diff --git a/packages/murmur-cli/src/cli.ts b/packages/murmur-cli/src/cli.ts index 4316cb7..3964651 100644 --- a/packages/murmur-cli/src/cli.ts +++ b/packages/murmur-cli/src/cli.ts @@ -367,6 +367,7 @@ function printUsage(): void { const lines = [ 'Usage:', ' murmur sign-in [--first-name ] [--last-name ]', + ' murmur update-profile --first-name [--last-name ]', ' murmur me', ' murmur delete-account --confirm', ' murmur contacts', @@ -519,6 +520,7 @@ type WebhookContext = { senderId: string senderIdentityKey: string senderName: string + text: string receivedAt: number hasAttachments: boolean } @@ -594,6 +596,7 @@ async function emitWebhook( senderId: formatWebhookSenderId(contact, message.conversationId), senderIdentityKey: message.conversationId, senderName: formatName(contact?.firstName, contact?.lastName, 'Unknown'), + text: message.text, receivedAt: message.createdAt, hasAttachments: Boolean(message.attachments && message.attachments.length > 0) } @@ -698,6 +701,14 @@ async function run(): Promise { console.log(JSON.stringify(profile, null, 2)) return } + case 'update-profile': { + await requireInitialized(getEngine()) + const firstName = requireStringOption(parsed.options, 'first-name', 'MURMUR_FIRST_NAME') + const lastName = readStringOption(parsed.options, 'last-name', 'MURMUR_LAST_NAME') + const account = await getEngine().updateProfile(firstName, lastName) + printAccountSummary('Profile updated.', account) + return + } case 'delete-account': { await requireInitialized(getEngine()) const confirmed = readBooleanOption(parsed.options, 'confirm', 'MURMUR_CONFIRM_DELETE') diff --git a/packages/murmur-cli/src/engine/engine.ts b/packages/murmur-cli/src/engine/engine.ts index 26c7325..866b4ee 100644 --- a/packages/murmur-cli/src/engine/engine.ts +++ b/packages/murmur-cli/src/engine/engine.ts @@ -47,6 +47,7 @@ import { decryptProfile, createProfileForRegistration, verifyProfileKeySignature, + signProfileKey, type Profile } from './profile.js' import { publicKeyFromPrivate } from '../encryption/crypto/dh.js' @@ -521,6 +522,45 @@ export class MurmurEngine { return this.account } + /** + * Update the current account's profile (firstName, lastName). + */ + async updateProfile(firstName: string, lastName?: string): Promise { + if (!this.agent || !this.account) { + throw new Error('Not initialized') + } + + // Create new encrypted profile + const profile: Profile = { firstName, lastName } + const profileSecretKeyBytes = decodeBase64(this.account.profileSecretKey, 'base64url') + const profilePublicKeyBytes = decodeBase64(this.account.profilePublicKey) + const encryptedProfile = encryptProfile(profile, profileSecretKeyBytes) + const profileKeySignature = signProfileKey( + profilePublicKeyBytes, + this.agent.keyStore.identityKeyPair.privateKey + ) + + // Upload to server + await this.api.updateProfile( + this.account.profilePublicKey, + profileKeySignature, + encryptedProfile + ) + + // Update local account + this.account = { + ...this.account, + firstName, + lastName, + encryptedProfile + } + + // Save to database + this.db.saveAccount(this.account) + + return this.account + } + /** * Delete the current account and local data. */