aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-02-26 16:07:52 -0800
committerAdam Soltys <[email protected]>2026-02-26 16:07:52 -0800
commit18df062a099811355cafc2024e30a7c2b68c7984 (patch)
tree1de4c341b3111f7ccc6c0e74824b2bc6115d3401 /src/lib
parent2a59047dc8fc10560a7fde614238ee821cfb6b1b (diff)
downloadcoinos-ui-18df062a099811355cafc2024e30a7c2b68c7984.tar.gz
coinos-ui-18df062a099811355cafc2024e30a7c2b68c7984.zip
client side password auth
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/deriveAuthKey.ts23
-rw-r--r--src/lib/utils.ts12
2 files changed, 35 insertions, 0 deletions
diff --git a/src/lib/deriveAuthKey.ts b/src/lib/deriveAuthKey.ts
new file mode 100644
index 00000000..9215b515
--- /dev/null
+++ b/src/lib/deriveAuthKey.ts
@@ -0,0 +1,23 @@
+import { scryptAsync } from "@noble/hashes/scrypt.js";
+import { bytesToHex } from "@noble/hashes/utils.js";
+import { getPublicKey } from "nostr-tools";
+import { rememberPrfKey, defaultRememberForMs } from "$lib/passwordCache";
+
+export async function deriveAuthKeypair(username: string, password: string) {
+ const salt = `coinos:auth:${username.toLowerCase().replace(/\s/g, "")}`;
+ const sk = await scryptAsync(password, salt, { N: 2 ** 16, r: 8, p: 1, dkLen: 32 });
+ const pubkey = getPublicKey(sk);
+ return { sk, pubkey, skHex: bytesToHex(sk) };
+}
+
+export async function deriveWalletEntropy(sk: Uint8Array): Promise<ArrayBuffer> {
+ const { finalizeEvent } = await import("nostr-tools");
+ const event = { kind: 1, created_at: 0, content: "coinos-wallet-key-derivation", tags: [] };
+ const signed = finalizeEvent(event as any, sk);
+ const sigBytes = new Uint8Array(signed.sig.length / 2);
+ for (let i = 0; i < signed.sig.length; i += 2)
+ sigBytes[i / 2] = parseInt(signed.sig.slice(i, i + 2), 16);
+ const entropy = await crypto.subtle.digest("SHA-256", sigBytes);
+ rememberPrfKey(entropy, defaultRememberForMs);
+ return entropy;
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 4bf96d6e..eee6903e 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -164,6 +164,7 @@ export const login = async (
token?: string;
challenge?: string;
recaptcha?: string;
+ authPubkey?: string;
},
cookies,
ip: string,
@@ -509,6 +510,17 @@ export const register = async (
};
if (ip) headers["cf-connecting-ip"] = ip;
+ // Derive authPubkey if password provided
+ if (user.password && user.username) {
+ try {
+ const { deriveAuthKeypair } = await import("$lib/deriveAuthKey");
+ const { pubkey: authPubkey } = await deriveAuthKeypair(user.username, user.password);
+ user.authPubkey = authPubkey;
+ } catch (e) {
+ console.log("Failed to derive authPubkey during registration", e);
+ }
+ }
+
let sk, token;
try {
({ sk, token } = await post("/register", { user }, headers));