From 72b01de7a5b0fb00b64defda1dca1c706b0cb8db Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:07:41 +0100 Subject: [PATCH 01/10] wip: signatures --- src/cli/cli.ts | 19 ++ src/lib/adapters/waku/crypto.ts | 16 +- src/lib/adapters/waku/index.ts | 280 ++++++++++++++++++----- src/lib/adapters/waku/safe-waku.ts | 74 ++++-- src/lib/adapters/waku/waku.ts | 51 +---- src/lib/adapters/waku/wakustore.ts | 127 +++++----- src/routes/invite/[address]/+page.svelte | 2 +- 7 files changed, 383 insertions(+), 186 deletions(-) diff --git a/src/cli/cli.ts b/src/cli/cli.ts index af960a56..863c9708 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -18,6 +18,7 @@ async function main() { fund, balance, txinfo, + waku, } const fn = commands[command] @@ -66,4 +67,22 @@ async function txinfo(hash: string) { console.log({ tx, receipt }) } +async function waku() { + const command = process.argv[3] + const restArgs = process.argv.slice(4) + + const commands: Record Promise> = { + doc, + } + + const fn = commands[command] + if (!fn) { + throw `unknown command: ${command}\nUsage: cli waku ${Object.keys(commands).join('|')}` + } + + await fn(...restArgs) + + process.exit(0) +} + main().catch(console.error) diff --git a/src/lib/adapters/waku/crypto.ts b/src/lib/adapters/waku/crypto.ts index 0c0d4374..f38c923e 100644 --- a/src/lib/adapters/waku/crypto.ts +++ b/src/lib/adapters/waku/crypto.ts @@ -3,15 +3,16 @@ import { sign as nobleSign, ProjectivePoint, Signature, + getPublicKey, } from '@noble/secp256k1' import { keccak_256 } from '@noble/hashes/sha3' import { bytesToHex, hexToBytes } from '@waku/utils/bytes' import { gcm } from '@noble/ciphers/aes' import { randomBytes } from '@noble/ciphers/webcrypto/utils' -type Hex = string +export type Hex = string -function fixHex(h: Hex): Hex { +export function fixHex(h: Hex): Hex { if (h.startsWith('0x')) { return h.slice(2) } @@ -53,6 +54,11 @@ export function publicKeyToAddress(publicKey: Hex): Hex { return '0x' + keyHash.slice(-40) } +export function compressPublicKey(publicKey: Hex | Uint8Array): Hex { + publicKey = typeof publicKey === 'string' ? fixHex(publicKey) : bytesToHex(publicKey) + return ProjectivePoint.fromHex(publicKey).toHex(true) +} + export function signatureToPublicKey(signature: Hex, messageHash: Hex): Hex { const publicKey = Signature.fromCompact(fixHex(signature)).recoverPublicKey(fixHex(messageHash)) return publicKey.toHex(true) @@ -63,3 +69,9 @@ export function sign(privateKey: Hex, data: Uint8Array): Hex { const signature = nobleSign(messageHash, fixHex(privateKey)) return signature.toCompactHex() } + +export function privateKeyToPublicKey(privateKey: Hex | Uint8Array): Hex { + const privateKeyHex = typeof privateKey === 'string' ? fixHex(privateKey) : bytesToHex(privateKey) + const publicKeyBytes = getPublicKey(privateKeyHex) + return bytesToHex(publicKeyBytes) +} diff --git a/src/lib/adapters/waku/index.ts b/src/lib/adapters/waku/index.ts index 77a5c41a..53240fcf 100644 --- a/src/lib/adapters/waku/index.ts +++ b/src/lib/adapters/waku/index.ts @@ -47,9 +47,16 @@ import { balanceStore } from '$lib/stores/balances' import type { ContentTopic } from './waku' import { installedObjectStore } from '$lib/stores/installed-objects' import { errorStore } from '$lib/stores/error' -import { getSharedSecret, hash } from './crypto' +import { compressPublicKey, fixHex, getSharedSecret, hash } from './crypto' import { bytesToHex, hexToBytes } from '@waku/utils/bytes' import { encrypt, decrypt } from './crypto' +import { + createEciesDecoder, + createEciesEncoder, + createSymmetricDecoder, + createSymmetricEncoder, +} from './codec' +import type { DecodedMessage } from '@waku/message-encryption' const MAX_MESSAGES = 100 @@ -203,32 +210,48 @@ async function getDoc( ): Promise { const id = hash(symKey) const key = `${contentTopic}/${id}` - const encryptedKey = encryptStringToHex(key, symKey) - const value = localStorage.getItem(encryptedKey) + const hashedKey = hash(new TextEncoder().encode(key)) + const value = localStorage.getItem(hashedKey) + if (value && value !== 'undefined') { const decryptedValue = decryptHexToString(value, symKey) return JSON.parse(decryptedValue) as T } - const storeValue = await ws.getDoc(contentTopic, symKey) - const json = JSON.stringify(storeValue) + const decoder = createSymmetricDecoder({ contentTopic, symKey }) + const storeValue = await ws.getDoc(decoder) + if (!storeValue) { + return + } + const json = JSON.stringify(storeValue) const encryptedJson = encryptStringToHex(json, symKey) - localStorage.setItem(encryptedKey, encryptedJson) + localStorage.setItem(hashedKey, encryptedJson) return storeValue } -async function setDoc(ws: Wakustore, contentTopic: ContentTopic, symKey: Uint8Array, doc: T) { +async function setDoc( + ws: Wakustore, + contentTopic: ContentTopic, + symKey: Uint8Array, + sigPrivKey: Uint8Array, + doc: T, +) { + if (!doc) { + return + } + const id = hash(symKey) const key = `${contentTopic}/${id}` - const encryptedKey = encryptStringToHex(key, symKey) + const hashedKey = hash(new TextEncoder().encode(key)) const json = JSON.stringify(doc) const encryptedJson = encryptStringToHex(json, symKey) - localStorage.setItem(encryptedKey, encryptedJson) + localStorage.setItem(hashedKey, encryptedJson) - return await ws.setDoc(contentTopic, symKey, doc) + const encoder = createSymmetricEncoder({ contentTopic, symKey, sigPrivKey }) + return await ws.setDoc(encoder, doc) } export default class WakuAdapter implements Adapter { @@ -242,7 +265,7 @@ export default class WakuAdapter implements Adapter { const ownPublicKey = wallet.signingKey.compressedPublicKey const ownPublicEncryptionKey = hexToBytes(hash(ownPublicKey)) - const ownPrivateEncryptionKey = hexToBytes(hash(wallet.privateKey)) + const ownPrivateEncryptionKey = hexToBytes(hash(ownPrivateKey)) const ws = await this.makeWakustore() const wakuObjectAdapter = makeWakuObjectAdapter(this, wallet) @@ -263,27 +286,35 @@ export default class WakuAdapter implements Adapter { chats.update((state) => ({ ...state, chats: new Map(storageChatEntries), loading: false })) // subscribe to invites - const inviteKey = ownPublicEncryptionKey - await this.safeWaku.subscribe(inviteKey, undefined, async (message) => { - if (message.type !== 'invite') { - return - } + const decoder = createEciesDecoder({ contentTopic: 'invites', privateKey: ownPrivateKey }) + await this.safeWaku.subscribeEncrypted( + ownPublicKey, + decoder, + async (message, decodedMessage) => { + if (!this.checkMessageSignature(message, decodedMessage)) { + return + } + + if (message.type !== 'invite') { + return + } - const chatEncryptionKey = getSharedSecret(ownPrivateKey, message.senderPublicKey) + const chatEncryptionKey = getSharedSecret(ownPrivateKey, message.senderPublicKey) - const chatsMap = get(chats).chats - if (!chatsMap.has(chatEncryptionKey)) { - let user = await this.storageProfileToUser(message.senderPublicKey) - if (!user) { - user = { - publicKey: message.senderPublicKey, + const chatsMap = get(chats).chats + if (!chatsMap.has(chatEncryptionKey)) { + let user = await this.storageProfileToUser(message.senderPublicKey) + if (!user) { + user = { + publicKey: message.senderPublicKey, + } } - } - createPrivateChat(chatEncryptionKey, user, ownPublicKey) - } - await this.subscribeToPrivateChat(ownPublicKey, chatEncryptionKey, wakuObjectAdapter) - }) + createPrivateChat(chatEncryptionKey, user, ownPublicKey) + } + await this.subscribeToPrivateChat(ownPublicKey, chatEncryptionKey, wakuObjectAdapter) + }, + ) // subscribe to chats const allChats = Array.from(get(chats).chats) @@ -334,13 +365,15 @@ export default class WakuAdapter implements Adapter { ws, 'objects', ownPrivateEncryptionKey, + hexToBytes(ownPrivateKey), Array.from(objects.objects), ) }) this.subscriptions.push(subscribeObjectStore) // installed objects - const storageInstalledObjects = await ws.getDoc( + const storageInstalledObjects = await getDoc( + ws, 'installed', ownPrivateEncryptionKey, ) @@ -356,9 +389,11 @@ export default class WakuAdapter implements Adapter { firstInstalledObjectStoreSave = false return } - await ws.setDoc( + await setDoc( + ws, 'installed', ownPrivateEncryptionKey, + hexToBytes(ownPrivateKey), Array.from(installed.objects), ) }) @@ -378,10 +413,8 @@ export default class WakuAdapter implements Adapter { async saveUserProfile(wallet: BaseWallet, name?: string, avatar?: string): Promise { const ownPublicKey = wallet.signingKey.compressedPublicKey - if (!ownPublicKey) { - throw 'wallet not found' - } const ownPublicEncryptionKey = hexToBytes(hash(ownPublicKey)) + const ownPrivateKey = wallet.privateKey const defaultProfile: StorageProfile = { name: name ?? ownPublicKey } const storageProfile = (await this.fetchStorageProfile(ownPublicKey)) || defaultProfile @@ -391,7 +424,13 @@ export default class WakuAdapter implements Adapter { if (avatar || name) { const ws = await this.makeWakustore() - setDoc(ws, 'profile', ownPublicEncryptionKey, storageProfile) + setDoc( + ws, + 'profile', + ownPublicEncryptionKey, + hexToBytes(ownPrivateKey), + storageProfile, + ) profile.update((state) => ({ ...state, name, avatar })) } } @@ -417,8 +456,15 @@ export default class WakuAdapter implements Adapter { chatId: ownPublicKey, } - const inviteEncryptionKey = hexToBytes(hash(peerPublicKey)) - await this.safeWaku.sendMessage(inviteMessage, inviteEncryptionKey) + // const inviteEncryptionKey = hexToBytes(hash(peerPublicKey)) + // await this.safeWaku.sendMessage(inviteMessage, inviteEncryptionKey, hexToBytes(ownPrivateKey)) + const ws = await this.makeWakustore() + const encoder = createEciesEncoder({ + contentTopic: 'invites', + publicKey: peerPublicKey, + sigPrivKey: ownPrivateKey, + }) + await ws.setDoc(encoder, inviteMessage) const chatEncryptionKey = getSharedSecret(ownPrivateKey, peerPublicKey) const joined = true @@ -459,8 +505,13 @@ export default class WakuAdapter implements Adapter { const ws = await this.makeWakustore() const encryptionKey = hexToBytes(chatId) - console.debug({ encryptionKey, storageChat, chatId }) - await ws.setDoc('group-chats', encryptionKey, storageChat) + const privateKey = hexToBytes(wallet.privateKey) + const encoder = createSymmetricEncoder({ + contentTopic: 'group-chats', + symKey: encryptionKey, + sigPrivKey: privateKey, + }) + await ws.setDoc(encoder, storageChat) const ownPublicKey = wallet.signingKey.compressedPublicKey await this.subscribeToGroupChat(ownPublicKey, chatId, wakuObjectAdapter) @@ -471,8 +522,9 @@ export default class WakuAdapter implements Adapter { async addMemberToGroupChat(chatId: string, users: string[]): Promise { const ws = await this.makeWakustore() const encryptionKey = hexToBytes(chatId) + const decoder = createSymmetricDecoder({ contentTopic: 'group-chats', symKey: encryptionKey }) - const groupChat = await ws.getDoc('group-chats', encryptionKey) + const groupChat = await ws.getDoc(decoder) if (!groupChat) { return } @@ -482,14 +534,26 @@ export default class WakuAdapter implements Adapter { groupChat.users = uniqueUsers - await ws.setDoc('group-chats', encryptionKey, groupChat) + const wallet = get(walletStore).wallet + if (!wallet) { + return + } + + const privateKey = hexToBytes(wallet.privateKey) + const encoder = createSymmetricEncoder({ + contentTopic: 'group-chats', + symKey: encryptionKey, + sigPrivKey: privateKey, + }) + await ws.setDoc(encoder, groupChat) } async removeFromGroupChat(chatId: string, address: string): Promise { const ws = await this.makeWakustore() const encryptionKey = hexToBytes(chatId) - const groupChat = await ws.getDoc('group-chats', encryptionKey) + const decoder = createSymmetricDecoder({ contentTopic: 'group-chats', symKey: encryptionKey }) + const groupChat = await ws.getDoc(decoder) if (!groupChat) { return } @@ -498,14 +562,26 @@ export default class WakuAdapter implements Adapter { users: groupChat.users.filter((user) => user !== address), } - await ws.setDoc('group-chats', encryptionKey, updatedGroupChat) + const wallet = get(walletStore).wallet + if (!wallet) { + return + } + + const privateKey = hexToBytes(wallet.privateKey) + const encoder = createSymmetricEncoder({ + contentTopic: 'group-chats', + symKey: encryptionKey, + sigPrivKey: privateKey, + }) + await ws.setDoc(encoder, updatedGroupChat) } async saveGroupChatProfile(chatId: string, name?: string, avatar?: string): Promise { const ws = await this.makeWakustore() const encryptionKey = hexToBytes(chatId) - const groupChat = await ws.getDoc('group-chats', encryptionKey) + const decoder = createSymmetricDecoder({ contentTopic: 'group-chats', symKey: encryptionKey }) + const groupChat = await ws.getDoc(decoder) if (!groupChat) { return } @@ -513,11 +589,23 @@ export default class WakuAdapter implements Adapter { groupChat.name = name ?? groupChat.name groupChat.avatar = avatar ?? groupChat.avatar - await ws.setDoc('group-chats', encryptionKey, groupChat) + const wallet = get(walletStore).wallet + if (!wallet) { + return + } + + const privateKey = hexToBytes(wallet.privateKey) + const encoder = createSymmetricEncoder({ + contentTopic: 'group-chats', + symKey: encryptionKey, + sigPrivKey: privateKey, + }) + await ws.setDoc(encoder, groupChat) } async sendChatMessage(wallet: BaseWallet, chatId: string, text: string): Promise { const senderPublicKey = wallet.signingKey.compressedPublicKey + const senderPrivateKey = wallet.privateKey const message: Message = { type: 'user', timestamp: Date.now(), @@ -527,7 +615,7 @@ export default class WakuAdapter implements Adapter { const encryptionKey = hexToBytes(chatId) - await this.safeWaku.sendMessage(message, encryptionKey) + await this.safeWaku.sendMessage(message, encryptionKey, hexToBytes(senderPrivateKey)) } async sendData( @@ -538,6 +626,7 @@ export default class WakuAdapter implements Adapter { data: JSONSerializable, ): Promise { const senderPublicKey = wallet.signingKey.compressedPublicKey + const senderPrivateKey = wallet.privateKey const message: Message = { type: 'data', timestamp: Date.now(), @@ -549,7 +638,7 @@ export default class WakuAdapter implements Adapter { const encryptionKey = hexToBytes(chatId) - await this.safeWaku.sendMessage(message, encryptionKey) + await this.safeWaku.sendMessage(message, encryptionKey, hexToBytes(senderPrivateKey)) } async sendGroupChatInvite( @@ -566,10 +655,11 @@ export default class WakuAdapter implements Adapter { } const ownPrivateKey = wallet.privateKey + const sigPrivKey = hexToBytes(ownPrivateKey) for (const userPublicKey of userPublicKeys) { const chatEncryptionKey = hexToBytes(getSharedSecret(ownPrivateKey, userPublicKey)) - await this.safeWaku.sendMessage(message, chatEncryptionKey) + await this.safeWaku.sendMessage(message, chatEncryptionKey, sigPrivKey) } } @@ -633,7 +723,34 @@ export default class WakuAdapter implements Adapter { private async fetchStorageProfile(profilePublicKey: string): Promise { const ws = await this.makeWakustore() const profileEncryptionKey = hexToBytes(hash(profilePublicKey)) - const storageProfile = await ws.getDoc('profile', profileEncryptionKey) + const decoder = createSymmetricDecoder({ + contentTopic: 'profile', + symKey: profileEncryptionKey, + }) + const decodedMessage = await ws.getDecodedMessage(decoder) + + if (!decodedMessage) { + console.error('missing document') + return + } + + if (!decodedMessage.signaturePublicKey) { + console.error('missing signature', { decodedMessage }) + return + } + + if (compressPublicKey(decodedMessage.signaturePublicKey) !== fixHex(profilePublicKey)) { + console.error('invalid signature', { + decodedMessage, + profilePublicKey, + signaturePublicKey: bytesToHex(decodedMessage.signaturePublicKey), + }) + return + } + + const storageProfile = await ws.decodeDoc(decodedMessage) + + console.debug({ storageProfile, profilePublicKey, decoder }) return storageProfile } @@ -691,7 +808,11 @@ export default class WakuAdapter implements Adapter { const ws = await this.makeWakustore() const groupEncryptionKey = hexToBytes(groupChatId) - const groupChat = await ws.getDoc('group-chats', groupEncryptionKey) + const decoder = createSymmetricDecoder({ + contentTopic: 'group-chats', + symKey: groupEncryptionKey, + }) + const groupChat = await ws.getDoc(decoder) console.debug({ groupChat, groupChatId }) if (groupChat) { const updatedGroupChat = await this.storageChatToChat(groupChatId, groupChat) @@ -705,8 +826,28 @@ export default class WakuAdapter implements Adapter { } const groupChatSubscription = await ws.onSnapshot( - ws.docQuery('group-chats', groupEncryptionKey), - async (groupChat) => { + ws.docQuery(decoder), + async (groupChat, decodedMessage) => { + // check if signed + if (!decodedMessage.signaturePublicKey) { + return + } + + // check if the chat exists locally + const chat = get(chats).chats.get(groupChatId) + if (!chat) { + return + } + + // check if the signature matches a member of the group + if ( + !chat.users + .map((user) => user.publicKey) + .includes(bytesToHex(decodedMessage.signaturePublicKey)) + ) { + return + } + if (groupChat.users.includes(ownPublicKey)) { const updatedGroupChat = await this.storageChatToChat(groupChatId, groupChat) chats.updateChat(groupChatId, (chat) => ({ @@ -733,9 +874,21 @@ export default class WakuAdapter implements Adapter { timeFilter?: TimeFilter, ) { const encryptionKey = hexToBytes(chatId) + const decoder = createSymmetricDecoder({ + contentTopic: 'private-message', + symKey: encryptionKey, + }) - this.safeWaku.subscribe(encryptionKey, timeFilter, (message) => - this.handleMessage(ownPublicKey, message, encryptionKey, wakuObjectAdapter), + this.safeWaku.subscribeEncrypted( + chatId, + decoder, + async (message, decodedMessage) => { + if (!this.checkMessageSignature(message, decodedMessage)) { + return + } + await this.handleMessage(ownPublicKey, message, encryptionKey, wakuObjectAdapter) + }, + timeFilter, ) } @@ -792,6 +945,20 @@ export default class WakuAdapter implements Adapter { await addMessageToChat(ownPublicKey, adapter, chatId, message, send) } + private checkMessageSignature(message: Message, decodedMessage: DecodedMessage): boolean { + if (!decodedMessage.signaturePublicKey) { + console.debug('missing signature') + return false + } + + if (compressPublicKey(decodedMessage.signaturePublicKey) !== fixHex(message.senderPublicKey)) { + console.error('invalid signature', { decodedMessage, message }) + return false + } + + return true + } + private async updateContactProfiles() { // look for changes in users profile name and picture const allContacts = Array.from(get(chats).chats).flatMap(([, chat]) => chat.users) @@ -834,10 +1001,17 @@ export default class WakuAdapter implements Adapter { const ws = await this.makeWakustore() const chatData: ChatData = get(chats) + const wallet = get(walletStore).wallet + if (!wallet) { + return + } + + const sigPrivKey = hexToBytes(wallet.privateKey) const result = await setDoc( ws, 'chats', ownPrivateEncryptionKey, + sigPrivKey, Array.from(chatData.chats), ) diff --git a/src/lib/adapters/waku/safe-waku.ts b/src/lib/adapters/waku/safe-waku.ts index d00d29c1..db02257a 100644 --- a/src/lib/adapters/waku/safe-waku.ts +++ b/src/lib/adapters/waku/safe-waku.ts @@ -1,14 +1,16 @@ -import { connectWaku, type ConnectWakuOptions, sendMessage } from '$lib/adapters/waku/waku' +import { connectWaku, storeDocument, type ConnectWakuOptions } from '$lib/adapters/waku/waku' import type { Message } from '$lib/stores/chat' -import type { LightNode, TimeFilter, Unsubscribe } from '@waku/interfaces' +import type { IDecoder, IEncoder, LightNode, TimeFilter, Unsubscribe } from '@waku/interfaces' import { PageDirection } from '@waku/interfaces' import { makeWakustore } from './wakustore' -import { bytesToHex, hexToBytes } from '@noble/hashes/utils' +import { createSymmetricEncoder } from './codec' +import type { DecodedMessage } from '@waku/message-encryption' -type Callback = (message: Message, chatId: string) => Promise +type Callback = (message: Message, decodedMessage: DecodedMessage) => Promise interface QueuedMessage { chatMessage: Message + decodedMessage: DecodedMessage chatId: string callback: Callback } @@ -16,6 +18,8 @@ interface QueuedMessage { interface Subscription { unsubscribe: Unsubscribe callback: Callback + decoder: IDecoder + id: string } async function sleep(msec: number) { @@ -49,17 +53,17 @@ export class SafeWaku { return this.lightNode } - async subscribe( - encryptionKey: Uint8Array, - timeFilter: TimeFilter | undefined, - callback: (message: Message, chatId: string) => Promise, + async subscribeEncrypted( + id: string, + decoder: IDecoder, + callback: Callback, + timeFilter?: TimeFilter, ) { if (!this.lightNode) { this.lightNode = await this.safeConnectWaku() } - const chatId = bytesToHex(encryptionKey) - const lastMessageTime = this.lastMessages.get(chatId)?.timestamp || 0 + const lastMessageTime = this.lastMessages.get(id)?.timestamp || 0 const startTime = new Date(lastMessageTime + 1) const endTime = new Date() const calculatedTimeFilter = lastMessageTime @@ -68,24 +72,28 @@ export class SafeWaku { timeFilter = timeFilter || calculatedTimeFilter const talkEmoji = '🗩' - this.log(`${talkEmoji} subscribe to ${chatId}`) + this.log(`${talkEmoji} subscribe to ${id}`) const ws = makeWakustore(this.lightNode) const unsubscribe = await ws.onSnapshot( - ws.collectionQuery('private-message', encryptionKey, { + ws.collectionQuery(decoder, { timeFilter, pageDirection: PageDirection.FORWARD, pageSize: 1000, }), - (message) => this.queueMessage(callback, message, chatId), + (message, decodedMessage) => { + this.queueMessage(id, callback, message, decodedMessage) + }, ) const subscription = { unsubscribe, callback, + id, + decoder, } - this.subscriptions.set(chatId, subscription) + this.subscriptions.set(id, subscription) } async unsubscribeAll() { @@ -96,7 +104,16 @@ export class SafeWaku { this.subscriptions = new Map() } - async sendMessage(message: Message, encryptionKey: Uint8Array) { + async sendMessage(message: Message, encryptionKey: Uint8Array, sigPrivKey: Uint8Array) { + const encoder = createSymmetricEncoder({ + contentTopic: 'private-message', + symKey: encryptionKey, + sigPrivKey, + }) + return await this.storeEncrypted(encoder, message) + } + + async storeEncrypted(encoder: IEncoder, message: { timestamp: number }) { if (!this.lightNode) { this.lightNode = await this.safeConnectWaku() } @@ -113,7 +130,7 @@ export class SafeWaku { do { try { - error = await sendMessage(this.lightNode, encryptionKey, message) + error = await storeDocument(this.lightNode, encoder, message) } catch (e) { error = e } finally { @@ -226,14 +243,17 @@ export class SafeWaku { } if (!subscribeError) { try { - const encryptionKey = hexToBytes(chatId) - await this.subscribe(encryptionKey, undefined, subscription.callback) + await this.subscribeEncrypted( + subscription.id, + subscription.decoder, + subscription.callback, + ) } catch (e) { subscribeError = e - this.subscribeEmpty(chatId, subscription.callback) + this.subscribeEmpty(chatId, subscription.callback, subscription.decoder) } } else { - this.subscribeEmpty(chatId, subscription.callback) + this.subscribeEmpty(chatId, subscription.callback, subscription.decoder) } } @@ -242,21 +262,29 @@ export class SafeWaku { } } - private subscribeEmpty(chatId: string, callback: Callback) { + private subscribeEmpty(chatId: string, callback: Callback, decoder: IDecoder) { const unsubscribe = () => { /* empty */ } const subscription = { + id: chatId, callback, unsubscribe, + decoder, } this.subscriptions.set(chatId, subscription) } - private async queueMessage(callback: Callback, chatMessage: Message, chatId: string) { + private async queueMessage( + chatId: string, + callback: Callback, + chatMessage: Message, + decodedMessage: DecodedMessage, + ) { this.queuedMessages.push({ callback, chatMessage, + decodedMessage, chatId, }) @@ -285,7 +313,7 @@ export class SafeWaku { this.lastMessages.set(chatId, message) try { - await callback(queuedMessage.chatMessage, queuedMessage.chatId) + await callback(queuedMessage.chatMessage, queuedMessage.decodedMessage) } catch (e) { this.log(`⁉️ Error in callback: ${e}`) } diff --git a/src/lib/adapters/waku/waku.ts b/src/lib/adapters/waku/waku.ts index f10f8836..ecb6893d 100644 --- a/src/lib/adapters/waku/waku.ts +++ b/src/lib/adapters/waku/waku.ts @@ -1,10 +1,4 @@ -import { - createLightNode, - waitForRemotePeer, - utf8ToBytes, - bytesToUtf8, - type DecodedMessage, -} from '@waku/sdk' +import { createLightNode, waitForRemotePeer, utf8ToBytes, bytesToUtf8 } from '@waku/sdk' import { multiaddr } from '@multiformats/multiaddr' import { type LightNode, @@ -12,9 +6,11 @@ import { type Callback, type StoreQueryOptions, type Unsubscribe, + type IEncoder, + type IDecoder, } from '@waku/interfaces' import { PUBLIC_WAKU } from '$env/static/public' -import { createDecoder, createEncoder } from '@waku/message-encryption/symmetric' +import type { DecodedMessage } from '@waku/message-encryption' import { hash } from './crypto' function getPeers(): string[] { @@ -89,29 +85,20 @@ export async function connectWaku(options?: ConnectWakuOptions) { export async function subscribe( waku: LightNode, - contentTopic: ContentTopic, - symKey: Uint8Array, + decoder: IDecoder, callback: Callback, ): Promise { - const topicKey = hash(symKey) - const messageDecoder = createDecoder(getTopic(contentTopic, topicKey), symKey) - const unsubscribe = await waku.filter.subscribe([messageDecoder], callback) + const unsubscribe = await waku.filter.subscribe([decoder], callback) return unsubscribe } -export async function storeDocument( - waku: LightNode, - contentTopicName: ContentTopic, - symKey: Uint8Array, - document: unknown, -) { - const topicKey = hash(symKey) - const contentTopic = getTopic(contentTopicName, topicKey) - const encoder = createEncoder({ contentTopic, symKey }) +export async function storeDocument(waku: LightNode, encoder: IEncoder, document: unknown) { const json = JSON.stringify(document) const payload = utf8ToBytes(json) + console.debug('storeDocument', { encoder, document }) + const sendResult = await waku.lightPush.send(encoder, { payload }) if (sendResult.errors && sendResult.errors.length > 0) { return sendResult.errors @@ -120,30 +107,12 @@ export async function storeDocument( export async function readStore( waku: LightNode, - contentTopic: ContentTopic, - symKey: Uint8Array, + decoder: IDecoder, storeQueryOptions?: StoreQueryOptions, ): Promise { - const topicKey = hash(symKey) - const topic = getTopic(contentTopic, topicKey) - const decoder = createDecoder(topic, symKey) - return waku.store.queryGenerator([decoder], storeQueryOptions) } export function decodeMessagePayload(wakuMessage: DecodedMessage): string { return bytesToUtf8(wakuMessage.payload) } - -export async function sendMessage(waku: LightNode, symKey: Uint8Array, message: unknown) { - const json = JSON.stringify(message) - const payload = utf8ToBytes(json) - const topicKey = hash(symKey) - const contentTopic = getTopic('private-message', topicKey) - const encoder = createEncoder({ contentTopic, symKey }) - - const sendResult = await waku.lightPush.send(encoder, { payload }) - if (sendResult.errors && sendResult.errors.length > 0) { - return sendResult.errors - } -} diff --git a/src/lib/adapters/waku/wakustore.ts b/src/lib/adapters/waku/wakustore.ts index 32d8a25d..0493dc27 100644 --- a/src/lib/adapters/waku/wakustore.ts +++ b/src/lib/adapters/waku/wakustore.ts @@ -1,74 +1,58 @@ -import type { DecodedMessage, SendError } from '@waku/sdk' +import type { IDecoder, IEncoder, SendError } from '@waku/sdk' import { decodeMessagePayload, readStore, storeDocument, subscribe } from './waku' -import type { ContentTopic, QueryResult } from './waku' +import type { QueryResult } from './waku' import { PageDirection, type LightNode, type StoreQueryOptions, type Unsubscribe, } from '@waku/interfaces' +import type { DecodedMessage } from '@waku/message-encryption' interface QueryOptions extends StoreQueryOptions { limit?: number } interface Query { - contentTopic: ContentTopic - symKey: Uint8Array + decoder: IDecoder queryOptions?: QueryOptions } export interface Wakustore { readonly waku: LightNode - docQuery: (contentTopic: ContentTopic, symKey: Uint8Array, queryOptions?: QueryOptions) => Query - collectionQuery: ( - contentTopic: ContentTopic, - symKey: Uint8Array, - queryOptions?: QueryOptions, - ) => Query - onSnapshot: (query: Query, callback: (value: T) => void) => Promise - getDoc: (contentTopic: ContentTopic, symKey: Uint8Array) => Promise - setDoc: ( - contentTopic: ContentTopic, - symKey: Uint8Array, - data: T, - ) => Promise + docQuery: (decoder: IDecoder, queryOptions?: QueryOptions) => Query + collectionQuery: (decoder: IDecoder, queryOptions?: QueryOptions) => Query + onSnapshot: ( + query: Query, + callback: (value: T, decodedMessage: DecodedMessage) => void, + ) => Promise + getDoc: (decoder: IDecoder) => Promise + setDoc: (encoder: IEncoder, data: T) => Promise + getDecodedMessage: (decoder: IDecoder) => Promise + decodeDoc: (decodedMessage: DecodedMessage) => Promise } -export function makeWakustore(waku: LightNode) { - function makeQuery( - contentTopic: ContentTopic, - symKey: Uint8Array, - queryOptions?: QueryOptions, - ): Query { +export function makeWakustore(waku: LightNode): Wakustore { + function makeQuery(decoder: IDecoder, queryOptions?: QueryOptions): Query { return { - contentTopic, - symKey, + decoder, queryOptions, } } - function docQuery( - contentTopic: ContentTopic, - symKey: Uint8Array, - queryOptions?: QueryOptions, - ): Query { - return makeQuery(contentTopic, symKey, { + function docQuery(decoder: IDecoder, queryOptions?: QueryOptions): Query { + return makeQuery(decoder, { pageDirection: PageDirection.BACKWARD, limit: 1, ...queryOptions, }) } - function collectionQuery( - contentTopic: ContentTopic, - symKey: Uint8Array, - queryOptions?: QueryOptions, - ): Query { - return makeQuery(contentTopic, symKey, queryOptions) + function collectionQuery(decoder: IDecoder, queryOptions?: QueryOptions): Query { + return makeQuery(decoder, queryOptions) } - function decodedMessageToTypedResult(message: DecodedMessage): T { + function decodeDoc(message: DecodedMessage): T { const decodedPayload = decodeMessagePayload(message) const typedPayload = JSON.parse(decodedPayload) as T & { timestamp?: number } @@ -89,70 +73,79 @@ export function makeWakustore(waku: LightNode) { } } - async function parseQueryResults( + async function getQueryResults( results: QueryResult, queryOptions?: QueryOptions, - ): Promise { - const typedResults: T[] = [] + ): Promise { + const decodedMessages: DecodedMessage[] = [] for await (const messagePromises of results) { for (const messagePromise of messagePromises) { const message = await messagePromise if (message) { - const typedResult = decodedMessageToTypedResult(message) - typedResults.push(typedResult) + decodedMessages.push(message) // reached the limit if ( Number.isInteger(queryOptions?.limit) && - typedResults.length === queryOptions?.limit + decodedMessages.length === queryOptions?.limit ) { - return typedResults + return decodedMessages } } } } - return typedResults + return decodedMessages } - async function getDoc(contentTopic: ContentTopic, symKey: Uint8Array): Promise { - const query = docQuery(contentTopic, symKey) + async function getDecodedMessage( + decoder: IDecoder, + ): Promise { + const query = docQuery(decoder) const queryOptions = { ...query.queryOptions, pageSize: query.queryOptions?.pageSize ?? query.queryOptions?.limit, } - const result = await readStore(waku, query.contentTopic, query.symKey, queryOptions) - const values = await parseQueryResults(result, queryOptions) + const result = await readStore(waku, query.decoder, queryOptions) + const values = await getQueryResults(result, queryOptions) if (values.length === 1) { return values[0] } } - async function setDoc(contentTopic: ContentTopic, symKey: Uint8Array, data: T) { - return await storeDocument(waku, contentTopic, symKey, data) + async function getDoc(decoder: IDecoder): Promise { + const decodedMessage = await getDecodedMessage(decoder) + if (!decodedMessage) { + return + } + + return decodeDoc(decodedMessage) + } + + async function setDoc(encoder: IEncoder, data: T) { + return await storeDocument(waku, encoder, data) } - async function onSnapshot(query: Query, callback: (value: T) => void): Promise { - const subscription = await subscribe( - waku, - query.contentTopic, - query.symKey, - (msg: DecodedMessage) => { - const typedResult = decodedMessageToTypedResult(msg) - callback(typedResult) - }, - ) + async function onSnapshot( + query: Query, + callback: (value: T, decodedMessage: DecodedMessage) => void, + ): Promise { + const subscription = await subscribe(waku, query.decoder, (msg: DecodedMessage) => { + const typedResult = decodeDoc(msg) + callback(typedResult, msg) + }) const queryOptions = { ...query.queryOptions, pageSize: query.queryOptions?.pageSize ?? query.queryOptions?.limit, } - const result = await readStore(waku, query.contentTopic, query.symKey, queryOptions) - const values = await parseQueryResults(result, queryOptions) + const result = await readStore(waku, query.decoder, queryOptions) + const messages = await getQueryResults(result, queryOptions) - for (const value of values) { - callback(value) + for (const message of messages) { + const value = decodeDoc(message) + callback(value, message) } return subscription @@ -165,5 +158,7 @@ export function makeWakustore(waku: LightNode) { onSnapshot, getDoc, setDoc, + getDecodedMessage, + decodeDoc, } } diff --git a/src/routes/invite/[address]/+page.svelte b/src/routes/invite/[address]/+page.svelte index 15084d09..1f4e2249 100644 --- a/src/routes/invite/[address]/+page.svelte +++ b/src/routes/invite/[address]/+page.svelte @@ -65,7 +65,7 @@ errorStore.addEnd({ title: 'Connection error', ok: true, - message: `Failed to load user profile. Datails: ${(error as Error)?.message}`, + message: `Failed to load user profile. Details: ${(error as Error)?.message}`, retry: () => tryLoadCounterPartyProfile(), }) } From 061a4561d4b3d770e0b6bf4c7d59d00ecaaef7e0 Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:10:29 +0100 Subject: [PATCH 02/10] wip: signatures --- src/cli/cli.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 863c9708..aa57c570 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -71,9 +71,7 @@ async function waku() { const command = process.argv[3] const restArgs = process.argv.slice(4) - const commands: Record Promise> = { - doc, - } + const commands: Record Promise> = {} const fn = commands[command] if (!fn) { From d3bbf26c4734c791fefbca94f577099ccfbbe4f7 Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:13:06 +0100 Subject: [PATCH 03/10] feat: encryption with signatures --- src/lib/adapters/waku/codec.ts | 33 ++++++++++++++++++++ src/lib/adapters/waku/crypto.ts | 6 ---- src/lib/adapters/waku/index.ts | 21 ++++++------- src/routes/group/chat/[id]/edit/+page.svelte | 12 ++++--- 4 files changed, 51 insertions(+), 21 deletions(-) create mode 100644 src/lib/adapters/waku/codec.ts diff --git a/src/lib/adapters/waku/codec.ts b/src/lib/adapters/waku/codec.ts new file mode 100644 index 00000000..a5a385d7 --- /dev/null +++ b/src/lib/adapters/waku/codec.ts @@ -0,0 +1,33 @@ +import { + createEncoder as createWakuSymmetricEncoder, + createDecoder as createWakuSymmetricDecoder, +} from '@waku/message-encryption/symmetric' +import { getTopic, type ContentTopic } from './waku' +import { bytesToHex, hexToBytes } from '@waku/utils/bytes' +import { type Hex, fixHex } from './crypto' + +function toHex(value: Uint8Array | Hex): Hex { + return typeof value === 'string' ? fixHex(value) : bytesToHex(value) +} + +export function createSymmetricEncoder(options: { + contentTopic: ContentTopic + symKey: Uint8Array | Hex + sigPrivKey?: Uint8Array | Hex +}) { + const contentTopic = getTopic(options.contentTopic, toHex(options.symKey)) + return createWakuSymmetricEncoder({ + ...options, + contentTopic, + symKey: hexToBytes(options.symKey), + sigPrivKey: options.sigPrivKey ? hexToBytes(options.sigPrivKey) : undefined, + }) +} + +export function createSymmetricDecoder(options: { + contentTopic: ContentTopic + symKey: Uint8Array | Hex +}) { + const contentTopic = getTopic(options.contentTopic, toHex(options.symKey)) + return createWakuSymmetricDecoder(contentTopic, hexToBytes(options.symKey)) +} diff --git a/src/lib/adapters/waku/crypto.ts b/src/lib/adapters/waku/crypto.ts index f38c923e..d84c3dab 100644 --- a/src/lib/adapters/waku/crypto.ts +++ b/src/lib/adapters/waku/crypto.ts @@ -69,9 +69,3 @@ export function sign(privateKey: Hex, data: Uint8Array): Hex { const signature = nobleSign(messageHash, fixHex(privateKey)) return signature.toCompactHex() } - -export function privateKeyToPublicKey(privateKey: Hex | Uint8Array): Hex { - const privateKeyHex = typeof privateKey === 'string' ? fixHex(privateKey) : bytesToHex(privateKey) - const publicKeyBytes = getPublicKey(privateKeyHex) - return bytesToHex(publicKeyBytes) -} diff --git a/src/lib/adapters/waku/index.ts b/src/lib/adapters/waku/index.ts index 53240fcf..4129b786 100644 --- a/src/lib/adapters/waku/index.ts +++ b/src/lib/adapters/waku/index.ts @@ -50,12 +50,7 @@ import { errorStore } from '$lib/stores/error' import { compressPublicKey, fixHex, getSharedSecret, hash } from './crypto' import { bytesToHex, hexToBytes } from '@waku/utils/bytes' import { encrypt, decrypt } from './crypto' -import { - createEciesDecoder, - createEciesEncoder, - createSymmetricDecoder, - createSymmetricEncoder, -} from './codec' +import { createSymmetricDecoder, createSymmetricEncoder } from './codec' import type { DecodedMessage } from '@waku/message-encryption' const MAX_MESSAGES = 100 @@ -286,11 +281,16 @@ export default class WakuAdapter implements Adapter { chats.update((state) => ({ ...state, chats: new Map(storageChatEntries), loading: false })) // subscribe to invites - const decoder = createEciesDecoder({ contentTopic: 'invites', privateKey: ownPrivateKey }) + const decoder = createSymmetricDecoder({ + contentTopic: 'invites', + symKey: ownPublicEncryptionKey, + }) await this.safeWaku.subscribeEncrypted( ownPublicKey, decoder, async (message, decodedMessage) => { + console.debug('invite', { message, decodedMessage }) + if (!this.checkMessageSignature(message, decodedMessage)) { return } @@ -456,12 +456,11 @@ export default class WakuAdapter implements Adapter { chatId: ownPublicKey, } - // const inviteEncryptionKey = hexToBytes(hash(peerPublicKey)) - // await this.safeWaku.sendMessage(inviteMessage, inviteEncryptionKey, hexToBytes(ownPrivateKey)) + const inviteEncryptionKey = hexToBytes(hash(peerPublicKey)) const ws = await this.makeWakustore() - const encoder = createEciesEncoder({ + const encoder = createSymmetricEncoder({ contentTopic: 'invites', - publicKey: peerPublicKey, + symKey: inviteEncryptionKey, sigPrivKey: ownPrivateKey, }) await ws.setDoc(encoder, inviteMessage) diff --git a/src/routes/group/chat/[id]/edit/+page.svelte b/src/routes/group/chat/[id]/edit/+page.svelte index b86b06a2..92c18985 100644 --- a/src/routes/group/chat/[id]/edit/+page.svelte +++ b/src/routes/group/chat/[id]/edit/+page.svelte @@ -33,6 +33,8 @@ import { userDisplayName } from '$lib/utils/user' import { errorStore } from '$lib/stores/error' + $: console.log($chats) + $: chatId = $page.params.id $: groupChat = $chats.chats.get(chatId) let picture: string | undefined @@ -185,9 +187,11 @@
    {#each groupMembers as user} - {@const isContact = Array.from($chats.chats) - .map(([, chat]) => chat.chatId) - .includes(user.publicKey)} + {@const contactChat = Array.from($chats.chats) + .filter(([, chat]) => chat.type === 'private') + .map(([, chat]) => chat) + .find((chat) => chat.users.map((user) => user.publicKey).includes(user.publicKey))} + {@const isContact = !!contactChat} {@const isMe = user.publicKey === wallet.signingKey.compressedPublicKey}
  • @@ -210,7 +214,7 @@ {:else if isContact} - {/if} From 19d5c5528630e3cc83bd0a6e1e120df551f15c7d Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:14:19 +0100 Subject: [PATCH 04/10] fix: remove unused function --- src/lib/adapters/waku/crypto.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/adapters/waku/crypto.ts b/src/lib/adapters/waku/crypto.ts index d84c3dab..9aa23074 100644 --- a/src/lib/adapters/waku/crypto.ts +++ b/src/lib/adapters/waku/crypto.ts @@ -3,7 +3,6 @@ import { sign as nobleSign, ProjectivePoint, Signature, - getPublicKey, } from '@noble/secp256k1' import { keccak_256 } from '@noble/hashes/sha3' import { bytesToHex, hexToBytes } from '@waku/utils/bytes' @@ -68,4 +67,5 @@ export function sign(privateKey: Hex, data: Uint8Array): Hex { const messageHash = hash(data) const signature = nobleSign(messageHash, fixHex(privateKey)) return signature.toCompactHex() -} + +} \ No newline at end of file From 2d5d8b0e19b363304bba81ba8d6a023d4cb146f9 Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:15:01 +0100 Subject: [PATCH 05/10] fix: formatting --- src/lib/adapters/waku/crypto.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/adapters/waku/crypto.ts b/src/lib/adapters/waku/crypto.ts index 9aa23074..a068a1b4 100644 --- a/src/lib/adapters/waku/crypto.ts +++ b/src/lib/adapters/waku/crypto.ts @@ -67,5 +67,4 @@ export function sign(privateKey: Hex, data: Uint8Array): Hex { const messageHash = hash(data) const signature = nobleSign(messageHash, fixHex(privateKey)) return signature.toCompactHex() - -} \ No newline at end of file +} From 98812381066e138177c2fd9ea878a7e8176294be Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:40:29 +0100 Subject: [PATCH 06/10] fix: remove unused crypto code --- src/lib/adapters/waku/crypto.test.ts | 17 ++--------------- src/lib/adapters/waku/crypto.ts | 11 ----------- src/lib/adapters/waku/waku.ts | 2 +- 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/lib/adapters/waku/crypto.test.ts b/src/lib/adapters/waku/crypto.test.ts index 1534750f..82c21635 100644 --- a/src/lib/adapters/waku/crypto.test.ts +++ b/src/lib/adapters/waku/crypto.test.ts @@ -1,11 +1,11 @@ import { describe, it, expect } from 'vitest' -import { hash, publicKeyToAddress, sign, signatureToPublicKey } from './crypto' +import { publicKeyToAddress } from './crypto' const testPrivateKey = 'd195918969e09d9394c768e25b621eafc4c360117a9e1eebb0a68bfd53119ba4' const testCompressedPublicKey = '0374a6b1cea74a7a755396d8c62a3be4eb9098c7bb286dcdfc02ab93e7683c93f9' const testUncompressedPublicKey = '0474a6b1cea74a7a755396d8c62a3be4eb9098c7bb286dcdfc02ab93e7683c93f99515f1cf8980e0cb25b6078113813d90d99303aaea1aa34c12805f8355768e21' -const testAddress = publicKeyToAddress(testUncompressedPublicKey) +const testAddress = '0x5018604b6fcfb992e48c102dcff8f9084a68b751' describe('publicKeyToAddress', () => { it('calculates correct address for compressed public key', () => { @@ -18,16 +18,3 @@ describe('publicKeyToAddress', () => { expect(address).toEqual(testAddress) }) }) - -describe('sign', () => { - it('calculates signature', () => { - const message = 'hello' - - const data = new TextEncoder().encode(message) - const signature = sign(testPrivateKey, data) - const messageHash = hash(data) - const recoveredPublicKey = signatureToPublicKey(signature, messageHash) - - expect(recoveredPublicKey).toEqual(testCompressedPublicKey) - }) -}) diff --git a/src/lib/adapters/waku/crypto.ts b/src/lib/adapters/waku/crypto.ts index a068a1b4..7c466e7c 100644 --- a/src/lib/adapters/waku/crypto.ts +++ b/src/lib/adapters/waku/crypto.ts @@ -57,14 +57,3 @@ export function compressPublicKey(publicKey: Hex | Uint8Array): Hex { publicKey = typeof publicKey === 'string' ? fixHex(publicKey) : bytesToHex(publicKey) return ProjectivePoint.fromHex(publicKey).toHex(true) } - -export function signatureToPublicKey(signature: Hex, messageHash: Hex): Hex { - const publicKey = Signature.fromCompact(fixHex(signature)).recoverPublicKey(fixHex(messageHash)) - return publicKey.toHex(true) -} - -export function sign(privateKey: Hex, data: Uint8Array): Hex { - const messageHash = hash(data) - const signature = nobleSign(messageHash, fixHex(privateKey)) - return signature.toCompactHex() -} diff --git a/src/lib/adapters/waku/waku.ts b/src/lib/adapters/waku/waku.ts index ecb6893d..b9de168a 100644 --- a/src/lib/adapters/waku/waku.ts +++ b/src/lib/adapters/waku/waku.ts @@ -43,7 +43,7 @@ export type ContentTopic = export type QueryResult = AsyncGenerator[]> -function getTopic(contentTopic: ContentTopic, id: string | '' = '') { +export function getTopic(contentTopic: ContentTopic, id: string | '' = '') { const topicApp = 'wakuplay.im' const topicVersion = '1' const topicEncoding = 'json' From a26b93fcad0bf1fd51f4dec77b4daa37f592651f Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:41:01 +0100 Subject: [PATCH 07/10] fix: remove unused crypto code --- src/lib/adapters/waku/crypto.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/adapters/waku/crypto.test.ts b/src/lib/adapters/waku/crypto.test.ts index 82c21635..0ddc7791 100644 --- a/src/lib/adapters/waku/crypto.test.ts +++ b/src/lib/adapters/waku/crypto.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect } from 'vitest' import { publicKeyToAddress } from './crypto' -const testPrivateKey = 'd195918969e09d9394c768e25b621eafc4c360117a9e1eebb0a68bfd53119ba4' +// const testPrivateKey = 'd195918969e09d9394c768e25b621eafc4c360117a9e1eebb0a68bfd53119ba4' const testCompressedPublicKey = '0374a6b1cea74a7a755396d8c62a3be4eb9098c7bb286dcdfc02ab93e7683c93f9' const testUncompressedPublicKey = '0474a6b1cea74a7a755396d8c62a3be4eb9098c7bb286dcdfc02ab93e7683c93f99515f1cf8980e0cb25b6078113813d90d99303aaea1aa34c12805f8355768e21' From c1eff7269ad5ace94cbe1af5ececca1a9e20124b Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:43:48 +0100 Subject: [PATCH 08/10] fix: remove unused waku cli command --- src/cli/cli.ts | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/cli/cli.ts b/src/cli/cli.ts index aa57c570..af960a56 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -18,7 +18,6 @@ async function main() { fund, balance, txinfo, - waku, } const fn = commands[command] @@ -67,20 +66,4 @@ async function txinfo(hash: string) { console.log({ tx, receipt }) } -async function waku() { - const command = process.argv[3] - const restArgs = process.argv.slice(4) - - const commands: Record Promise> = {} - - const fn = commands[command] - if (!fn) { - throw `unknown command: ${command}\nUsage: cli waku ${Object.keys(commands).join('|')}` - } - - await fn(...restArgs) - - process.exit(0) -} - main().catch(console.error) From b958c6d35ba3b962a3e3f5db970df50ca4129768 Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:48:31 +0100 Subject: [PATCH 09/10] fix: remove unused imports --- src/lib/adapters/waku/crypto.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/lib/adapters/waku/crypto.ts b/src/lib/adapters/waku/crypto.ts index 7c466e7c..24268e77 100644 --- a/src/lib/adapters/waku/crypto.ts +++ b/src/lib/adapters/waku/crypto.ts @@ -1,9 +1,4 @@ -import { - getSharedSecret as nobleGetSharedSecret, - sign as nobleSign, - ProjectivePoint, - Signature, -} from '@noble/secp256k1' +import { getSharedSecret as nobleGetSharedSecret, ProjectivePoint } from '@noble/secp256k1' import { keccak_256 } from '@noble/hashes/sha3' import { bytesToHex, hexToBytes } from '@waku/utils/bytes' import { gcm } from '@noble/ciphers/aes' From 514f8ed0922df2348124e603729ee8024785d8aa Mon Sep 17 00:00:00 2001 From: Attila Gazso <230163+agazso@users.noreply.github.com> Date: Thu, 9 Nov 2023 17:52:59 +0100 Subject: [PATCH 10/10] fix: remove console.debug --- src/lib/adapters/waku/index.ts | 6 ------ src/lib/adapters/waku/waku.ts | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/lib/adapters/waku/index.ts b/src/lib/adapters/waku/index.ts index 4129b786..94c24afa 100644 --- a/src/lib/adapters/waku/index.ts +++ b/src/lib/adapters/waku/index.ts @@ -289,8 +289,6 @@ export default class WakuAdapter implements Adapter { ownPublicKey, decoder, async (message, decodedMessage) => { - console.debug('invite', { message, decodedMessage }) - if (!this.checkMessageSignature(message, decodedMessage)) { return } @@ -749,8 +747,6 @@ export default class WakuAdapter implements Adapter { const storageProfile = await ws.decodeDoc(decodedMessage) - console.debug({ storageProfile, profilePublicKey, decoder }) - return storageProfile } @@ -812,7 +808,6 @@ export default class WakuAdapter implements Adapter { symKey: groupEncryptionKey, }) const groupChat = await ws.getDoc(decoder) - console.debug({ groupChat, groupChatId }) if (groupChat) { const updatedGroupChat = await this.storageChatToChat(groupChatId, groupChat) chats.updateChat(groupChatId, (chat) => ({ @@ -946,7 +941,6 @@ export default class WakuAdapter implements Adapter { private checkMessageSignature(message: Message, decodedMessage: DecodedMessage): boolean { if (!decodedMessage.signaturePublicKey) { - console.debug('missing signature') return false } diff --git a/src/lib/adapters/waku/waku.ts b/src/lib/adapters/waku/waku.ts index b9de168a..19c93198 100644 --- a/src/lib/adapters/waku/waku.ts +++ b/src/lib/adapters/waku/waku.ts @@ -97,8 +97,6 @@ export async function storeDocument(waku: LightNode, encoder: IEncoder, document const json = JSON.stringify(document) const payload = utf8ToBytes(json) - console.debug('storeDocument', { encoder, document }) - const sendResult = await waku.lightPush.send(encoder, { payload }) if (sendResult.errors && sendResult.errors.length > 0) { return sendResult.errors