diff --git a/packages/status-communities/src/application_metadata_message.ts b/packages/status-communities/src/application_metadata_message.ts index 63d5658..bfd5c95 100644 --- a/packages/status-communities/src/application_metadata_message.ts +++ b/packages/status-communities/src/application_metadata_message.ts @@ -1,4 +1,7 @@ +import { keccak256 } from "js-sha3"; +import { utils } from "js-waku"; import { Reader } from "protobufjs"; +import secp256k1 from "secp256k1"; import { ChatMessage } from "./chat_message"; import { Identity } from "./identity"; @@ -58,4 +61,14 @@ export class ApplicationMetadataMessage { return ChatMessage.decode(this.payload); } + + public get signer(): Uint8Array | undefined { + if (!this.signature || !this.payload) return; + + const signature = this.signature.slice(0, 64); + const recid = this.signature.slice(64)[0]; + const hash = keccak256(this.payload); + + return secp256k1.ecdsaRecover(signature, recid, utils.hexToBuf(hash)); + } } diff --git a/packages/status-communities/src/identity.ts b/packages/status-communities/src/identity.ts index 2d4c4ae..88ec6e8 100644 --- a/packages/status-communities/src/identity.ts +++ b/packages/status-communities/src/identity.ts @@ -26,4 +26,11 @@ export class Identity { return Buffer.concat([signature, Buffer.from([recid])]); } + + /** + * Returns the compressed public key. + */ + public get publicKey(): Uint8Array { + return secp256k1.publicKeyCreate(this.privateKey, true); + } } diff --git a/packages/status-communities/src/messenger.spec.ts b/packages/status-communities/src/messenger.spec.ts index dd074b8..fa93e2c 100644 --- a/packages/status-communities/src/messenger.spec.ts +++ b/packages/status-communities/src/messenger.spec.ts @@ -1,4 +1,5 @@ import { expect } from "chai"; +import { utils } from "js-waku"; import { ApplicationMetadataMessage } from "./application_metadata_message"; import { Identity } from "./identity"; @@ -9,12 +10,14 @@ const testChatId = "test-chat-id"; describe("Messenger", () => { let messengerAlice: Messenger; let messengerBob: Messenger; + let identityAlice: Identity; + let identityBob: Identity; beforeEach(async function () { this.timeout(10_000); - const identityAlice = Identity.generate(); - const identityBob = Identity.generate(); + identityAlice = Identity.generate(); + identityBob = Identity.generate(); [messengerAlice, messengerBob] = await Promise.all([ Messenger.create(identityAlice), @@ -44,7 +47,7 @@ describe("Messenger", () => { ]); }); - it("Sends & Receive message in public chat", async function () { + it("Sends & Receive public chat messages", async function () { this.timeout(10_000); await messengerAlice.joinChat(testChatId); @@ -66,6 +69,30 @@ describe("Messenger", () => { expect(receivedMessage.chatMessage?.text).to.eq(text); }); + it("public chat messages have signers", async function () { + this.timeout(10_000); + + await messengerAlice.joinChat(testChatId); + await messengerBob.joinChat(testChatId); + + const text = "This is a message."; + + const receivedMessagePromise: Promise = + new Promise((resolve) => { + messengerBob.addObserver((message) => { + resolve(message); + }, testChatId); + }); + + await messengerAlice.sendMessage(text, testChatId); + + const receivedMessage = await receivedMessagePromise; + + expect(utils.bufToHex(receivedMessage.signer!)).to.eq( + utils.bufToHex(identityAlice.publicKey) + ); + }); + afterEach(async function () { this.timeout(5000); await messengerAlice.stop();