2021-03-10 16:22:49 +11:00
|
|
|
// Ensure that this class matches the proto interface while
|
2021-07-07 11:23:56 +10:00
|
|
|
import { Buffer } from 'buffer';
|
|
|
|
|
|
2021-03-22 15:34:13 +11:00
|
|
|
import { Reader } from 'protobufjs/minimal';
|
2021-03-10 16:22:49 +11:00
|
|
|
|
2021-03-22 15:34:13 +11:00
|
|
|
// Protecting the user from protobuf oddities
|
2021-07-05 11:10:31 +10:00
|
|
|
import * as proto from '../../proto/waku/v2/message';
|
2021-03-10 16:22:49 +11:00
|
|
|
|
2021-07-07 11:23:56 +10:00
|
|
|
import * as version_1 from './version_1';
|
|
|
|
|
|
2021-05-10 11:43:57 +10:00
|
|
|
export const DefaultContentTopic = '/waku/2/default-content/proto';
|
|
|
|
|
const DefaultVersion = 0;
|
2021-03-10 16:22:49 +11:00
|
|
|
|
2021-07-06 15:29:02 +10:00
|
|
|
export interface Options {
|
|
|
|
|
contentTopic?: string;
|
|
|
|
|
timestamp?: Date;
|
2021-07-07 11:23:56 +10:00
|
|
|
encPublicKey?: Uint8Array;
|
|
|
|
|
sigPrivKey?: Uint8Array;
|
2021-07-06 15:29:02 +10:00
|
|
|
}
|
|
|
|
|
|
2021-04-01 11:18:35 +11:00
|
|
|
export class WakuMessage {
|
2021-07-07 11:23:56 +10:00
|
|
|
private constructor(
|
|
|
|
|
public proto: proto.WakuMessage,
|
|
|
|
|
private _signaturePublicKey?: Uint8Array,
|
|
|
|
|
private _signature?: Uint8Array
|
|
|
|
|
) {}
|
2021-04-07 11:04:30 +10:00
|
|
|
|
2021-03-12 14:23:21 +11:00
|
|
|
/**
|
2021-05-28 16:00:34 +10:00
|
|
|
* Create Message with a utf-8 string as payload.
|
2021-03-12 14:23:21 +11:00
|
|
|
*/
|
2021-07-07 11:23:56 +10:00
|
|
|
static async fromUtf8String(
|
|
|
|
|
utf8: string,
|
|
|
|
|
opts?: Options
|
|
|
|
|
): Promise<WakuMessage> {
|
2021-05-03 16:26:02 +10:00
|
|
|
const payload = Buffer.from(utf8, 'utf-8');
|
2021-07-06 15:29:02 +10:00
|
|
|
return WakuMessage.fromBytes(payload, opts);
|
2021-03-31 10:43:29 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2021-07-07 11:23:56 +10:00
|
|
|
* Create a Waku Message with the given payload.
|
|
|
|
|
*
|
|
|
|
|
* By default, the payload is kept clear (version 0).
|
|
|
|
|
* If `opts.encPublicKey` is passed, the payload is encrypted using
|
|
|
|
|
* asymmetric encryption (version 1).
|
|
|
|
|
*
|
|
|
|
|
* If `opts.sigPrivKey` is passed and version 1 is used, the payload is signed
|
|
|
|
|
* before encryption.
|
2021-03-31 10:43:29 +11:00
|
|
|
*/
|
2021-07-07 11:23:56 +10:00
|
|
|
static async fromBytes(
|
|
|
|
|
payload: Uint8Array,
|
|
|
|
|
opts?: Options
|
|
|
|
|
): Promise<WakuMessage> {
|
|
|
|
|
const { timestamp, contentTopic, encPublicKey, sigPrivKey } = Object.assign(
|
2021-07-06 15:29:02 +10:00
|
|
|
{ timestamp: new Date(), contentTopic: DefaultContentTopic },
|
|
|
|
|
opts ? opts : {}
|
|
|
|
|
);
|
2021-07-07 11:23:56 +10:00
|
|
|
|
|
|
|
|
let _payload = payload;
|
|
|
|
|
let version = DefaultVersion;
|
|
|
|
|
let sig;
|
|
|
|
|
if (encPublicKey) {
|
|
|
|
|
const enc = version_1.clearEncode(_payload, sigPrivKey);
|
|
|
|
|
_payload = await version_1.encryptAsymmetric(enc.payload, encPublicKey);
|
|
|
|
|
sig = enc.sig;
|
|
|
|
|
version = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new WakuMessage(
|
|
|
|
|
{
|
|
|
|
|
payload: _payload,
|
|
|
|
|
timestamp: timestamp.valueOf() / 1000,
|
|
|
|
|
version,
|
|
|
|
|
contentTopic,
|
|
|
|
|
},
|
|
|
|
|
sig?.publicKey,
|
|
|
|
|
sig?.signature
|
|
|
|
|
);
|
2021-03-10 16:22:49 +11:00
|
|
|
}
|
|
|
|
|
|
2021-07-07 11:23:56 +10:00
|
|
|
/**
|
|
|
|
|
* Decode a byte array into Waku Message.
|
|
|
|
|
*
|
|
|
|
|
* If the payload is encrypted, then `decPrivateKey` is used for decryption.
|
|
|
|
|
*/
|
|
|
|
|
static async decode(
|
|
|
|
|
bytes: Uint8Array,
|
|
|
|
|
decPrivateKey?: Uint8Array
|
|
|
|
|
): Promise<WakuMessage | undefined> {
|
|
|
|
|
const protoBuf = proto.WakuMessage.decode(Reader.create(bytes));
|
|
|
|
|
|
|
|
|
|
return WakuMessage.decodeProto(protoBuf, decPrivateKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Decode a Waku Message Protobuf Object into Waku Message.
|
|
|
|
|
*
|
|
|
|
|
* If the payload is encrypted, then `decPrivateKey` is used for decryption.
|
|
|
|
|
*/
|
|
|
|
|
static async decodeProto(
|
|
|
|
|
protoBuf: proto.WakuMessage,
|
|
|
|
|
decPrivateKey?: Uint8Array
|
|
|
|
|
): Promise<WakuMessage | undefined> {
|
|
|
|
|
let signaturePublicKey;
|
|
|
|
|
let signature;
|
|
|
|
|
if (protoBuf.version === 1 && protoBuf.payload) {
|
|
|
|
|
if (!decPrivateKey) return;
|
|
|
|
|
|
|
|
|
|
const dec = await version_1.decryptAsymmetric(
|
|
|
|
|
protoBuf.payload,
|
|
|
|
|
decPrivateKey
|
|
|
|
|
);
|
|
|
|
|
const res = await version_1.clearDecode(dec);
|
|
|
|
|
if (!res) return;
|
|
|
|
|
Object.assign(protoBuf, { payload: res.payload });
|
|
|
|
|
signaturePublicKey = res.sig?.publicKey;
|
|
|
|
|
signature = res.sig?.signature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new WakuMessage(protoBuf, signaturePublicKey, signature);
|
2021-03-10 16:22:49 +11:00
|
|
|
}
|
|
|
|
|
|
2021-05-03 16:26:02 +10:00
|
|
|
encode(): Uint8Array {
|
|
|
|
|
return proto.WakuMessage.encode(this.proto).finish();
|
2021-03-10 16:22:49 +11:00
|
|
|
}
|
|
|
|
|
|
2021-05-03 16:26:02 +10:00
|
|
|
get payloadAsUtf8(): string {
|
|
|
|
|
if (!this.proto.payload) {
|
2021-03-24 16:31:54 +11:00
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 16:26:02 +10:00
|
|
|
return Array.from(this.proto.payload)
|
2021-03-24 16:31:54 +11:00
|
|
|
.map((char) => {
|
|
|
|
|
return String.fromCharCode(char);
|
|
|
|
|
})
|
|
|
|
|
.join('');
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-03 16:26:02 +10:00
|
|
|
get payload(): Uint8Array | undefined {
|
|
|
|
|
return this.proto.payload;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get contentTopic(): string | undefined {
|
|
|
|
|
return this.proto.contentTopic;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get version(): number | undefined {
|
|
|
|
|
return this.proto.version;
|
2021-03-10 16:22:49 +11:00
|
|
|
}
|
2021-05-28 16:00:34 +10:00
|
|
|
|
|
|
|
|
get timestamp(): Date | undefined {
|
|
|
|
|
if (this.proto.timestamp) {
|
|
|
|
|
return new Date(this.proto.timestamp * 1000);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-07-07 11:23:56 +10:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The public key used to sign the message.
|
|
|
|
|
*
|
|
|
|
|
* MAY be present if the message is version 1.
|
|
|
|
|
*/
|
|
|
|
|
get signaturePublicKey(): Uint8Array | undefined {
|
|
|
|
|
return this._signaturePublicKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The signature of the message.
|
|
|
|
|
*
|
|
|
|
|
* MAY be present if the message is version 1.
|
|
|
|
|
*/
|
|
|
|
|
get signature(): Uint8Array | undefined {
|
|
|
|
|
return this._signature;
|
|
|
|
|
}
|
2021-03-10 16:22:49 +11:00
|
|
|
}
|