72 lines
2.5 KiB
TypeScript
72 lines
2.5 KiB
TypeScript
|
|
import { describe, test, expect } from 'bun:test';
|
||
|
|
import {
|
||
|
|
encodeStreamOpen,
|
||
|
|
encodeStreamOpenAck,
|
||
|
|
decodeStreamHandshake,
|
||
|
|
encodeStreamFrame,
|
||
|
|
decodeStreamFrame,
|
||
|
|
inspectEnvelopeType,
|
||
|
|
} from '../src/index.js';
|
||
|
|
import type { RatchetMessage } from '@shade/core';
|
||
|
|
|
||
|
|
function randBytes(n: number): Uint8Array {
|
||
|
|
const buf = new Uint8Array(n);
|
||
|
|
crypto.getRandomValues(buf);
|
||
|
|
return buf;
|
||
|
|
}
|
||
|
|
|
||
|
|
function makeRatchetMessage(): RatchetMessage {
|
||
|
|
return {
|
||
|
|
dhPublicKey: randBytes(32),
|
||
|
|
previousCounter: 3,
|
||
|
|
counter: 9001,
|
||
|
|
ciphertext: randBytes(128),
|
||
|
|
nonce: randBytes(12),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
describe('Stream sub-session wire (V4.11)', () => {
|
||
|
|
test('STREAM_OPEN round-trips and inspects', () => {
|
||
|
|
const sid = randBytes(16);
|
||
|
|
const eph = randBytes(32);
|
||
|
|
const bytes = encodeStreamOpen(sid, eph);
|
||
|
|
expect(inspectEnvelopeType(bytes)).toBe('stream-open');
|
||
|
|
const hs = decodeStreamHandshake(bytes);
|
||
|
|
expect(hs.kind).toBe('open');
|
||
|
|
expect(hs.streamId).toEqual(sid);
|
||
|
|
expect(hs.ephemeralPub).toEqual(eph);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('STREAM_OPEN_ACK round-trips and inspects', () => {
|
||
|
|
const sid = randBytes(16);
|
||
|
|
const eph = randBytes(32);
|
||
|
|
const bytes = encodeStreamOpenAck(sid, eph);
|
||
|
|
expect(inspectEnvelopeType(bytes)).toBe('stream-open-ack');
|
||
|
|
const hs = decodeStreamHandshake(bytes);
|
||
|
|
expect(hs.kind).toBe('open-ack');
|
||
|
|
expect(hs.streamId).toEqual(sid);
|
||
|
|
expect(hs.ephemeralPub).toEqual(eph);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('STREAM_FRAME carries a full ratchet message verbatim', () => {
|
||
|
|
const sid = randBytes(16);
|
||
|
|
const msg = makeRatchetMessage();
|
||
|
|
const bytes = encodeStreamFrame(sid, msg);
|
||
|
|
expect(inspectEnvelopeType(bytes)).toBe('stream-frame');
|
||
|
|
const decoded = decodeStreamFrame(bytes);
|
||
|
|
expect(decoded.streamId).toEqual(sid);
|
||
|
|
expect(decoded.message.dhPublicKey).toEqual(msg.dhPublicKey);
|
||
|
|
expect(decoded.message.previousCounter).toBe(msg.previousCounter);
|
||
|
|
expect(decoded.message.counter).toBe(msg.counter);
|
||
|
|
expect(decoded.message.ciphertext).toEqual(msg.ciphertext);
|
||
|
|
expect(decoded.message.nonce).toEqual(msg.nonce);
|
||
|
|
});
|
||
|
|
|
||
|
|
test('rejects wrong sizes and wrong type tags', () => {
|
||
|
|
expect(() => encodeStreamOpen(randBytes(15), randBytes(32))).toThrow();
|
||
|
|
expect(() => encodeStreamOpen(randBytes(16), randBytes(31))).toThrow();
|
||
|
|
expect(() => decodeStreamHandshake(encodeStreamFrame(randBytes(16), makeRatchetMessage()))).toThrow();
|
||
|
|
expect(() => decodeStreamFrame(encodeStreamOpen(randBytes(16), randBytes(32)))).toThrow();
|
||
|
|
});
|
||
|
|
});
|