injected.js raw
1 // Injected into page context. Exposes window.nostr (NIP-07) and window.nostr.smesh (management).
2 // All methods return Promises. Communication via postMessage → content-script → extension background.
3
4 (function() {
5 let nextID = 1;
6 const pending = {};
7 let promptHandler = null;
8
9 window.addEventListener("message", (e) => {
10 if (e.source !== window || !e.data || e.data.target !== "smesh-page") return;
11 // Response to a pending request.
12 if (e.data.id && pending[e.data.id]) {
13 const { resolve, reject } = pending[e.data.id];
14 delete pending[e.data.id];
15 if (e.data.error) reject(new Error(e.data.error));
16 else resolve(e.data.response);
17 return;
18 }
19 // Broadcast from extension.
20 if (e.data.broadcast && e.data.payload) {
21 const msg = e.data.payload;
22 if (msg.type === "PROMPT" && promptHandler) {
23 promptHandler(msg);
24 }
25 }
26 });
27
28 function request(method, params) {
29 return new Promise((resolve, reject) => {
30 const id = nextID++;
31 pending[id] = { resolve, reject };
32 window.postMessage({ target: "smesh-signer", id, payload: { method, params } }, "*");
33 setTimeout(() => {
34 if (pending[id]) {
35 delete pending[id];
36 reject(new Error("timeout"));
37 }
38 }, 300000);
39 });
40 }
41
42 window.nostr = {
43 getPublicKey: () => request("getPublicKey"),
44 signEvent: (event) => request("signEvent", { event }),
45 getRelays: () => request("getRelays"),
46
47 nip04: {
48 encrypt: (pk, pt) => request("nip04.encrypt", { pubkey: pk, plaintext: pt }),
49 decrypt: (pk, ct) => request("nip04.decrypt", { pubkey: pk, ciphertext: ct }),
50 },
51
52 nip44: {
53 encrypt: (pk, pt) => request("nip44.encrypt", { pubkey: pk, plaintext: pt }),
54 decrypt: (pk, ct) => request("nip44.decrypt", { pubkey: pk, ciphertext: ct }),
55 },
56
57 // Management API (sm3sh modal → extension).
58 smesh: {
59 isInstalled: () => true,
60 getVaultStatus: () => request("smesh.getVaultStatus"),
61 unlockVault: (password) => request("smesh.unlockVault", { password }),
62 lockVault: () => request("smesh.lockVault"),
63 createVault: (password) => request("smesh.createVault", { password }),
64 listIdentities: () => request("smesh.listIdentities"),
65 switchIdentity: (pubkey) => request("smesh.switchIdentity", { pubkey }),
66 addIdentity: (nsec) => request("smesh.addIdentity", { nsec }),
67 removeIdentity: (pubkey) => request("smesh.removeIdentity", { pubkey }),
68 exportVault: () => request("smesh.exportVault"),
69 importVault: (data) => request("smesh.importVault", { data }),
70 getPermissions: () => request("smesh.getPermissions"),
71 setPermission: (host, method, policy) => request("smesh.setPermission", { host, method, policy }),
72 onPrompt: (cb) => { promptHandler = cb; },
73
74 // HD keychain
75 generateMnemonic: () => request("smesh.generateMnemonic"),
76 validateMnemonic: (mnemonic) => request("smesh.validateMnemonic", { mnemonic }),
77 createHDVault: (password, name) => request("smesh.createHDVault", { password, name }),
78 restoreHDVault: (password, mnemonic, name) => request("smesh.restoreHDVault", { password, mnemonic, name }),
79 deriveIdentity: (name) => request("smesh.deriveIdentity", { name }),
80 getMnemonic: () => request("smesh.getMnemonic"),
81 probeAccount: (index) => request("smesh.probeAccount", { index }),
82 isHD: () => request("smesh.isHD"),
83 resetExtension: () => request("smesh.resetExtension"),
84 },
85 };
86 })();
87