src/main/generic/network/message/SignalMessage.js
class SignalMessage extends Message {
/**
* @param {PeerId} senderId
* @param {PeerId} recipientId
* @param {number} nonce
* @param {number} ttl
* @param {SignalMessage.Flag|number} flags
* @param {Uint8Array} [payload]
* @param {PublicKey} [senderPubKey]
* @param {Signature} [signature]
*/
constructor(senderId, recipientId, nonce, ttl, flags = 0, payload = new Uint8Array(0), senderPubKey, signature) {
super(Message.Type.SIGNAL);
if (!(senderId instanceof PeerId)) throw new Error('Malformed senderId');
if (!(recipientId instanceof PeerId)) throw new Error('Malformed recipientId');
if (!NumberUtils.isUint32(nonce)) throw new Error('Malformed nonce');
if (!NumberUtils.isUint8(ttl)) throw new Error('Malformed ttl');
if (!NumberUtils.isUint8(flags)) throw new Error('Malformed flags');
if (!(payload instanceof Uint8Array) || !NumberUtils.isUint16(payload.byteLength)) throw new Error('Malformed payload');
const hasPayload = payload.byteLength > 0;
if (hasPayload && !(signature instanceof Signature)) throw new Error('Malformed signature');
if (hasPayload && !(senderPubKey instanceof PublicKey)) throw new Error('Malformed public key');
// Note that the signature is NOT verified here.
// Callers must explicitly invoke verifySignature() to check it.
/** @type {PeerId} */
this._senderId = senderId;
/** @type {PeerId} */
this._recipientId = recipientId;
/** @type {number} */
this._nonce = nonce;
/** @type {number} */
this._ttl = ttl;
/** @type {SignalMessage.Flag|number} */
this._flags = flags;
/** @type {Uint8Array} */
this._payload = payload;
/** @type {PublicKey} */
this._senderPubKey = hasPayload ? senderPubKey : undefined;
/** @type {Signature} */
this._signature = hasPayload ? signature : undefined;
}
/**
* @param {SerialBuffer} buf
* @returns {SignalMessage}
*/
static unserialize(buf) {
Message.unserialize(buf);
const senderId = PeerId.unserialize(buf);
const recipientId = PeerId.unserialize(buf);
const nonce = buf.readUint32();
const ttl = buf.readUint8();
const flags = buf.readUint8();
const length = buf.readUint16();
const payload = buf.read(length);
const senderPubKey = length > 0 ? PublicKey.unserialize(buf) : undefined;
const signature = length > 0 ? Signature.unserialize(buf) : undefined;
return new SignalMessage(senderId, recipientId, nonce, ttl, flags, payload, senderPubKey, signature);
}
/**
* @param {SerialBuffer} [buf]
* @returns {SerialBuffer}
*/
serialize(buf) {
buf = buf || new SerialBuffer(this.serializedSize);
super.serialize(buf);
this._senderId.serialize(buf);
this._recipientId.serialize(buf);
buf.writeUint32(this._nonce);
buf.writeUint8(this._ttl);
buf.writeUint8(this._flags);
buf.writeUint16(this._payload.byteLength);
buf.write(this._payload);
if (this._payload.byteLength > 0) {
this._senderPubKey.serialize(buf);
this._signature.serialize(buf);
}
super._setChecksum(buf);
return buf;
}
/** @type {number} */
get serializedSize() {
return super.serializedSize
+ /*senderId*/ this._senderId.serializedSize
+ /*recipientId*/ this._recipientId.serializedSize
+ /*nonce*/ 4
+ /*ttl*/ 1
+ /*flags*/ 1
+ /*payloadLength*/ 2
+ this._payload.byteLength
+ (this._payload.byteLength > 0 ? this._senderPubKey.serializedSize : 0)
+ (this._payload.byteLength > 0 ? this._signature.serializedSize : 0);
}
/**
* @return {boolean}
*/
verifySignature() {
if (!this._signature) {
return false;
}
return this._signature.verify(this._senderPubKey, this._payload)
&& this._senderId.equals(this._senderPubKey.toPeerId());
}
/** @type {PeerId} */
get senderId() {
return this._senderId;
}
/** @type {PeerId} */
get recipientId() {
return this._recipientId;
}
/** @type {number} */
get nonce() {
return this._nonce;
}
/** @type {number} */
get ttl() {
return this._ttl;
}
/** @type {SignalMessage.Flag|number} */
get flags() {
return this._flags;
}
/** @type {Uint8Array} */
get payload() {
return this._payload;
}
/** @type {Signature} */
get signature() {
return this._signature;
}
/** @type {PublicKey} */
get senderPubKey() {
return this._senderPubKey;
}
/**
* @returns {boolean}
*/
hasPayload() {
return this._payload.byteLength > 0;
}
/**
* @returns {boolean}
*/
isUnroutable() {
return (this._flags & SignalMessage.Flag.UNROUTABLE) !== 0;
}
/**
* @returns {boolean}
*/
isTtlExceeded() {
return (this._flags & SignalMessage.Flag.TTL_EXCEEDED) !== 0;
}
toString() {
return `SignalMessage{sender=${this._senderId}, recipient=${this._recipientId}, nonce=${this._nonce}, ttl=${this._ttl}, flags=${this._flags}}`;
}
}
/**
* @enum {number}
*/
SignalMessage.Flag = {
UNROUTABLE: 0x1,
TTL_EXCEEDED: 0x2
};
Class.register(SignalMessage);