signer.mjs raw
1 // TinyJS Runtime — Signer Bridge
2 // Wraps window.nostr (NIP-07) and window.nostr.smesh (management API).
3 // Called by generated Go→JS signer jsbridge code.
4 //
5 // All string parameters are coerced with '' + x because Moxie strings are
6 // Slice objects. The extension bridge JSON-serialises arguments, and
7 // JSON.stringify(Slice) produces garbage. Coercion triggers Slice.toString()
8 // which decodes the bytes to a JS string.
9
10 function _str(v) { return '' + v; }
11
12 export function HasSigner() {
13 return typeof window !== 'undefined' && typeof window.nostr !== 'undefined';
14 }
15
16 export function HasMLS() {
17 return HasSigner() && !!(window.nostr.mls);
18 }
19
20 export function GetPublicKey(fn) {
21 if (!HasSigner() || typeof window.nostr.getPublicKey !== 'function') { fn(''); return; }
22 window.nostr.getPublicKey()
23 .then(function(k) { fn(k); })
24 .catch(function() { fn(''); });
25 }
26
27 export function SignEvent(eventJSON, fn) {
28 if (!HasSigner() || typeof window.nostr.signEvent !== 'function') { console.warn('[signer] SignEvent: no signer'); fn(''); return; }
29 var ev = JSON.parse(_str(eventJSON));
30 console.log('[signer] SignEvent: kind=' + ev.kind + ' hasSigner=true');
31 window.nostr.signEvent(ev)
32 .then(function(signed) {
33 if (!signed || signed.error || !signed.sig) {
34 var reason = (signed && signed.error) || 'no sig field';
35 console.error('[signer] signEvent error:', reason, signed);
36 fn('');
37 return;
38 }
39 console.log('[signer] signEvent OK kind=' + ev.kind + ' sig=' + signed.sig.substring(0,16));
40 fn(JSON.stringify(signed));
41 })
42 .catch(function(e) { console.error('[signer] signEvent failed:', e); fn(''); });
43 }
44
45 export function GetSharedSecret(peerPubkey, fn) {
46 if (!HasSigner() || typeof window.nostr.getSharedSecret !== 'function') { fn(''); return; }
47 window.nostr.getSharedSecret(_str(peerPubkey))
48 .then(function(s) { fn(s || ''); })
49 .catch(function() { fn(''); });
50 }
51
52 export function Nip04Decrypt(peerPubkey, ciphertext, fn) {
53 if (!HasSigner() || !window.nostr.nip04) { fn(''); return; }
54 window.nostr.nip04.decrypt(_str(peerPubkey), _str(ciphertext))
55 .then(function(pt) { fn(pt); })
56 .catch(function() { fn(''); });
57 }
58
59 export function Nip04Encrypt(peerPubkey, plaintext, fn) {
60 if (!HasSigner() || !window.nostr.nip04) { fn(''); return; }
61 window.nostr.nip04.encrypt(_str(peerPubkey), _str(plaintext))
62 .then(function(ct) { fn(ct); })
63 .catch(function() { fn(''); });
64 }
65
66 export function Nip44Decrypt(peerPubkey, ciphertext, fn) {
67 if (!HasSigner() || !window.nostr.nip44) { fn(''); return; }
68 window.nostr.nip44.decrypt(_str(peerPubkey), _str(ciphertext))
69 .then(function(pt) { fn(pt); })
70 .catch(function() { fn(''); });
71 }
72
73 export function Nip44Encrypt(peerPubkey, plaintext, fn) {
74 if (!HasSigner() || !window.nostr.nip44) { fn(''); return; }
75 window.nostr.nip44.encrypt(_str(peerPubkey), _str(plaintext))
76 .then(function(ct) { fn(ct); })
77 .catch(function() { fn(''); });
78 }
79
80 // --- Smesh management API (window.nostr.smesh) ---
81
82 function _smesh() {
83 return (typeof window !== 'undefined' && window.nostr && window.nostr.smesh) || null;
84 }
85
86 export function IsInstalled(fn) {
87 var s = _smesh();
88 if (s && s.isInstalled) {
89 var result = s.isInstalled();
90 if (result && typeof result.then === 'function') {
91 result.then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
92 } else {
93 fn(!!result);
94 }
95 } else {
96 fn(false);
97 }
98 }
99
100 export function GetVaultStatus(fn) {
101 var s = _smesh();
102 if (s && s.getVaultStatus) {
103 s.getVaultStatus().then(function(st) { fn(st); }).catch(function() { fn('none'); });
104 } else {
105 fn('none');
106 }
107 }
108
109 export function CreateVault(password, fn) {
110 var s = _smesh();
111 if (s && s.createVault) {
112 s.createVault(_str(password)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
113 } else {
114 fn(false);
115 }
116 }
117
118 export function UnlockVault(password, fn) {
119 var s = _smesh();
120 if (s && s.unlockVault) {
121 s.unlockVault(_str(password)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
122 } else {
123 fn(false);
124 }
125 }
126
127 export function LockVault(fn) {
128 var s = _smesh();
129 if (s && s.lockVault) {
130 s.lockVault().then(function() { fn(); }).catch(function() { fn(); });
131 } else {
132 fn();
133 }
134 }
135
136 export function ListIdentities(fn) {
137 var s = _smesh();
138 if (s && s.listIdentities) {
139 s.listIdentities()
140 .then(function(list) { fn(typeof list === 'string' ? list : JSON.stringify(list)); })
141 .catch(function() { fn('[]'); });
142 } else {
143 fn('[]');
144 }
145 }
146
147 export function AddIdentity(nsec, fn) {
148 var s = _smesh();
149 if (s && s.addIdentity) {
150 s.addIdentity(_str(nsec)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
151 } else {
152 fn(false);
153 }
154 }
155
156 export function NsecLogin(nsec, fn) {
157 var s = _smesh();
158 if (s && s.nsecLogin) {
159 s.nsecLogin(_str(nsec)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
160 } else {
161 fn(false);
162 }
163 }
164
165 export function SwitchIdentity(pubkey, fn) {
166 var s = _smesh();
167 if (s && s.switchIdentity) {
168 s.switchIdentity(_str(pubkey)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
169 } else {
170 fn(false);
171 }
172 }
173
174 export function ExportVault(password, fn) {
175 var s = _smesh();
176 if (s && s.exportVault) {
177 s.exportVault(_str(password)).then(function(data) {
178 // data may be an object (parsed by ext.mjs) or a string
179 if (typeof data === 'object' && data !== null) {
180 fn(JSON.stringify(data));
181 } else {
182 fn(data || '');
183 }
184 }).catch(function() { fn(''); });
185 } else {
186 fn('');
187 }
188 }
189
190 export function ImportVault(data, fn) {
191 var s = _smesh();
192 if (s && s.importVault) {
193 s.importVault(_str(data)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
194 } else {
195 fn(false);
196 }
197 }
198
199 export function RemoveIdentity(pubkey, fn) {
200 var s = _smesh();
201 if (s && s.removeIdentity) {
202 s.removeIdentity(_str(pubkey)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
203 } else {
204 fn(false);
205 }
206 }
207
208 // --- HD keychain ---
209
210 export function GenerateMnemonic(fn) {
211 var s = _smesh();
212 if (s && s.generateMnemonic) {
213 s.generateMnemonic().then(function(m) { fn(m || ''); }).catch(function() { fn(''); });
214 } else {
215 fn('');
216 }
217 }
218
219 export function ValidateMnemonic(mnemonic, fn) {
220 var s = _smesh();
221 if (s && s.validateMnemonic) {
222 s.validateMnemonic(_str(mnemonic)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
223 } else {
224 fn(false);
225 }
226 }
227
228 export function CreateHDVault(password, name, fn) {
229 var s = _smesh();
230 if (s && s.createHDVault) {
231 s.createHDVault(_str(password), _str(name)).then(function(m) { fn(m || ''); }).catch(function() { fn(''); });
232 } else {
233 fn('');
234 }
235 }
236
237 export function RestoreHDVault(password, mnemonic, name, fn) {
238 var s = _smesh();
239 if (s && s.restoreHDVault) {
240 s.restoreHDVault(_str(password), _str(mnemonic), _str(name)).then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
241 } else {
242 fn(false);
243 }
244 }
245
246 export function DeriveIdentity(name, fn) {
247 var s = _smesh();
248 if (s && s.deriveIdentity) {
249 s.deriveIdentity(_str(name)).then(function(pk) { fn(pk || ''); }).catch(function() { fn(''); });
250 } else {
251 fn('');
252 }
253 }
254
255 export function GetMnemonic(fn) {
256 var s = _smesh();
257 if (s && s.getMnemonic) {
258 s.getMnemonic().then(function(m) { fn(m || ''); }).catch(function() { fn(''); });
259 } else {
260 fn('');
261 }
262 }
263
264 export function ProbeAccount(index, fn) {
265 var s = _smesh();
266 if (s && s.probeAccount) {
267 s.probeAccount(index).then(function(pk) { fn(pk || ''); }).catch(function() { fn(''); });
268 } else {
269 fn('');
270 }
271 }
272
273 export function IsHD(fn) {
274 var s = _smesh();
275 if (s && s.isHD) {
276 s.isHD().then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
277 } else {
278 fn(false);
279 }
280 }
281
282 export function ResetExtension(fn) {
283 var s = _smesh();
284 if (s && s.resetExtension) {
285 s.resetExtension().then(function(ok) { fn(!!ok); }).catch(function() { fn(false); });
286 } else {
287 fn(false);
288 }
289 }
290