Compare commits
7 Commits
61082d32e7
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| dcc343fb02 | |||
| 68f31018ef | |||
| 356b70474c | |||
| ed1dc6870e | |||
| 22999c34f9 | |||
| 61b7c50868 | |||
| 15fa2b1608 |
52
.drone.yml
52
.drone.yml
@@ -1,52 +0,0 @@
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: build
|
||||
|
||||
steps:
|
||||
- name: install
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- apk add git
|
||||
- npm install
|
||||
|
||||
- name: lint
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- npm run lint
|
||||
depends_on:
|
||||
- install
|
||||
|
||||
- name: test
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- npm run test
|
||||
depends_on:
|
||||
- install
|
||||
|
||||
- name: build
|
||||
image: node:lts-alpine
|
||||
commands:
|
||||
- apk add zip
|
||||
- npm run build
|
||||
- zip -r bennc-m.zip dist/
|
||||
depends_on:
|
||||
- install
|
||||
|
||||
- name: publish
|
||||
image: plugins/gitea-release
|
||||
depends_on:
|
||||
- lint
|
||||
- test
|
||||
- build
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
settings:
|
||||
base_url: https://git.jacknet.io
|
||||
api_key:
|
||||
from_secret: gitea_token
|
||||
files:
|
||||
- bennc-m.zip
|
||||
checksum:
|
||||
- md5
|
||||
- sha256
|
||||
57
.gitea/workflows/ci..yml
Normal file
57
.gitea/workflows/ci..yml
Normal file
@@ -0,0 +1,57 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
tags: ["v*"]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: node:lts-alpine
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test
|
||||
|
||||
- name: Build project
|
||||
run: npm run build
|
||||
|
||||
publish:
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
container: node:lts-alpine
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Build project
|
||||
run: npm run build
|
||||
|
||||
- name: Set version from git tag
|
||||
run: |
|
||||
VERSION=${GITHUB_REF#refs/tags/v}
|
||||
npm version $VERSION --no-git-tag-version
|
||||
|
||||
- name: Setup npm for publishing
|
||||
run: |
|
||||
npm config set //git.3t.network/api/packages/3t.network/npm/:_authToken ${{ secrets.PUBLISH_TOKEN }}
|
||||
|
||||
- name: Publish to Gitea npm registry
|
||||
run: npm publish
|
||||
192
README.md
192
README.md
@@ -2,54 +2,198 @@
|
||||
|
||||
[](https://drone.jacknet.io/TerribleCodeClub/bennc-js)
|
||||
|
||||
An implementation of the [BENNC](https://wiki.jacknet.io/books/simontech/chapter/bennc) client specification.
|
||||
A TypeScript implementation of the [BENNC](https://wiki.jacknet.io/books/simontech/chapter/bennc) (Butlersaurus Ephemeral No NONCEnse Chat) protocol specification. This library provides both low-level protocol utilities and a high-level client for connecting to BENNC chat servers via WebSocket.
|
||||
|
||||
## Features
|
||||
|
||||
- **Complete BENNC Protocol Support**: All message types (0x0000-0xFFFF) including subscribe, basic chat, user data, keepalive, history, and unsubscribe
|
||||
- **High-Level Client**: `BenncClient` class with automatic reconnection and event-driven architecture
|
||||
- **Browser & Node.js Compatible**: Works in modern browsers and Node.js environments
|
||||
- **TypeScript First**: Full type safety with comprehensive TypeScript definitions
|
||||
- **Encryption Support**: Built-in Romulus-M AEAD encryption for secure messaging
|
||||
- **Automatic Reconnection**: Configurable backoff strategies (constant, exponential)
|
||||
- **Small Bundle Size**: Minimal dependencies and efficient implementation
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @3t/bennc
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using the BenncClient (Recommended)
|
||||
|
||||
```typescript
|
||||
import { BenncClient, MessageTypes } from "@3t/bennc";
|
||||
|
||||
const client = new BenncClient({
|
||||
url: "wss://your-bennc-server.com",
|
||||
autoReconnect: true,
|
||||
reconnectBackoff: "exponential",
|
||||
reconnectDelay: 1000,
|
||||
});
|
||||
|
||||
// Listen for events
|
||||
client.addEventListener("connected", () => {
|
||||
console.log("Connected to BENNC server");
|
||||
|
||||
// Subscribe to basic messages
|
||||
client.subscribe(MessageTypes.Basic);
|
||||
});
|
||||
|
||||
client.addEventListener("message:1", (event) => {
|
||||
const { senderId, data } = event.detail;
|
||||
console.log(`Message from ${senderId}:`, new TextDecoder().decode(data));
|
||||
});
|
||||
|
||||
client.addEventListener("disconnected", (event) => {
|
||||
console.log("Disconnected:", event.detail);
|
||||
});
|
||||
|
||||
// Connect to server
|
||||
await client.connect();
|
||||
|
||||
// Send a message
|
||||
client.sendBasicMessage("Hello, BENNC!");
|
||||
```
|
||||
|
||||
### Using Low-Level Protocol Functions
|
||||
|
||||
```typescript
|
||||
import { packers, unpackers, MessageTypes } from "@3t/bennc";
|
||||
|
||||
// Pack a basic message
|
||||
const messageData = new TextEncoder().encode("Hello World");
|
||||
const packet = packers[MessageTypes.Basic](messageData);
|
||||
|
||||
// Unpack incoming message
|
||||
const incomingMessage = unpackers[MessageTypes.Basic](receivedData);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### BenncClient
|
||||
|
||||
#### Constructor Options
|
||||
|
||||
```typescript
|
||||
interface BenncClientOptions {
|
||||
url: string; // WebSocket server URL
|
||||
protocols?: string[]; // WebSocket protocols
|
||||
autoReconnect?: boolean; // Enable auto-reconnection (default: true)
|
||||
reconnectBackoff?: "constant" | "exponential"; // Backoff strategy (default: 'exponential')
|
||||
reconnectDelay?: number; // Reconnection delay in ms (default: 1000)
|
||||
maxReconnectAttempts?: number; // Max reconnection attempts (default: 10)
|
||||
}
|
||||
```
|
||||
|
||||
#### Methods
|
||||
|
||||
- `connect(): Promise<void>` - Connect to the BENNC server
|
||||
- `disconnect(): void` - Disconnect from the server
|
||||
- `isConnected(): boolean` - Check connection status
|
||||
- `subscribe(messageType: MessageTypes): void` - Subscribe to message type
|
||||
- `unsubscribe(messageType: MessageTypes): void` - Unsubscribe from message type
|
||||
- `sendBasicMessage(message: string, key?: Uint8Array): void` - Send encrypted chat message
|
||||
- `sendUserDataRequest(username: string, colour: Color, clientId: string, key?: Uint8Array): void` - Request user data
|
||||
- `sendUserDataResponse(username: string, colour: Color, clientId: string, key?: Uint8Array): void` - Respond with user data
|
||||
- `sendKeepalive(): void` - Send keepalive message
|
||||
- `requestHistory(): void` - Request message history
|
||||
|
||||
#### Events
|
||||
|
||||
The client extends `EventTarget` and emits the following events:
|
||||
|
||||
- `connected` - Successfully connected to server
|
||||
- `disconnected` - Disconnected from server (detail: `{code, reason}`)
|
||||
- `reconnecting` - Attempting to reconnect
|
||||
- `error` - Connection or protocol error (detail: error object)
|
||||
- `packet` - Raw incoming packet (detail: packet object)
|
||||
- `message` - Parsed message (detail: `{messageType, senderId, data}`)
|
||||
- `message:${messageType}` - Specific message type events (detail: `{senderId, data}`)
|
||||
- `unknown-message` - Unknown message type received
|
||||
- `parse-error` - Error parsing incoming message
|
||||
|
||||
### Message Types
|
||||
|
||||
```typescript
|
||||
enum MessageTypes {
|
||||
Subscribe = 0x0000,
|
||||
Basic = 0x0001,
|
||||
UserDataRequest = 0x0002,
|
||||
UserDataResponse = 0x0003,
|
||||
Keepalive = 0x0005,
|
||||
GetHistory = 0xfffe,
|
||||
Unsubscribe = 0xffff,
|
||||
}
|
||||
```
|
||||
|
||||
### Protocol Constants
|
||||
|
||||
```typescript
|
||||
const MAX_DATA_LENGTH = 1000; // Maximum data payload size
|
||||
const DEFAULT_KEY: Uint8Array; // Default encryption key
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
To build the BENNC-JS library, first clone this repository.
|
||||
|
||||
Run the following commands from the root of the repository:
|
||||
To build the BENNC-JS library from source:
|
||||
|
||||
```bash
|
||||
$ git clone <repository-url>
|
||||
$ cd bennc-js
|
||||
$ npm install
|
||||
$ npm run build
|
||||
```
|
||||
|
||||
The build output will be saved to the `dist` directory.
|
||||
|
||||
## Development instructions
|
||||
## Protocol Details
|
||||
|
||||
Requirements:
|
||||
BENNC uses a binary protocol with the following message structure:
|
||||
|
||||
- The latest LTS builds of Node and npm.
|
||||
**Client → Server**: `[Type(2)|Length(2)|Data(0-1000)]`
|
||||
**Server → Client**: `[Type(2)|SenderId(4)|Length(2)|Data(0-1000)]`
|
||||
|
||||
Follow the instructions below to lint, test and build BENNC-JS.
|
||||
- All integers are big-endian
|
||||
- Maximum data payload is 1000 bytes (including encryption overhead)
|
||||
- Encrypted message types (0x0001, 0x0002, 0x0003) use Romulus-M AEAD with 16-byte nonces
|
||||
- Reserved sender IDs: 0xFFFFFF00-0xFFFFFFFF
|
||||
|
||||
#### Lint
|
||||
## Development
|
||||
|
||||
Requirements: Node.js LTS and npm
|
||||
|
||||
### Commands
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
$ npm run lint
|
||||
```
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
#### Test
|
||||
# Run tests
|
||||
npm run test
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
$ npm run test
|
||||
```
|
||||
# Lint code
|
||||
npm run lint
|
||||
|
||||
#### Build
|
||||
# Format code
|
||||
npm run format
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
$ npm run build
|
||||
# Build library
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Visual Studio Code
|
||||
|
||||
This repository contains the necessary configuration files to debug, test and build BENNC-JS using only Visual Studio Code.
|
||||
This repository includes VS Code configuration for debugging and testing. Use `Ctrl+Shift+B` (or `⇧⌘B`) to run the build task.
|
||||
|
||||
Run the build task (`Ctrl+Shift+B` or `⇧⌘B`) to automatically compile the Typescript source files in the background.
|
||||
Unit tests use [Jest](https://jestjs.io/) with VS Code support via the [Jest extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest).
|
||||
|
||||
Unit tests use the [Jest](https://jestjs.io/) library. Support for Visual Studio Code is offered through the [Jest marketplace package](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest) maintained by Orta.
|
||||
## License
|
||||
|
||||
ISC License - see package.json for details.
|
||||
|
||||
## Contributing
|
||||
|
||||
This is part of the BENNC protocol ecosystem. Please refer to the [BENNC specification](https://wiki.jacknet.io/books/simontech/chapter/bennc) for protocol details.
|
||||
|
||||
10661
package-lock.json
generated
10661
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
24
package.json
24
package.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "bennc-js",
|
||||
"name": "@3t/bennc",
|
||||
"version": "1.0.0",
|
||||
"description": "A TypeScript/Javascript BENNC implementation.",
|
||||
"main": "dist/index.js",
|
||||
@@ -13,17 +13,13 @@
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.jacknet.io/TerribleCodeClub/bennc-js"
|
||||
"url": "https://git.3t.network/3t.network/bennc"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://git.3t.network/api/packages/3t.network/npm/"
|
||||
},
|
||||
"author": "Butlersaurus",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.4.0",
|
||||
"jest": "^27.4.7",
|
||||
"ts-jest": "^27.1.3",
|
||||
"ts-standard": "^11.0.0",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"jest": {
|
||||
"verbose": true,
|
||||
"transform": {
|
||||
@@ -33,6 +29,14 @@
|
||||
"dependencies": {
|
||||
"@3t/romulus": "^1.0.2",
|
||||
"@types/color": "^3.0.3",
|
||||
"color": "^4.2.0"
|
||||
"color": "^4.2.0",
|
||||
"websocket-ts": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^30.0.0",
|
||||
"jest": "^30.1.3",
|
||||
"prettier": "^3.6.2",
|
||||
"ts-jest": "^29.4.1",
|
||||
"typescript": "^5.9.2"
|
||||
}
|
||||
}
|
||||
|
||||
211
src/BenncClient.ts
Normal file
211
src/BenncClient.ts
Normal file
@@ -0,0 +1,211 @@
|
||||
import {
|
||||
WebsocketBuilder,
|
||||
ConstantBackoff,
|
||||
ExponentialBackoff,
|
||||
} from "websocket-ts";
|
||||
import { MessageTypes } from "./common";
|
||||
import { packOutgoingPacket, unpackIncomingPacket } from "./messages/packet";
|
||||
import { packers, unpackers } from "./mapping";
|
||||
import { numberToUint16BE } from "./utilities/number";
|
||||
import Color from "color";
|
||||
|
||||
export interface BenncClientOptions {
|
||||
url: string;
|
||||
protocols?: string[];
|
||||
autoReconnect?: boolean;
|
||||
reconnectBackoff?: "constant" | "linear" | "exponential";
|
||||
reconnectDelay?: number;
|
||||
maxReconnectAttempts?: number;
|
||||
}
|
||||
|
||||
export class BenncClient extends EventTarget {
|
||||
private ws: any = null;
|
||||
private options: BenncClientOptions;
|
||||
|
||||
constructor(options: BenncClientOptions) {
|
||||
super();
|
||||
this.options = {
|
||||
autoReconnect: true,
|
||||
reconnectBackoff: "exponential",
|
||||
reconnectDelay: 1000,
|
||||
maxReconnectAttempts: 10,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
connect(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (
|
||||
this.ws &&
|
||||
(this.ws.state === WebSocket.OPEN ||
|
||||
this.ws.state === WebSocket.CONNECTING)
|
||||
) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const builder = new WebsocketBuilder(this.options.url);
|
||||
|
||||
if (this.options.protocols) {
|
||||
builder.withProtocols(this.options.protocols);
|
||||
}
|
||||
|
||||
if (this.options.autoReconnect) {
|
||||
let backoff;
|
||||
switch (this.options.reconnectBackoff) {
|
||||
case "constant":
|
||||
backoff = new ConstantBackoff(this.options.reconnectDelay!);
|
||||
break;
|
||||
case "exponential":
|
||||
default:
|
||||
backoff = new ExponentialBackoff(this.options.reconnectDelay!);
|
||||
break;
|
||||
}
|
||||
builder.withBackoff(backoff);
|
||||
}
|
||||
|
||||
this.ws = builder
|
||||
.onOpen(() => {
|
||||
this.dispatchEvent(new CustomEvent("connected"));
|
||||
resolve();
|
||||
})
|
||||
.onClose((_: any, event: any) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("disconnected", {
|
||||
detail: { code: event.code, reason: event.reason },
|
||||
}),
|
||||
);
|
||||
})
|
||||
.onError((_: any, error: any) => {
|
||||
this.dispatchEvent(new CustomEvent("error", { detail: error }));
|
||||
reject(error);
|
||||
})
|
||||
.onMessage((_: any, event: any) => {
|
||||
this.handleMessage(event.data);
|
||||
})
|
||||
.onReconnect(() => {
|
||||
this.dispatchEvent(new CustomEvent("reconnecting"));
|
||||
})
|
||||
.build();
|
||||
});
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
}
|
||||
|
||||
isConnected(): boolean {
|
||||
return this.ws && this.ws.state === WebSocket.OPEN;
|
||||
}
|
||||
|
||||
getConnectionState(): { connected: boolean; connecting: boolean } {
|
||||
return {
|
||||
connected: this.ws?.state === WebSocket.OPEN || false,
|
||||
connecting: this.ws?.state === WebSocket.CONNECTING || false,
|
||||
};
|
||||
}
|
||||
|
||||
private sendRawMessage(messageType: number, data?: Uint8Array): void {
|
||||
if (!this.isConnected()) {
|
||||
throw new Error("Client is not connected");
|
||||
}
|
||||
|
||||
const packet = packOutgoingPacket({
|
||||
messageType: numberToUint16BE(messageType),
|
||||
data,
|
||||
});
|
||||
|
||||
this.ws.send(packet);
|
||||
}
|
||||
|
||||
subscribe(messageType: MessageTypes): void {
|
||||
const packer = packers[MessageTypes.Subscribe];
|
||||
const data = packer({ messageType });
|
||||
this.sendRawMessage(MessageTypes.Subscribe, data);
|
||||
}
|
||||
|
||||
unsubscribe(messageType: MessageTypes): void {
|
||||
const packer = packers[MessageTypes.Unsubscribe];
|
||||
const data = packer({ messageType });
|
||||
this.sendRawMessage(MessageTypes.Unsubscribe, data);
|
||||
}
|
||||
|
||||
sendBasicMessage(message: string, key?: Uint8Array): void {
|
||||
const encoder = new TextEncoder();
|
||||
const messageBytes = encoder.encode(message);
|
||||
const packer = packers[MessageTypes.Basic];
|
||||
const data = packer(messageBytes, key);
|
||||
this.sendRawMessage(MessageTypes.Basic, data);
|
||||
}
|
||||
|
||||
sendUserDataRequest(
|
||||
username: string,
|
||||
colour: Color,
|
||||
clientId: string,
|
||||
key?: Uint8Array,
|
||||
): void {
|
||||
const packer = packers[MessageTypes.UserDataRequest];
|
||||
const data = packer({ username, colour, clientId }, key);
|
||||
this.sendRawMessage(MessageTypes.UserDataRequest, data);
|
||||
}
|
||||
|
||||
sendUserDataResponse(
|
||||
username: string,
|
||||
colour: Color,
|
||||
clientId: string,
|
||||
key?: Uint8Array,
|
||||
): void {
|
||||
const packer = packers[MessageTypes.UserDataResponse];
|
||||
const data = packer({ username, colour, clientId }, key);
|
||||
this.sendRawMessage(MessageTypes.UserDataResponse, data);
|
||||
}
|
||||
|
||||
sendKeepalive(): void {
|
||||
const packer = packers[MessageTypes.Keepalive];
|
||||
const data = packer();
|
||||
this.sendRawMessage(MessageTypes.Keepalive, data);
|
||||
}
|
||||
|
||||
requestHistory(): void {
|
||||
const packer = packers[MessageTypes.GetHistory];
|
||||
const data = packer();
|
||||
this.sendRawMessage(MessageTypes.GetHistory, data);
|
||||
}
|
||||
|
||||
private handleMessage(data: ArrayBuffer): void {
|
||||
try {
|
||||
const packet = unpackIncomingPacket(data);
|
||||
this.dispatchEvent(new CustomEvent("packet", { detail: packet }));
|
||||
|
||||
const unpacker = unpackers[packet.messageType as keyof typeof unpackers];
|
||||
if (unpacker) {
|
||||
const unpackedData = unpacker(packet.data);
|
||||
const messageEvent = {
|
||||
messageType: packet.messageType,
|
||||
senderId: packet.senderId,
|
||||
data: unpackedData,
|
||||
};
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("message", { detail: messageEvent }),
|
||||
);
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(`message:${packet.messageType}`, {
|
||||
detail: {
|
||||
senderId: packet.senderId,
|
||||
data: unpackedData,
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("unknown-message", { detail: packet }),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.dispatchEvent(new CustomEvent("parse-error", { detail: error }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
export { numberToUint16BE, numberToUint32BE } from "./utilities/number";
|
||||
export { unpackIncomingPacket } from "./messages/packet";
|
||||
export { packers, unpackers } from "./mapping";
|
||||
export type { MessageTypes } from "./common";
|
||||
export { MessageTypes } from "./common";
|
||||
export type { IncomingPacket, OutgoingPacket } from "./messages/packet";
|
||||
export type { SubscribeMessage } from "./messages/subscribe";
|
||||
export type { BasicMessage } from "./messages/basic";
|
||||
export type { UserDataRequestMessage } from "./messages/userDataRequest";
|
||||
export type { UserDataResponseMessage } from "./messages/userDataResponse";
|
||||
export { BenncClient } from "./BenncClient";
|
||||
export type { BenncClientOptions } from "./BenncClient";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { encrypt, decrypt } from "romulus-js";
|
||||
import { encrypt, decrypt } from "@3t/romulus";
|
||||
import { DEFAULT_KEY, MessageTypes } from "../common";
|
||||
import { numberToUint16BE } from "../utilities/number";
|
||||
import { packOutgoingPacket } from "./packet";
|
||||
|
||||
@@ -21,7 +21,7 @@ export interface OutgoingPacket {
|
||||
export function packOutgoingPacket(outgoingPacket: OutgoingPacket): Uint8Array {
|
||||
// Default to empty data if not provided
|
||||
const data = outgoingPacket.data ?? new Uint8Array(0);
|
||||
|
||||
|
||||
// Verify that the data does not exceed the maximum data length.
|
||||
if (data.length > MAX_DATA_LENGTH) {
|
||||
throw RangeError(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Color from "color";
|
||||
import { encrypt } from "romulus-js";
|
||||
import { encrypt } from "@3t/romulus";
|
||||
import { DEFAULT_KEY, MessageTypes } from "../common";
|
||||
import { numberToUint16BE } from "../utilities/number";
|
||||
import { SmartBuffer } from "../utilities/smart-buffer";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Color from "color";
|
||||
import { encrypt } from "romulus-js";
|
||||
import { encrypt } from "@3t/romulus";
|
||||
import { DEFAULT_KEY, MessageTypes } from "../common";
|
||||
import { numberToUint16BE } from "../utilities/number";
|
||||
import { SmartBuffer } from "../utilities/smart-buffer";
|
||||
|
||||
@@ -26,12 +26,17 @@ test("Create a basic message (0x0001) packet.", () => {
|
||||
|
||||
test("Parse a basic message (0x0001).", () => {
|
||||
// Given
|
||||
const data = new Uint8Array([1, 2, 3, 4]);
|
||||
const encoder = new TextEncoder();
|
||||
const originalMessage = encoder.encode("Test message");
|
||||
|
||||
// First encrypt the message to get valid encrypted data
|
||||
const encryptedData = packers[MessageTypes.Basic](originalMessage, KEY);
|
||||
// Extract just the data portion (skip the 4-byte header)
|
||||
const dataOnly = encryptedData.slice(4);
|
||||
|
||||
// When
|
||||
const unpackedPacket = unpackers[MessageTypes.Basic](data);
|
||||
const unpackedMessage = unpackers[MessageTypes.Basic](dataOnly, KEY);
|
||||
|
||||
// Then
|
||||
expect(unpackedPacket);
|
||||
expect(unpackedPacket).toMatchObject(data);
|
||||
expect(unpackedMessage).toEqual(originalMessage);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user