diff --git a/frontend/src/auth/crypto.ts b/frontend/src/auth/crypto.ts index f8e30e4..1e16ff1 100644 --- a/frontend/src/auth/crypto.ts +++ b/frontend/src/auth/crypto.ts @@ -65,6 +65,17 @@ export function getCurrentKeys(): UserKeyPairMemory | null { return null; } +function saveKeys( + publicKey: Uint8Array, + privateKey: Uint8Array +) { + const encodedPublicKey = b64(publicKey); + const encodedPrivateKey = b64(privateKey); + + localStorage.setItem("publicKey", encodedPublicKey); + localStorage.setItem("privateKey", encodedPrivateKey); +} + export async function ensureKeysOnLogin(password: string, token: string): Promise { // Try to restore from backup const blobJson = await fetchBackupBlob(token); @@ -86,7 +97,13 @@ export async function ensureKeysOnLogin(password: string, token: string): Promis const newBlob = await encryptBackupWithPassword(password, { version: 1, privateKey: currentPrivateKey }); await uploadBackupBlob(encodeBlob(newBlob), token); } - return { publicKey: currentPublicKey!, privateKey: currentPrivateKey! }; + + saveKeys(currentPublicKey!, currentPrivateKey!); + + return { + publicKey: currentPublicKey!, + privateKey: currentPrivateKey! + }; } // First-time setup: generate keys and upload @@ -96,5 +113,13 @@ export async function ensureKeysOnLogin(password: string, token: string): Promis await uploadPublicKey(currentPublicKey, token); const encBlob = await encryptBackupWithPassword(password, { version: 1, privateKey: currentPrivateKey }); await uploadBackupBlob(encodeBlob(encBlob), token); - return { publicKey: currentPublicKey, privateKey: currentPrivateKey }; + + saveKeys(pair.publicKey, pair.privateKey); + + return pair; +} + +export function restoreKeys() { + currentPublicKey = ub64(localStorage.getItem("publicKey")!); + currentPrivateKey = ub64(localStorage.getItem("privateKey")!); } \ No newline at end of file diff --git a/frontend/src/ui/state.ts b/frontend/src/ui/state.ts index 3f1bada..2150b7d 100644 --- a/frontend/src/ui/state.ts +++ b/frontend/src/ui/state.ts @@ -5,6 +5,7 @@ import { MessagePanel } from "./panels/MessagePanel"; import { PublicChatPanel } from "./panels/PublicChatPanel"; import { DMPanel, type DMPanelData } from "./panels/DMPanel"; import { getAuthHeaders } from "../auth/api"; +import { restoreKeys } from "../auth/crypto"; type Page = "login" | "register" | "chat" export type ChatTabs = "chats" | "channels" | "contacts" | "dms" @@ -202,6 +203,8 @@ export const useAppState = create((set, get) => ({ headers: getAuthHeaders(token) })).json(); + restoreKeys(); + set(() => ({ user: { currentUser: user, diff --git a/frontend/src/utils/crypto/asymmetric.ts b/frontend/src/utils/crypto/asymmetric.ts index a086efa..09b8dfa 100644 --- a/frontend/src/utils/crypto/asymmetric.ts +++ b/frontend/src/utils/crypto/asymmetric.ts @@ -6,6 +6,8 @@ export interface X25519KeyPair { privateKey: Uint8Array; } +export type KeyPair = X25519KeyPair; + export function generateX25519KeyPair(): X25519KeyPair { const kp = nacl.box.keyPair(); return { publicKey: kp.publicKey, privateKey: kp.secretKey };