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