mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-06 12:52:26 +00:00
Refactor NIP-07 helpers and session actor storage
This commit is contained in:
1 parent
35ac62be15
commit
3382185512
6 files changed
+935
-659
No files matched your search
@@ -0,0 +1,76 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
readStoredNip07Permissions,
|
||||
writeStoredNip07Permissions,
|
||||
clearStoredNip07Permissions,
|
||||
requestEnablePermissions,
|
||||
} from "../../js/nostr/nip07Permissions.js";
|
||||
|
||||
test("writeStoredNip07Permissions normalizes and persists granted methods", () => {
|
||||
clearStoredNip07Permissions();
|
||||
|
||||
writeStoredNip07Permissions([" get_public_key ", "", "sign_event"]);
|
||||
|
||||
const stored = readStoredNip07Permissions();
|
||||
assert.ok(stored instanceof Set);
|
||||
|
||||
const sorted = [...stored].sort();
|
||||
assert.deepStrictEqual(sorted, ["get_public_key", "sign_event"]);
|
||||
});
|
||||
|
||||
test("clearStoredNip07Permissions removes persisted grants", () => {
|
||||
clearStoredNip07Permissions();
|
||||
writeStoredNip07Permissions(["get_public_key"]);
|
||||
assert.notStrictEqual(
|
||||
globalThis.localStorage.getItem("bitvid:nip07:permissions"),
|
||||
null,
|
||||
);
|
||||
|
||||
clearStoredNip07Permissions();
|
||||
|
||||
const afterClear = readStoredNip07Permissions();
|
||||
assert.strictEqual(afterClear.size, 0);
|
||||
assert.strictEqual(
|
||||
globalThis.localStorage.getItem("bitvid:nip07:permissions"),
|
||||
null,
|
||||
);
|
||||
});
|
||||
|
||||
test("requestEnablePermissions retries explicit and fallback variants", async () => {
|
||||
clearStoredNip07Permissions();
|
||||
const calls = [];
|
||||
let attempt = 0;
|
||||
|
||||
const extension = {
|
||||
enable: (options) => {
|
||||
calls.push(options);
|
||||
attempt += 1;
|
||||
if (attempt < 3) {
|
||||
return Promise.reject(new Error(`attempt-${attempt}`));
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
};
|
||||
|
||||
const result = await requestEnablePermissions(
|
||||
extension,
|
||||
["sign_event"],
|
||||
{ isDevMode: false },
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(calls, [
|
||||
{ permissions: [{ method: "sign_event" }] },
|
||||
{ permissions: ["sign_event"] },
|
||||
undefined,
|
||||
]);
|
||||
assert.deepStrictEqual(result, { ok: true });
|
||||
});
|
||||
|
||||
test("requestEnablePermissions reports unavailable extension", async () => {
|
||||
clearStoredNip07Permissions();
|
||||
const result = await requestEnablePermissions(null, ["sign_event"]);
|
||||
assert.strictEqual(result.ok, false);
|
||||
assert.strictEqual(result.error?.message, "extension-unavailable");
|
||||
});
|
||||
@@ -0,0 +1,122 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { webcrypto } from "node:crypto";
|
||||
|
||||
const originalCrypto = globalThis.crypto;
|
||||
if (originalCrypto === undefined) {
|
||||
Object.defineProperty(globalThis, "crypto", {
|
||||
value: webcrypto,
|
||||
configurable: true,
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
});
|
||||
}
|
||||
|
||||
import {
|
||||
encryptSessionPrivateKey,
|
||||
decryptSessionPrivateKey,
|
||||
persistSessionActor,
|
||||
readStoredSessionActorEntry,
|
||||
clearStoredSessionActor,
|
||||
SESSION_ACTOR_STORAGE_KEY,
|
||||
} from "../../js/nostr/sessionActor.js";
|
||||
|
||||
test.after(() => {
|
||||
clearStoredSessionActor();
|
||||
if (originalCrypto === undefined) {
|
||||
delete globalThis.crypto;
|
||||
}
|
||||
});
|
||||
|
||||
test("encryptSessionPrivateKey + decryptSessionPrivateKey roundtrip", async () => {
|
||||
clearStoredSessionActor();
|
||||
const privateKey = "a".repeat(64);
|
||||
const passphrase = "correct horse";
|
||||
|
||||
const encrypted = await encryptSessionPrivateKey(privateKey, passphrase);
|
||||
assert.match(encrypted.ciphertext, /.+/);
|
||||
assert.ok(encrypted.salt.length > 0);
|
||||
assert.ok(encrypted.iv.length > 0);
|
||||
|
||||
const decrypted = await decryptSessionPrivateKey(
|
||||
{
|
||||
privateKeyEncrypted: encrypted.ciphertext,
|
||||
encryption: encrypted,
|
||||
},
|
||||
passphrase,
|
||||
);
|
||||
|
||||
assert.strictEqual(decrypted, privateKey);
|
||||
});
|
||||
|
||||
test("persistSessionActor stores plain-text session actors", () => {
|
||||
clearStoredSessionActor();
|
||||
|
||||
persistSessionActor({
|
||||
pubkey: "npub1test",
|
||||
privateKey: "b".repeat(64),
|
||||
createdAt: 123,
|
||||
});
|
||||
|
||||
const raw = globalThis.localStorage.getItem(SESSION_ACTOR_STORAGE_KEY);
|
||||
assert.ok(raw, "session actor should be persisted");
|
||||
|
||||
const parsed = JSON.parse(raw);
|
||||
assert.deepStrictEqual(parsed, {
|
||||
pubkey: "npub1test",
|
||||
privateKey: "b".repeat(64),
|
||||
createdAt: 123,
|
||||
});
|
||||
});
|
||||
|
||||
test("persistSessionActor stores encrypted payload metadata", async () => {
|
||||
clearStoredSessionActor();
|
||||
|
||||
const privateKey = "c".repeat(64);
|
||||
const passphrase = "battery staple";
|
||||
const encrypted = await encryptSessionPrivateKey(privateKey, passphrase);
|
||||
|
||||
persistSessionActor({
|
||||
pubkey: "npub1encrypted",
|
||||
privateKeyEncrypted: encrypted.ciphertext,
|
||||
encryption: encrypted,
|
||||
createdAt: 456,
|
||||
});
|
||||
|
||||
const entry = readStoredSessionActorEntry();
|
||||
assert.ok(entry);
|
||||
assert.strictEqual(entry.pubkey, "npub1encrypted");
|
||||
assert.strictEqual(entry.privateKey, "");
|
||||
assert.strictEqual(entry.privateKeyEncrypted, encrypted.ciphertext);
|
||||
assert.deepStrictEqual(entry.encryption, {
|
||||
version: encrypted.version,
|
||||
algorithm: encrypted.algorithm,
|
||||
salt: encrypted.salt,
|
||||
iv: encrypted.iv,
|
||||
iterations: encrypted.iterations,
|
||||
hash: encrypted.hash,
|
||||
});
|
||||
assert.strictEqual(entry.createdAt, 456);
|
||||
|
||||
const raw = globalThis.localStorage.getItem(SESSION_ACTOR_STORAGE_KEY);
|
||||
assert.ok(raw);
|
||||
const parsed = JSON.parse(raw);
|
||||
assert.strictEqual(parsed.privateKey, undefined);
|
||||
assert.strictEqual(parsed.pubkey, "npub1encrypted");
|
||||
assert.strictEqual(parsed.privateKeyEncrypted, encrypted.ciphertext);
|
||||
});
|
||||
|
||||
test("clearStoredSessionActor removes persisted payload", () => {
|
||||
clearStoredSessionActor();
|
||||
persistSessionActor({
|
||||
pubkey: "npub1cleanup",
|
||||
privateKey: "d".repeat(64),
|
||||
});
|
||||
assert.ok(globalThis.localStorage.getItem(SESSION_ACTOR_STORAGE_KEY));
|
||||
|
||||
clearStoredSessionActor();
|
||||
assert.strictEqual(
|
||||
globalThis.localStorage.getItem(SESSION_ACTOR_STORAGE_KEY),
|
||||
null,
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user