-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Needed by relaycorp/awala-gateway-internet#16
- Loading branch information
Showing
6 changed files
with
166 additions
and
108 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { describeMessage } from './_test_utils'; | ||
import Cargo from './Cargo'; | ||
|
||
describe('Cargo', () => { | ||
describeMessage(Cargo, 0x43, 0x0); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// This module wouldn't duplicate Parcel.ts if TypeScript supported static+abstract methods | ||
|
||
import { SignatureOptions } from '../crypto_wrappers/cms/signedData'; | ||
import * as serialization from '../ramf/serialization'; | ||
import Message from './Message'; | ||
|
||
const concreteMessageTypeOctet = 0x43; | ||
const concreteMessageVersionOctet = 0; | ||
|
||
export default class Cargo extends Message { | ||
public static async deserialize(parcelSerialized: ArrayBuffer): Promise<Cargo> { | ||
return serialization.deserialize( | ||
parcelSerialized, | ||
concreteMessageTypeOctet, | ||
concreteMessageVersionOctet, | ||
Cargo, | ||
); | ||
} | ||
|
||
public async serialize( | ||
senderPrivateKey: CryptoKey, | ||
signatureOptions?: SignatureOptions, | ||
): Promise<ArrayBuffer> { | ||
return serialization.serialize( | ||
this, | ||
concreteMessageTypeOctet, | ||
concreteMessageVersionOctet, | ||
senderPrivateKey, | ||
signatureOptions, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,6 @@ | ||
/* tslint:disable:no-let */ | ||
import bufferToArray from 'buffer-to-arraybuffer'; | ||
|
||
import { generateStubCert, getMockContext } from '../_test_utils'; | ||
import { generateRSAKeyPair } from '../crypto_wrappers/keys'; | ||
import * as serialization from '../ramf/serialization'; | ||
import { describeMessage } from './_test_utils'; | ||
import Parcel from './Parcel'; | ||
|
||
afterAll(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
describe('Parcel', () => { | ||
let parcel: Parcel; | ||
let senderPrivateKey: CryptoKey; | ||
beforeAll(async () => { | ||
const senderKeyPair = await generateRSAKeyPair(); | ||
const senderCertificate = await generateStubCert({ | ||
issuerPrivateKey: senderKeyPair.privateKey, | ||
}); | ||
senderPrivateKey = senderKeyPair.privateKey; | ||
parcel = new Parcel('address', senderCertificate, Buffer.from('hi')); | ||
}); | ||
|
||
describe('serialize', () => { | ||
const expectedSerialization = bufferToArray(Buffer.from('serialized')); | ||
const serializeSpy = jest.spyOn(serialization, 'serialize'); | ||
beforeAll(() => { | ||
serializeSpy.mockResolvedValueOnce(expectedSerialization); | ||
}); | ||
afterEach(() => { | ||
serializeSpy.mockReset(); | ||
}); | ||
|
||
test('Result should be RAMF serialization', async () => { | ||
const messageSerialized = await parcel.serialize(senderPrivateKey); | ||
|
||
expect(serializeSpy).toBeCalledTimes(1); | ||
expect(messageSerialized).toBe(expectedSerialization); | ||
}); | ||
|
||
test('Concrete message type should be 0x50', async () => { | ||
await parcel.serialize(senderPrivateKey); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[1]).toEqual(0x50); | ||
}); | ||
|
||
test('Concrete message version should be 0x0', async () => { | ||
await parcel.serialize(senderPrivateKey); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[2]).toEqual(0); | ||
}); | ||
|
||
test('Message should be signed with private key specified', async () => { | ||
await parcel.serialize(senderPrivateKey); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[3]).toEqual(senderPrivateKey); | ||
}); | ||
|
||
test('Signature options should be honored', async () => { | ||
const signatureOptions = { hashingAlgorithmName: 'SHA-384' }; | ||
await parcel.serialize(senderPrivateKey, signatureOptions); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[4]).toEqual(signatureOptions); | ||
}); | ||
}); | ||
|
||
describe('deserialize', () => { | ||
const stubParcelSerialized = bufferToArray(Buffer.from('I am a parcel. I swear.')); | ||
const deserializeSpy = jest.spyOn(serialization, 'deserialize'); | ||
beforeAll(() => { | ||
deserializeSpy.mockResolvedValueOnce(parcel); | ||
}); | ||
afterEach(() => { | ||
deserializeSpy.mockReset(); | ||
}); | ||
|
||
test('Result should be the parcel', async () => { | ||
const parcelDeserialized = await Parcel.deserialize(stubParcelSerialized); | ||
|
||
expect(parcelDeserialized).toBe(parcel); | ||
expect(deserializeSpy).toBeCalledTimes(1); | ||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[0]).toBe(stubParcelSerialized); | ||
}); | ||
|
||
test('Concrete message type should be 0x50', async () => { | ||
await Parcel.deserialize(stubParcelSerialized); | ||
|
||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[1]).toEqual(0x50); | ||
}); | ||
|
||
test('Concrete message version should be 0x0', async () => { | ||
await Parcel.deserialize(stubParcelSerialized); | ||
|
||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[2]).toEqual(0); | ||
}); | ||
|
||
test('Message class should be Parcel', async () => { | ||
await Parcel.deserialize(stubParcelSerialized); | ||
|
||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[3]).toBe(Parcel); | ||
}); | ||
}); | ||
describeMessage(Parcel, 0x50, 0x0); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* tslint:disable:no-let */ | ||
import bufferToArray from 'buffer-to-arraybuffer'; | ||
|
||
import { generateStubCert, getMockContext } from '../_test_utils'; | ||
import { generateRSAKeyPair } from '../crypto_wrappers/keys'; | ||
import * as serialization from '../ramf/serialization'; | ||
import Message from './Message'; | ||
|
||
interface MessageClass<M extends Message> { | ||
readonly deserialize: (serialization: ArrayBuffer) => Promise<M>; | ||
// tslint:disable-next-line:no-mixed-interface | ||
new (...args: readonly any[]): M; | ||
} | ||
|
||
export function describeMessage<M extends Message>( | ||
messageClass: MessageClass<M>, | ||
messageType: number, | ||
messageVersion: number, | ||
): void { | ||
afterAll(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
let message: M; | ||
let senderPrivateKey: CryptoKey; | ||
|
||
beforeAll(async () => { | ||
const senderKeyPair = await generateRSAKeyPair(); | ||
const senderCertificate = await generateStubCert({ | ||
issuerPrivateKey: senderKeyPair.privateKey, | ||
}); | ||
senderPrivateKey = senderKeyPair.privateKey; | ||
message = new messageClass('address', senderCertificate, Buffer.from('hi')); | ||
}); | ||
|
||
describe('serialize', () => { | ||
const expectedSerialization = bufferToArray(Buffer.from('serialized')); | ||
const serializeSpy = jest.spyOn(serialization, 'serialize'); | ||
beforeAll(() => { | ||
serializeSpy.mockResolvedValueOnce(expectedSerialization); | ||
}); | ||
afterEach(() => { | ||
serializeSpy.mockReset(); | ||
}); | ||
|
||
test('Result should be RAMF serialization', async () => { | ||
const messageSerialized = await message.serialize(senderPrivateKey); | ||
|
||
expect(serializeSpy).toBeCalledTimes(1); | ||
expect(messageSerialized).toBe(expectedSerialization); | ||
}); | ||
|
||
test(`Concrete message type should be ${messageType}`, async () => { | ||
await message.serialize(senderPrivateKey); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[1]).toEqual(messageType); | ||
}); | ||
|
||
test(`Concrete message version should be ${messageVersion}`, async () => { | ||
await message.serialize(senderPrivateKey); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[2]).toEqual(messageVersion); | ||
}); | ||
|
||
test('Message should be signed with private key specified', async () => { | ||
await message.serialize(senderPrivateKey); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[3]).toEqual(senderPrivateKey); | ||
}); | ||
|
||
test('Signature options should be honored', async () => { | ||
const signatureOptions = { hashingAlgorithmName: 'SHA-384' }; | ||
await message.serialize(senderPrivateKey, signatureOptions); | ||
|
||
const serializeCallArs = getMockContext(serialization.serialize).calls[0]; | ||
expect(serializeCallArs[4]).toEqual(signatureOptions); | ||
}); | ||
}); | ||
|
||
describe('deserialize', () => { | ||
const stubMessageSerialized = bufferToArray(Buffer.from('I am a message. I swear.')); | ||
const deserializeSpy = jest.spyOn(serialization, 'deserialize'); | ||
beforeAll(() => { | ||
deserializeSpy.mockResolvedValueOnce(message); | ||
}); | ||
afterEach(() => { | ||
deserializeSpy.mockReset(); | ||
}); | ||
|
||
test('Result should be the expected message', async () => { | ||
const messageDeserialized = await messageClass.deserialize(stubMessageSerialized); | ||
|
||
expect(messageDeserialized).toBe(message); | ||
expect(deserializeSpy).toBeCalledTimes(1); | ||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[0]).toBe(stubMessageSerialized); | ||
}); | ||
|
||
test(`Concrete message type should be ${messageType}`, async () => { | ||
await messageClass.deserialize(stubMessageSerialized); | ||
|
||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[1]).toEqual(messageType); | ||
}); | ||
|
||
test(`Concrete message version should be ${messageVersion}`, async () => { | ||
await messageClass.deserialize(stubMessageSerialized); | ||
|
||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[2]).toEqual(messageVersion); | ||
}); | ||
|
||
test(`Message class should be ${messageClass.name}`, async () => { | ||
await messageClass.deserialize(stubMessageSerialized); | ||
|
||
const deserializeCallArgs = getMockContext(deserializeSpy).calls[0]; | ||
expect(deserializeCallArgs[3]).toBe(messageClass); | ||
}); | ||
}); | ||
} |