Wrap chat message in ApplicationMetadataMessage

This commit is contained in:
Franck Royer 2021-09-23 14:33:09 +10:00
parent 5dd482be11
commit bbf5cc6b00
No known key found for this signature in database
GPG Key ID: A82ED75A8DFC50A4
10 changed files with 644 additions and 44 deletions

Binary file not shown.

View File

@ -25,6 +25,7 @@
"devDependencies": {
"@types/chai": "^4.2.22",
"@types/mocha": "^9.0.0",
"@types/secp256k1": "^4.0.3",
"@typescript-eslint/eslint-plugin": "^4.31.1",
"@typescript-eslint/parser": "^4.31.1",
"chai": "^4.3.4",
@ -45,6 +46,7 @@
"buffer": "^6.0.3",
"js-sha3": "^0.8.0",
"js-waku": "^0.12.0",
"protobufjs": "^6.11.2"
"protobufjs": "^6.11.2",
"secp256k1": "^4.0.2"
}
}

View File

@ -0,0 +1,50 @@
syntax = "proto3";
package status.v1;
message ApplicationMetadataMessage {
// Signature of the payload field
bytes signature = 1;
// This is the encoded protobuf of the application level message, i.e ChatMessage
bytes payload = 2;
// The type of protobuf message sent
Type type = 3;
enum Type {
TYPE_UNKNOWN_UNSPECIFIED = 0;
TYPE_CHAT_MESSAGE = 1;
TYPE_CONTACT_UPDATE = 2;
TYPE_MEMBERSHIP_UPDATE_MESSAGE = 3;
TYPE_PAIR_INSTALLATION = 4;
TYPE_SYNC_INSTALLATION = 5;
TYPE_REQUEST_ADDRESS_FOR_TRANSACTION = 6;
TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7;
TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8;
TYPE_REQUEST_TRANSACTION = 9;
TYPE_SEND_TRANSACTION = 10;
TYPE_DECLINE_REQUEST_TRANSACTION = 11;
TYPE_SYNC_INSTALLATION_CONTACT = 12;
TYPE_SYNC_INSTALLATION_ACCOUNT = 13;
TYPE_SYNC_INSTALLATION_PUBLIC_CHAT = 14;
TYPE_CONTACT_CODE_ADVERTISEMENT = 15;
TYPE_PUSH_NOTIFICATION_REGISTRATION = 16;
TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17;
TYPE_PUSH_NOTIFICATION_QUERY = 18;
TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE = 19;
TYPE_PUSH_NOTIFICATION_REQUEST = 20;
TYPE_PUSH_NOTIFICATION_RESPONSE = 21;
TYPE_EMOJI_REACTION = 22;
TYPE_GROUP_CHAT_INVITATION = 23;
TYPE_CHAT_IDENTITY = 24;
TYPE_COMMUNITY_DESCRIPTION = 25;
TYPE_COMMUNITY_INVITATION = 26;
TYPE_COMMUNITY_REQUEST_TO_JOIN = 27;
TYPE_PIN_MESSAGE = 28;
TYPE_EDIT_MESSAGE = 29;
TYPE_STATUS_UPDATE = 30;
TYPE_DELETE_MESSAGE = 31;
TYPE_SYNC_INSTALLATION_COMMUNITY = 32;
TYPE_ANONYMOUS_METRIC_BATCH = 33;
}
}

View File

@ -0,0 +1,61 @@
import { Reader } from "protobufjs";
import { ChatMessage } from "./chat_message";
import { Identity } from "./identity";
import * as proto from "./proto/status/v1/application_metadata_message";
import { ApplicationMetadataMessage_Type } from "./proto/status/v1/application_metadata_message";
export class ApplicationMetadataMessage {
private constructor(public proto: proto.ApplicationMetadataMessage) {}
/**
* Create a chat message to be sent to an Open (permission = no membership) community
*/
public static create(
payload: Uint8Array,
type: ApplicationMetadataMessage_Type,
identity: Identity
): ApplicationMetadataMessage {
const signature = identity.sign(payload);
const proto = {
signature,
payload,
type,
};
return new ApplicationMetadataMessage(proto);
}
static decode(bytes: Uint8Array): ApplicationMetadataMessage {
const protoBuf = proto.ApplicationMetadataMessage.decode(
Reader.create(bytes)
);
return new ApplicationMetadataMessage(protoBuf);
}
encode(): Uint8Array {
return proto.ApplicationMetadataMessage.encode(this.proto).finish();
}
public get signature(): Uint8Array | undefined {
return this.proto.signature;
}
public get payload(): Uint8Array | undefined {
return this.proto.payload;
}
public get type(): ApplicationMetadataMessage_Type | undefined {
return this.proto.type;
}
/**
* Returns a chat message if the type is [TYPE_CHAT_MESSAGE], undefined otherwise.
*/
public get chatMessage(): ChatMessage | undefined {
if (!this.payload) return;
return ChatMessage.decode(this.payload);
}
}

View File

@ -19,13 +19,13 @@ export class Chat {
const message = ChatMessage.createMessage(clock, timestamp, text, this.id);
this._updateFromMessage(message);
this._updateClockFromMessage(message);
return message;
}
public handleNewMessage(message: ChatMessage) {
this._updateFromMessage(message);
this._updateClockFromMessage(message);
}
private _nextClockAndTimestamp(): { clock: number; timestamp: number } {
@ -41,7 +41,7 @@ export class Chat {
return { clock, timestamp };
}
private _updateFromMessage(message: ChatMessage): void {
private _updateClockFromMessage(message: ChatMessage): void {
if (!this.lastMessage || this.lastMessage.clock <= message.clock) {
this.lastMessage = message;
}

View File

@ -0,0 +1,29 @@
import { Buffer } from "buffer";
import { keccak256 } from "js-sha3";
import { generatePrivateKey } from "js-waku";
import { utils } from "js-waku";
import * as secp256k1 from "secp256k1";
export class Identity {
public constructor(private privateKey: Uint8Array) {}
public static generate(): Identity {
const privateKey = generatePrivateKey();
return new Identity(privateKey);
}
/**
* Hashes the payload with SHA3-256 and signs the result using the internal private key.
*/
public sign(payload: Uint8Array): Uint8Array {
const hash = keccak256(payload);
const { signature, recid } = secp256k1.ecdsaSign(
utils.hexToBuf(hash),
this.privateKey
);
return Buffer.concat([signature, Buffer.from([recid])]);
}
}

View File

@ -1,38 +1,43 @@
import { expect } from "chai";
import { ChatMessage } from "./chat_message";
import { ApplicationMetadataMessage } from "./application_metadata_message";
import { Identity } from "./identity";
import { Messenger } from "./messenger";
const testChatId = "test-chat-id";
describe("Messenger", () => {
let messenger1: Messenger;
let messenger2: Messenger;
let messengerAlice: Messenger;
let messengerBob: Messenger;
beforeEach(async function () {
this.timeout(10_000);
[messenger1, messenger2] = await Promise.all([
Messenger.create(),
Messenger.create({
const identityAlice = Identity.generate();
const identityBob = Identity.generate();
[messengerAlice, messengerBob] = await Promise.all([
Messenger.create(identityAlice),
Messenger.create(identityBob, {
libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } },
}),
]);
// Connect both messengers together for test purposes
messenger1.waku.addPeerToAddressBook(
messenger2.waku.libp2p.peerId,
messenger2.waku.libp2p.multiaddrs
messengerAlice.waku.addPeerToAddressBook(
messengerBob.waku.libp2p.peerId,
messengerBob.waku.libp2p.multiaddrs
);
await Promise.all([
new Promise((resolve) =>
messenger1.waku.libp2p.pubsub.once("pubsub:subscription-change", () =>
resolve(null)
messengerAlice.waku.libp2p.pubsub.once(
"pubsub:subscription-change",
() => resolve(null)
)
),
new Promise((resolve) =>
messenger2.waku.libp2p.pubsub.once("pubsub:subscription-change", () =>
messengerBob.waku.libp2p.pubsub.once("pubsub:subscription-change", () =>
resolve(null)
)
),
@ -42,29 +47,28 @@ describe("Messenger", () => {
it("Sends & Receive message in public chat", async function () {
this.timeout(10_000);
messenger1.joinChat(testChatId);
messenger2.joinChat(testChatId);
messengerAlice.joinChat(testChatId);
messengerBob.joinChat(testChatId);
const text = "This is a message.";
const receivedMessagePromise: Promise<ChatMessage> = new Promise(
(resolve) => {
messenger2.addObserver((message) => {
const receivedMessagePromise: Promise<ApplicationMetadataMessage> =
new Promise((resolve) => {
messengerBob.addObserver((message) => {
resolve(message);
}, testChatId);
}
);
});
await messenger1.sendMessage(text, testChatId);
await messengerAlice.sendMessage(text, testChatId);
const receivedMessage = await receivedMessagePromise;
expect(receivedMessage?.text).to.eq(text);
expect(receivedMessage.chatMessage?.text).to.eq(text);
});
afterEach(async function () {
this.timeout(5000);
await messenger1.stop();
await messenger2.stop();
await messengerAlice.stop();
await messengerBob.stop();
});
});

View File

@ -1,26 +1,37 @@
import debug from "debug";
import { Waku, WakuMessage } from "js-waku";
import { CreateOptions as WakuCreateOptions } from "js-waku/build/main/lib/waku";
import { ApplicationMetadataMessage } from "./application_metadata_message";
import { Chat } from "./chat";
import { ChatMessage } from "./chat_message";
import { Identity } from "./identity";
import { ApplicationMetadataMessage_Type } from "./proto/status/v1/application_metadata_message";
const dbg = debug("communities:messenger");
export class Messenger {
waku: Waku;
chatsById: Map<string, Chat>;
observers: {
[chatId: string]: Set<(chatMessage: ChatMessage) => void>;
[chatId: string]: Set<(message: ApplicationMetadataMessage) => void>;
};
identity: Identity;
private constructor(waku: Waku) {
private constructor(identity: Identity, waku: Waku) {
this.identity = identity;
this.waku = waku;
this.chatsById = new Map();
this.observers = {};
}
public static async create(wakuOptions?: WakuCreateOptions) {
public static async create(
identity: Identity,
wakuOptions?: WakuCreateOptions
) {
const _wakuOptions = Object.assign({ bootstrap: true }, wakuOptions);
const waku = await Waku.create(_wakuOptions);
return new Messenger(waku);
return new Messenger(identity, waku);
}
/**
@ -37,14 +48,14 @@ export class Messenger {
(wakuMessage: WakuMessage) => {
if (!wakuMessage.payload) return;
const chatMessage = ChatMessage.decode(wakuMessage.payload);
const message = ApplicationMetadataMessage.decode(wakuMessage.payload);
chat.handleNewMessage(chatMessage);
if (this.observers[chatId]) {
this.observers[chatId].forEach((observer) => {
observer(chatMessage);
});
switch (message.type) {
case ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE:
this._handleNewChatMessage(chat, message);
break;
default:
dbg("Received unsupported message type", message.type);
}
},
[chat.contentTopic]
@ -63,10 +74,17 @@ export class Messenger {
const chat = this.chatsById.get(chatId);
if (!chat) throw `Chat not joined: ${chatId}`;
const message = chat.createMessage(text);
const chatMessage = chat.createMessage(text);
const appMetadataMessage = ApplicationMetadataMessage.create(
chatMessage.encode(),
ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE,
this.identity
);
// TODO: Use version 1 with signature
const wakuMessage = await WakuMessage.fromBytes(
message.encode(),
appMetadataMessage.encode(),
chat.contentTopic
);
@ -74,12 +92,12 @@ export class Messenger {
}
/**
* Add an observer of new messages received on the chat.
* Add an observer of new messages received on the given chat id.
*
* @throws string If the chat has not been joined first using [joinChat].
*/
public addObserver(
observer: (chatMessage: ChatMessage) => void,
observer: (message: ApplicationMetadataMessage) => void,
chatId: string
) {
// Not sure this is the best design here. Maybe `addObserver` and `joinChat` should be merged.
@ -94,13 +112,13 @@ export class Messenger {
}
/**
* Add an observer of new messages received on the chat.
* Delete an observer of new messages received on the given chat id.
*
* @throws string If the chat has not been joined first using [joinChat].
*/
deleteObserver(
observer: (chatMessage: ChatMessage) => void,
observer: (message: ApplicationMetadataMessage) => void,
chatId: string
): void {
if (this.observers[chatId]) {
@ -114,4 +132,20 @@ export class Messenger {
public async stop(): Promise<void> {
await this.waku.stop();
}
private _handleNewChatMessage(
chat: Chat,
message: ApplicationMetadataMessage
) {
if (!message.payload || !message.type || !message.signature) return;
const chatMessage = ChatMessage.decode(message.payload);
chat.handleNewMessage(chatMessage);
if (this.observers[chat.id]) {
this.observers[chat.id].forEach((observer) => {
observer(message);
});
}
}
}

View File

@ -0,0 +1,409 @@
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
export const protobufPackage = "status.v1";
export interface ApplicationMetadataMessage {
/** Signature of the payload field */
signature: Uint8Array;
/** This is the encoded protobuf of the application level message, i.e ChatMessage */
payload: Uint8Array;
/** The type of protobuf message sent */
type: ApplicationMetadataMessage_Type;
}
export enum ApplicationMetadataMessage_Type {
TYPE_UNKNOWN_UNSPECIFIED = 0,
TYPE_CHAT_MESSAGE = 1,
TYPE_CONTACT_UPDATE = 2,
TYPE_MEMBERSHIP_UPDATE_MESSAGE = 3,
TYPE_PAIR_INSTALLATION = 4,
TYPE_SYNC_INSTALLATION = 5,
TYPE_REQUEST_ADDRESS_FOR_TRANSACTION = 6,
TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION = 7,
TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION = 8,
TYPE_REQUEST_TRANSACTION = 9,
TYPE_SEND_TRANSACTION = 10,
TYPE_DECLINE_REQUEST_TRANSACTION = 11,
TYPE_SYNC_INSTALLATION_CONTACT = 12,
TYPE_SYNC_INSTALLATION_ACCOUNT = 13,
TYPE_SYNC_INSTALLATION_PUBLIC_CHAT = 14,
TYPE_CONTACT_CODE_ADVERTISEMENT = 15,
TYPE_PUSH_NOTIFICATION_REGISTRATION = 16,
TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE = 17,
TYPE_PUSH_NOTIFICATION_QUERY = 18,
TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE = 19,
TYPE_PUSH_NOTIFICATION_REQUEST = 20,
TYPE_PUSH_NOTIFICATION_RESPONSE = 21,
TYPE_EMOJI_REACTION = 22,
TYPE_GROUP_CHAT_INVITATION = 23,
TYPE_CHAT_IDENTITY = 24,
TYPE_COMMUNITY_DESCRIPTION = 25,
TYPE_COMMUNITY_INVITATION = 26,
TYPE_COMMUNITY_REQUEST_TO_JOIN = 27,
TYPE_PIN_MESSAGE = 28,
TYPE_EDIT_MESSAGE = 29,
TYPE_STATUS_UPDATE = 30,
TYPE_DELETE_MESSAGE = 31,
TYPE_SYNC_INSTALLATION_COMMUNITY = 32,
TYPE_ANONYMOUS_METRIC_BATCH = 33,
UNRECOGNIZED = -1,
}
export function applicationMetadataMessage_TypeFromJSON(
object: any
): ApplicationMetadataMessage_Type {
switch (object) {
case 0:
case "TYPE_UNKNOWN_UNSPECIFIED":
return ApplicationMetadataMessage_Type.TYPE_UNKNOWN_UNSPECIFIED;
case 1:
case "TYPE_CHAT_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE;
case 2:
case "TYPE_CONTACT_UPDATE":
return ApplicationMetadataMessage_Type.TYPE_CONTACT_UPDATE;
case 3:
case "TYPE_MEMBERSHIP_UPDATE_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_MEMBERSHIP_UPDATE_MESSAGE;
case 4:
case "TYPE_PAIR_INSTALLATION":
return ApplicationMetadataMessage_Type.TYPE_PAIR_INSTALLATION;
case 5:
case "TYPE_SYNC_INSTALLATION":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION;
case 6:
case "TYPE_REQUEST_ADDRESS_FOR_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_REQUEST_ADDRESS_FOR_TRANSACTION;
case 7:
case "TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION;
case 8:
case "TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION;
case 9:
case "TYPE_REQUEST_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_REQUEST_TRANSACTION;
case 10:
case "TYPE_SEND_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_SEND_TRANSACTION;
case 11:
case "TYPE_DECLINE_REQUEST_TRANSACTION":
return ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_TRANSACTION;
case 12:
case "TYPE_SYNC_INSTALLATION_CONTACT":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_CONTACT;
case 13:
case "TYPE_SYNC_INSTALLATION_ACCOUNT":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_ACCOUNT;
case 14:
case "TYPE_SYNC_INSTALLATION_PUBLIC_CHAT":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_PUBLIC_CHAT;
case 15:
case "TYPE_CONTACT_CODE_ADVERTISEMENT":
return ApplicationMetadataMessage_Type.TYPE_CONTACT_CODE_ADVERTISEMENT;
case 16:
case "TYPE_PUSH_NOTIFICATION_REGISTRATION":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION;
case 17:
case "TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE;
case 18:
case "TYPE_PUSH_NOTIFICATION_QUERY":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY;
case 19:
case "TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE;
case 20:
case "TYPE_PUSH_NOTIFICATION_REQUEST":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REQUEST;
case 21:
case "TYPE_PUSH_NOTIFICATION_RESPONSE":
return ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_RESPONSE;
case 22:
case "TYPE_EMOJI_REACTION":
return ApplicationMetadataMessage_Type.TYPE_EMOJI_REACTION;
case 23:
case "TYPE_GROUP_CHAT_INVITATION":
return ApplicationMetadataMessage_Type.TYPE_GROUP_CHAT_INVITATION;
case 24:
case "TYPE_CHAT_IDENTITY":
return ApplicationMetadataMessage_Type.TYPE_CHAT_IDENTITY;
case 25:
case "TYPE_COMMUNITY_DESCRIPTION":
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_DESCRIPTION;
case 26:
case "TYPE_COMMUNITY_INVITATION":
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_INVITATION;
case 27:
case "TYPE_COMMUNITY_REQUEST_TO_JOIN":
return ApplicationMetadataMessage_Type.TYPE_COMMUNITY_REQUEST_TO_JOIN;
case 28:
case "TYPE_PIN_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_PIN_MESSAGE;
case 29:
case "TYPE_EDIT_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_EDIT_MESSAGE;
case 30:
case "TYPE_STATUS_UPDATE":
return ApplicationMetadataMessage_Type.TYPE_STATUS_UPDATE;
case 31:
case "TYPE_DELETE_MESSAGE":
return ApplicationMetadataMessage_Type.TYPE_DELETE_MESSAGE;
case 32:
case "TYPE_SYNC_INSTALLATION_COMMUNITY":
return ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_COMMUNITY;
case 33:
case "TYPE_ANONYMOUS_METRIC_BATCH":
return ApplicationMetadataMessage_Type.TYPE_ANONYMOUS_METRIC_BATCH;
case -1:
case "UNRECOGNIZED":
default:
return ApplicationMetadataMessage_Type.UNRECOGNIZED;
}
}
export function applicationMetadataMessage_TypeToJSON(
object: ApplicationMetadataMessage_Type
): string {
switch (object) {
case ApplicationMetadataMessage_Type.TYPE_UNKNOWN_UNSPECIFIED:
return "TYPE_UNKNOWN_UNSPECIFIED";
case ApplicationMetadataMessage_Type.TYPE_CHAT_MESSAGE:
return "TYPE_CHAT_MESSAGE";
case ApplicationMetadataMessage_Type.TYPE_CONTACT_UPDATE:
return "TYPE_CONTACT_UPDATE";
case ApplicationMetadataMessage_Type.TYPE_MEMBERSHIP_UPDATE_MESSAGE:
return "TYPE_MEMBERSHIP_UPDATE_MESSAGE";
case ApplicationMetadataMessage_Type.TYPE_PAIR_INSTALLATION:
return "TYPE_PAIR_INSTALLATION";
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION:
return "TYPE_SYNC_INSTALLATION";
case ApplicationMetadataMessage_Type.TYPE_REQUEST_ADDRESS_FOR_TRANSACTION:
return "TYPE_REQUEST_ADDRESS_FOR_TRANSACTION";
case ApplicationMetadataMessage_Type.TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION:
return "TYPE_ACCEPT_REQUEST_ADDRESS_FOR_TRANSACTION";
case ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION:
return "TYPE_DECLINE_REQUEST_ADDRESS_FOR_TRANSACTION";
case ApplicationMetadataMessage_Type.TYPE_REQUEST_TRANSACTION:
return "TYPE_REQUEST_TRANSACTION";
case ApplicationMetadataMessage_Type.TYPE_SEND_TRANSACTION:
return "TYPE_SEND_TRANSACTION";
case ApplicationMetadataMessage_Type.TYPE_DECLINE_REQUEST_TRANSACTION:
return "TYPE_DECLINE_REQUEST_TRANSACTION";
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_CONTACT:
return "TYPE_SYNC_INSTALLATION_CONTACT";
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_ACCOUNT:
return "TYPE_SYNC_INSTALLATION_ACCOUNT";
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_PUBLIC_CHAT:
return "TYPE_SYNC_INSTALLATION_PUBLIC_CHAT";
case ApplicationMetadataMessage_Type.TYPE_CONTACT_CODE_ADVERTISEMENT:
return "TYPE_CONTACT_CODE_ADVERTISEMENT";
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION:
return "TYPE_PUSH_NOTIFICATION_REGISTRATION";
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE:
return "TYPE_PUSH_NOTIFICATION_REGISTRATION_RESPONSE";
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY:
return "TYPE_PUSH_NOTIFICATION_QUERY";
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE:
return "TYPE_PUSH_NOTIFICATION_QUERY_RESPONSE";
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_REQUEST:
return "TYPE_PUSH_NOTIFICATION_REQUEST";
case ApplicationMetadataMessage_Type.TYPE_PUSH_NOTIFICATION_RESPONSE:
return "TYPE_PUSH_NOTIFICATION_RESPONSE";
case ApplicationMetadataMessage_Type.TYPE_EMOJI_REACTION:
return "TYPE_EMOJI_REACTION";
case ApplicationMetadataMessage_Type.TYPE_GROUP_CHAT_INVITATION:
return "TYPE_GROUP_CHAT_INVITATION";
case ApplicationMetadataMessage_Type.TYPE_CHAT_IDENTITY:
return "TYPE_CHAT_IDENTITY";
case ApplicationMetadataMessage_Type.TYPE_COMMUNITY_DESCRIPTION:
return "TYPE_COMMUNITY_DESCRIPTION";
case ApplicationMetadataMessage_Type.TYPE_COMMUNITY_INVITATION:
return "TYPE_COMMUNITY_INVITATION";
case ApplicationMetadataMessage_Type.TYPE_COMMUNITY_REQUEST_TO_JOIN:
return "TYPE_COMMUNITY_REQUEST_TO_JOIN";
case ApplicationMetadataMessage_Type.TYPE_PIN_MESSAGE:
return "TYPE_PIN_MESSAGE";
case ApplicationMetadataMessage_Type.TYPE_EDIT_MESSAGE:
return "TYPE_EDIT_MESSAGE";
case ApplicationMetadataMessage_Type.TYPE_STATUS_UPDATE:
return "TYPE_STATUS_UPDATE";
case ApplicationMetadataMessage_Type.TYPE_DELETE_MESSAGE:
return "TYPE_DELETE_MESSAGE";
case ApplicationMetadataMessage_Type.TYPE_SYNC_INSTALLATION_COMMUNITY:
return "TYPE_SYNC_INSTALLATION_COMMUNITY";
case ApplicationMetadataMessage_Type.TYPE_ANONYMOUS_METRIC_BATCH:
return "TYPE_ANONYMOUS_METRIC_BATCH";
default:
return "UNKNOWN";
}
}
const baseApplicationMetadataMessage: object = { type: 0 };
export const ApplicationMetadataMessage = {
encode(
message: ApplicationMetadataMessage,
writer: _m0.Writer = _m0.Writer.create()
): _m0.Writer {
if (message.signature.length !== 0) {
writer.uint32(10).bytes(message.signature);
}
if (message.payload.length !== 0) {
writer.uint32(18).bytes(message.payload);
}
if (message.type !== 0) {
writer.uint32(24).int32(message.type);
}
return writer;
},
decode(
input: _m0.Reader | Uint8Array,
length?: number
): ApplicationMetadataMessage {
const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = {
...baseApplicationMetadataMessage,
} as ApplicationMetadataMessage;
message.signature = new Uint8Array();
message.payload = new Uint8Array();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
message.signature = reader.bytes();
break;
case 2:
message.payload = reader.bytes();
break;
case 3:
message.type = reader.int32() as any;
break;
default:
reader.skipType(tag & 7);
break;
}
}
return message;
},
fromJSON(object: any): ApplicationMetadataMessage {
const message = {
...baseApplicationMetadataMessage,
} as ApplicationMetadataMessage;
message.signature = new Uint8Array();
message.payload = new Uint8Array();
if (object.signature !== undefined && object.signature !== null) {
message.signature = bytesFromBase64(object.signature);
}
if (object.payload !== undefined && object.payload !== null) {
message.payload = bytesFromBase64(object.payload);
}
if (object.type !== undefined && object.type !== null) {
message.type = applicationMetadataMessage_TypeFromJSON(object.type);
} else {
message.type = 0;
}
return message;
},
toJSON(message: ApplicationMetadataMessage): unknown {
const obj: any = {};
message.signature !== undefined &&
(obj.signature = base64FromBytes(
message.signature !== undefined ? message.signature : new Uint8Array()
));
message.payload !== undefined &&
(obj.payload = base64FromBytes(
message.payload !== undefined ? message.payload : new Uint8Array()
));
message.type !== undefined &&
(obj.type = applicationMetadataMessage_TypeToJSON(message.type));
return obj;
},
fromPartial(
object: DeepPartial<ApplicationMetadataMessage>
): ApplicationMetadataMessage {
const message = {
...baseApplicationMetadataMessage,
} as ApplicationMetadataMessage;
if (object.signature !== undefined && object.signature !== null) {
message.signature = object.signature;
} else {
message.signature = new Uint8Array();
}
if (object.payload !== undefined && object.payload !== null) {
message.payload = object.payload;
} else {
message.payload = new Uint8Array();
}
if (object.type !== undefined && object.type !== null) {
message.type = object.type;
} else {
message.type = 0;
}
return message;
},
};
declare var self: any | undefined;
declare var window: any | undefined;
declare var global: any | undefined;
var globalThis: any = (() => {
if (typeof globalThis !== "undefined") return globalThis;
if (typeof self !== "undefined") return self;
if (typeof window !== "undefined") return window;
if (typeof global !== "undefined") return global;
throw "Unable to locate global object";
})();
const atob: (b64: string) => string =
globalThis.atob ||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
function bytesFromBase64(b64: string): Uint8Array {
const bin = atob(b64);
const arr = new Uint8Array(bin.length);
for (let i = 0; i < bin.length; ++i) {
arr[i] = bin.charCodeAt(i);
}
return arr;
}
const btoa: (bin: string) => string =
globalThis.btoa ||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
function base64FromBytes(arr: Uint8Array): string {
const bin: string[] = [];
for (const byte of arr) {
bin.push(String.fromCharCode(byte));
}
return btoa(bin.join(""));
}
type Builtin =
| Date
| Function
| Uint8Array
| string
| number
| boolean
| undefined;
export type DeepPartial<T> = T extends Builtin
? T
: T extends Array<infer U>
? Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U>
? ReadonlyArray<DeepPartial<U>>
: T extends {}
? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
}

View File

@ -604,6 +604,15 @@ __metadata:
languageName: node
linkType: hard
"@types/secp256k1@npm:^4.0.3":
version: 4.0.3
resolution: "@types/secp256k1@npm:4.0.3"
dependencies:
"@types/node": "*"
checksum: 1bd10b9afa724084b655dc81b7b315def3d2d0e272014ef16009fa76e17537411c07c0695fdea412bc7b36d2a02687f5fea33522d55b8ef29eda42992f812913
languageName: node
linkType: hard
"@types/yargs-parser@npm:*":
version: 20.2.1
resolution: "@types/yargs-parser@npm:20.2.1"
@ -5621,6 +5630,7 @@ fsevents@~2.3.2:
dependencies:
"@types/chai": ^4.2.22
"@types/mocha": ^9.0.0
"@types/secp256k1": ^4.0.3
"@typescript-eslint/eslint-plugin": ^4.31.1
"@typescript-eslint/parser": ^4.31.1
buffer: ^6.0.3
@ -5637,6 +5647,7 @@ fsevents@~2.3.2:
npm-run-all: ^4.1.5
prettier: ^2.4.0
protobufjs: ^6.11.2
secp256k1: ^4.0.2
ts-node: ^10.2.1
ts-proto: ^1.83.0
typescript: ^4.4.3