77 lines
3.7 KiB
TypeScript
77 lines
3.7 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import vm from "node:vm";
|
|
import { NostrConnectSigner } from "applesauce-signers";
|
|
import { loginWithBunker, loginWithRemoteApp, clearSigner, getNativeIdentityPicker } from "../src/services/signer.ts";
|
|
|
|
function storage() {
|
|
const values = new Map<string, string>();
|
|
return { getItem: (key: string) => values.get(key) ?? null,
|
|
setItem: (key: string, value: string) => { values.set(key, value); },
|
|
removeItem: (key: string) => { values.delete(key); } };
|
|
}
|
|
function browser() {
|
|
Object.defineProperty(globalThis, "localStorage", { configurable: true, value: storage() });
|
|
Object.defineProperty(globalThis, "sessionStorage", { configurable: true, value: storage() });
|
|
Object.defineProperty(globalThis, "navigator", { configurable: true, value: { userAgent: "Android" } });
|
|
const window = { location: { origin: "https://miners.example", href: "" }, setTimeout, clearTimeout };
|
|
Object.defineProperty(globalThis, "window", { configurable: true, value: window });
|
|
return window;
|
|
}
|
|
|
|
test("provider does not overwrite an externally installed NIP-07 extension", () => {
|
|
const extension = { getPublicKey() {}, signEvent() {} };
|
|
const window = { nostr: extension };
|
|
const source = readFileSync(new URL("../../../nostr-provider.js", import.meta.url), "utf8");
|
|
vm.runInNewContext(source, { window });
|
|
assert.equal(window.nostr, extension);
|
|
assert.equal((window as any).archipelagoNostr, undefined);
|
|
});
|
|
|
|
test("native picker remains available locally but is not used for a late extension", () => {
|
|
const window = browser() as any;
|
|
const bridge = { getPublicKey() {}, signEvent() {} };
|
|
window.nostr = bridge;
|
|
window.archipelagoNostr = { provider: bridge, selectIdentity() {}, getSelectedIdentity() {} };
|
|
assert.equal(getNativeIdentityPicker(), window.archipelagoNostr);
|
|
window.nostr = { getPublicKey() {}, signEvent() {} };
|
|
assert.equal(getNativeIdentityPicker(), undefined);
|
|
});
|
|
|
|
test("bunker URI gets explicit relay transport without contacting any relay", async () => {
|
|
browser();
|
|
const original = NostrConnectSigner.fromBunkerURI;
|
|
const pubkey = "a".repeat(64);
|
|
(NostrConnectSigner as any).fromBunkerURI = async (_uri: string, options: any) => {
|
|
assert.equal(typeof options.subscriptionMethod, "function");
|
|
assert.equal(typeof options.publishMethod, "function");
|
|
return { getPublicKey: async () => pubkey, remote: pubkey,
|
|
signer: { key: new Uint8Array(32).fill(1) }, secret: "synthetic", relays: [] };
|
|
};
|
|
try { assert.equal(await loginWithBunker(`bunker://${pubkey}`), pubkey); }
|
|
finally { NostrConnectSigner.fromBunkerURI = original; clearSigner(); }
|
|
});
|
|
|
|
test("mobile signer URI opens synchronously on tap and keeps the external callback origin", async () => {
|
|
const window = browser();
|
|
const originalWait = NostrConnectSigner.prototype.waitForSigner;
|
|
const originalKey = NostrConnectSigner.prototype.getPublicKey;
|
|
NostrConnectSigner.prototype.waitForSigner = function () {
|
|
this.remote = "a".repeat(64); this.isConnected = true; return Promise.resolve();
|
|
};
|
|
NostrConnectSigner.prototype.getPublicKey = async () => "a".repeat(64);
|
|
try {
|
|
const pending = loginWithRemoteApp();
|
|
// Deliberately before an await/microtask: preserve mobile user activation.
|
|
assert.match(window.location.href, /^nostrconnect:\/\//);
|
|
assert.equal(new URL(window.location.href).searchParams.get("callback"),
|
|
"https://miners.example/auth/nostr-callback");
|
|
assert.equal(await pending, "a".repeat(64));
|
|
} finally {
|
|
NostrConnectSigner.prototype.waitForSigner = originalWait;
|
|
NostrConnectSigner.prototype.getPublicKey = originalKey;
|
|
clearSigner();
|
|
}
|
|
});
|