Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c45a4f3dc | ||
|
|
2221e81c9b | ||
|
|
2ca4baad63 | ||
|
|
c4ecc8aca2 | ||
|
|
43c8d0d3a3 |
+49
-50
@@ -8,7 +8,7 @@
|
||||
* Two-file architecture:
|
||||
* 1. Load nostr.bundle.js (official nostr-tools bundle)
|
||||
* 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes)
|
||||
* Generated on: 2026-05-27T19:17:36.261Z
|
||||
* Generated on: 2026-07-21T23:30:02.044Z
|
||||
*/
|
||||
|
||||
// Verify dependencies are loaded
|
||||
@@ -436,7 +436,7 @@ class Modal {
|
||||
modalContent.appendChild(modalHeader);
|
||||
// Add version element in bottom-right corner aligned with modal body
|
||||
const versionElement = document.createElement('div');
|
||||
versionElement.textContent = 'v0.1.19';
|
||||
versionElement.textContent = 'v0.1.22';
|
||||
versionElement.style.cssText = `
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
@@ -1663,7 +1663,7 @@ class Modal {
|
||||
try {
|
||||
// Incremental step 1:
|
||||
// chooser + capture + driver open only (no getPublicKey/auth yet).
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x303a }] });
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{}] });
|
||||
this._nsignerSelectedDevice = selectedDevice;
|
||||
|
||||
if (!window.NSignerWebUSB || typeof window.NSignerWebUSB !== 'function') {
|
||||
@@ -2008,10 +2008,7 @@ class Modal {
|
||||
|
||||
if (!driver && canUsb) {
|
||||
try {
|
||||
const pairedUsb = await window.NSignerWebUSB.getPairedDevice({
|
||||
vendorId: 0x303a,
|
||||
productId: 0x4001
|
||||
});
|
||||
const pairedUsb = await window.NSignerWebUSB.getPairedDevice();
|
||||
if (pairedUsb) {
|
||||
renderConnectingScreen('Reconnecting to paired WebUSB device...');
|
||||
transport = 'webusb';
|
||||
@@ -2055,7 +2052,7 @@ class Modal {
|
||||
} else if (target === 'webusb') {
|
||||
renderConnectingScreen('Waiting for WebUSB device selection...');
|
||||
try {
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x303a }] });
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{}] });
|
||||
transport = 'webusb';
|
||||
driver = await connectUsbFromDevice(selectedDevice);
|
||||
} catch (usbErr) {
|
||||
@@ -2300,7 +2297,7 @@ class Modal {
|
||||
throw new Error('NSignerWebUSB driver missing');
|
||||
}
|
||||
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x303a }] });
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{}] });
|
||||
|
||||
const driver = new window.NSignerWebUSB(selectedDevice, {
|
||||
callerSecretKey: caller.secret,
|
||||
@@ -3364,9 +3361,9 @@ window.addEventListener('load', () => {
|
||||
// ======================================
|
||||
|
||||
class NSignerWebUSB {
|
||||
// Keep picker broad (vendor-level) so Chromium can show all matching Feather states.
|
||||
// Product-level checks still happen during open()/RPC.
|
||||
static FILTERS = [{ vendorId: 0x303a }];
|
||||
// Keep WebUSB chooser unfiltered so users can select any USB device.
|
||||
// WebUSB requires a non-empty filters array; {} matches all devices.
|
||||
static FILTERS = [{}];
|
||||
|
||||
static async requestAndConnect(options = {}) {
|
||||
if (!('usb' in navigator)) {
|
||||
@@ -3385,13 +3382,14 @@ class NSignerWebUSB {
|
||||
const devices = await navigator.usb.getDevices();
|
||||
if (!devices || devices.length === 0) return null;
|
||||
|
||||
const vendorId = options.vendorId ?? 0x303a;
|
||||
const vendorId = options.vendorId ?? null;
|
||||
const productId = options.productId ?? null;
|
||||
const serial = options.serialNumber || null;
|
||||
|
||||
return devices.find((d) => {
|
||||
const vendorMatch = d.vendorId === vendorId;
|
||||
if (!vendorMatch) return false;
|
||||
if (vendorId !== null && vendorId !== undefined && d.vendorId !== vendorId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (productId !== null && productId !== undefined && d.productId !== productId) {
|
||||
return false;
|
||||
@@ -3518,43 +3516,43 @@ class NSignerWebUSB {
|
||||
|
||||
async getPublicKey() {
|
||||
const params = [{ nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('get_public_key', params);
|
||||
const resp = await this._rpcCall('nostr_get_public_key', params);
|
||||
if (!resp || typeof resp.result !== 'string') {
|
||||
throw new Error('Invalid get_public_key response');
|
||||
throw new Error('Invalid nostr_get_public_key response');
|
||||
}
|
||||
return resp.result.trim().toLowerCase();
|
||||
}
|
||||
|
||||
async signEvent(unsignedEvent) {
|
||||
const params = [unsignedEvent, { nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('sign_event', params);
|
||||
const resp = await this._rpcCall('nostr_sign_event', params);
|
||||
if (!resp || typeof resp.result !== 'object') {
|
||||
throw new Error('Invalid sign_event response');
|
||||
throw new Error('Invalid nostr_sign_event response');
|
||||
}
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
@@ -3727,19 +3725,17 @@ if (typeof window !== 'undefined') {
|
||||
// ======================================
|
||||
|
||||
class NSignerWebSerial {
|
||||
// CH340 VID:PID 0x1a86:0x7523 (most CYD revisions)
|
||||
// CP2102 VID:PID 0x10c4:0xea60 (some CYD revisions)
|
||||
static FILTERS = [
|
||||
{ usbVendorId: 0x1a86, usbProductId: 0x7523 },
|
||||
{ usbVendorId: 0x10c4, usbProductId: 0xea60 }
|
||||
];
|
||||
// Keep Web Serial chooser unfiltered so users can select any serial port.
|
||||
static FILTERS = [];
|
||||
|
||||
static async requestAndConnect(options = {}) {
|
||||
if (!('serial' in navigator)) {
|
||||
throw new Error('Web Serial API not available in this browser (requires Chrome 89+, Edge 89+, or Brave)');
|
||||
}
|
||||
|
||||
const port = await navigator.serial.requestPort({ filters: NSignerWebSerial.FILTERS });
|
||||
const port = NSignerWebSerial.FILTERS.length
|
||||
? await navigator.serial.requestPort({ filters: NSignerWebSerial.FILTERS })
|
||||
: await navigator.serial.requestPort();
|
||||
const driver = new NSignerWebSerial(port, options);
|
||||
await driver.open();
|
||||
return driver;
|
||||
@@ -3918,43 +3914,43 @@ class NSignerWebSerial {
|
||||
|
||||
async getPublicKey() {
|
||||
const params = [{ nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('get_public_key', params);
|
||||
const resp = await this._rpcCall('nostr_get_public_key', params);
|
||||
if (!resp || typeof resp.result !== 'string') {
|
||||
throw new Error('Invalid get_public_key response');
|
||||
throw new Error('Invalid nostr_get_public_key response');
|
||||
}
|
||||
return resp.result.trim().toLowerCase();
|
||||
}
|
||||
|
||||
async signEvent(unsignedEvent) {
|
||||
const params = [unsignedEvent, { nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('sign_event', params);
|
||||
const resp = await this._rpcCall('nostr_sign_event', params);
|
||||
if (!resp || typeof resp.result !== 'object') {
|
||||
throw new Error('Invalid sign_event response');
|
||||
throw new Error('Invalid nostr_sign_event response');
|
||||
}
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
@@ -4170,12 +4166,15 @@ class NSignerWebSerial {
|
||||
const vid = matchInfo?.usbVendorId;
|
||||
const pid = matchInfo?.usbProductId;
|
||||
|
||||
return ports.find((p) => {
|
||||
// Prefer exact VID/PID match when available, but do not require it.
|
||||
const exact = ports.find((p) => {
|
||||
const i = p.getInfo?.() || {};
|
||||
if (vid != null && i.usbVendorId !== vid) return false;
|
||||
if (pid != null && i.usbProductId !== pid) return false;
|
||||
return true;
|
||||
}) || ports[0] || null;
|
||||
});
|
||||
|
||||
return exact || ports[0] || null;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
@@ -5958,8 +5957,8 @@ class AuthManager {
|
||||
}
|
||||
|
||||
const paired = await window.NSignerWebUSB.getPairedDevice({
|
||||
vendorId: nsigner.deviceVid ?? 0x303a,
|
||||
productId: nsigner.deviceProductId ?? 0x4001,
|
||||
vendorId: nsigner.deviceVid ?? null,
|
||||
productId: nsigner.deviceProductId ?? null,
|
||||
serialNumber: nsigner.deviceSerial || undefined
|
||||
});
|
||||
|
||||
|
||||
@@ -11146,12 +11146,12 @@ zoo`.split("\n");
|
||||
}
|
||||
async getPublicKey() {
|
||||
if (!this.cachedPubKey) {
|
||||
this.cachedPubKey = await this.sendRequest("get_public_key", []);
|
||||
this.cachedPubKey = await this.sendRequest("nostr_get_public_key", []);
|
||||
}
|
||||
return this.cachedPubKey;
|
||||
}
|
||||
async signEvent(event) {
|
||||
let resp = await this.sendRequest("sign_event", [JSON.stringify(event)]);
|
||||
let resp = await this.sendRequest("nostr_sign_event", [JSON.stringify(event)]);
|
||||
let signed = JSON.parse(resp);
|
||||
if (verifyEvent(signed)) {
|
||||
return signed;
|
||||
@@ -11160,16 +11160,16 @@ zoo`.split("\n");
|
||||
}
|
||||
}
|
||||
async nip04Encrypt(thirdPartyPubkey, plaintext) {
|
||||
return await this.sendRequest("nip04_encrypt", [thirdPartyPubkey, plaintext]);
|
||||
return await this.sendRequest("nostr_nip04_encrypt", [thirdPartyPubkey, plaintext]);
|
||||
}
|
||||
async nip04Decrypt(thirdPartyPubkey, ciphertext) {
|
||||
return await this.sendRequest("nip04_decrypt", [thirdPartyPubkey, ciphertext]);
|
||||
return await this.sendRequest("nostr_nip04_decrypt", [thirdPartyPubkey, ciphertext]);
|
||||
}
|
||||
async nip44Encrypt(thirdPartyPubkey, plaintext) {
|
||||
return await this.sendRequest("nip44_encrypt", [thirdPartyPubkey, plaintext]);
|
||||
return await this.sendRequest("nostr_nip44_encrypt", [thirdPartyPubkey, plaintext]);
|
||||
}
|
||||
async nip44Decrypt(thirdPartyPubkey, ciphertext) {
|
||||
return await this.sendRequest("nip44_decrypt", [thirdPartyPubkey, ciphertext]);
|
||||
return await this.sendRequest("nostr_nip44_decrypt", [thirdPartyPubkey, ciphertext]);
|
||||
}
|
||||
};
|
||||
async function createAccount(bunker, params, username, domain, email, localSecretKey = generateSecretKey()) {
|
||||
|
||||
@@ -249,12 +249,8 @@
|
||||
const nip44DecOutEl = document.getElementById("nip44DecOut");
|
||||
|
||||
// ── State ─────────────────────────────────────────────────────────────────
|
||||
// CH340 VID:PID 0x1a86:0x7523 (most CYD revisions)
|
||||
// CP2102 VID:PID 0x10c4:0xea60 (some CYD revisions)
|
||||
const SERIAL_FILTERS = [
|
||||
{ usbVendorId: 0x1a86, usbProductId: 0x7523 },
|
||||
{ usbVendorId: 0x10c4, usbProductId: 0xea60 }
|
||||
];
|
||||
// Keep chooser unfiltered so any serial-capable device can be selected.
|
||||
const SERIAL_FILTERS = [];
|
||||
|
||||
let port = null; // SerialPort
|
||||
let writer = null; // WritableStreamDefaultWriter
|
||||
@@ -507,7 +503,9 @@
|
||||
throw new Error("Web Serial API not available — use Chrome 89+, Edge 89+, or Brave");
|
||||
}
|
||||
|
||||
const initiallySelected = await navigator.serial.requestPort({ filters: SERIAL_FILTERS });
|
||||
const initiallySelected = SERIAL_FILTERS.length
|
||||
? await navigator.serial.requestPort({ filters: SERIAL_FILTERS })
|
||||
: await navigator.serial.requestPort();
|
||||
const selectedInfo = initiallySelected.getInfo?.() || {};
|
||||
let lastError = null;
|
||||
|
||||
@@ -613,7 +611,7 @@
|
||||
// ── Pubkey helper ─────────────────────────────────────────────────────────
|
||||
async function fetchOwnPubkeyAndFillPeers() {
|
||||
const params = [getIndexOptions()];
|
||||
const resp = await rpcCall("get_public_key", params);
|
||||
const resp = await rpcCall("nostr_get_public_key", params);
|
||||
if (resp && typeof resp.result === "string") {
|
||||
ownPubkey = resp.result.trim().toLowerCase();
|
||||
pubkeyOutEl.textContent = pretty(resp);
|
||||
@@ -670,7 +668,7 @@
|
||||
};
|
||||
|
||||
const params = [unsignedEvent, getIndexOptions()];
|
||||
const resp = await rpcCall("sign_event", params);
|
||||
const resp = await rpcCall("nostr_sign_event", params);
|
||||
signOutEl.textContent = pretty(resp?.result ?? resp);
|
||||
} catch (e) {
|
||||
signOutEl.textContent = String(e);
|
||||
@@ -682,7 +680,7 @@
|
||||
const peer = requirePeerHex(nip04PeerEl.value);
|
||||
const msg = String(nip04MsgEl.value || "");
|
||||
const params = [peer, msg, getIndexOptions()];
|
||||
const resp = await rpcCall("nip04_encrypt", params);
|
||||
const resp = await rpcCall("nostr_nip04_encrypt", params);
|
||||
nip04OutEl.textContent = pretty(resp?.result ?? resp);
|
||||
if (resp && typeof resp.result === "string") {
|
||||
nip04DecPeerEl.value = peer;
|
||||
@@ -698,7 +696,7 @@
|
||||
const peer = requirePeerHex(nip04DecPeerEl.value);
|
||||
const ciphertext = String(nip04CipherEl.value || "");
|
||||
const params = [peer, ciphertext, getIndexOptions()];
|
||||
const resp = await rpcCall("nip04_decrypt", params);
|
||||
const resp = await rpcCall("nostr_nip04_decrypt", params);
|
||||
nip04DecOutEl.textContent = requireStringResult(resp, "NIP-04 decrypt");
|
||||
} catch (e) {
|
||||
nip04DecOutEl.textContent = String(e);
|
||||
@@ -710,7 +708,7 @@
|
||||
const peer = requirePeerHex(nip44PeerEl.value);
|
||||
const msg = String(nip44MsgEl.value || "");
|
||||
const params = [peer, msg, getIndexOptions()];
|
||||
const resp = await rpcCall("nip44_encrypt", params);
|
||||
const resp = await rpcCall("nostr_nip44_encrypt", params);
|
||||
nip44OutEl.textContent = pretty(resp?.result ?? resp);
|
||||
if (resp && typeof resp.result === "string") {
|
||||
nip44DecPeerEl.value = peer;
|
||||
@@ -726,7 +724,7 @@
|
||||
const peer = requirePeerHex(nip44DecPeerEl.value);
|
||||
const ciphertext = String(nip44CipherEl.value || "");
|
||||
const params = [peer, ciphertext, getIndexOptions()];
|
||||
const resp = await rpcCall("nip44_decrypt", params);
|
||||
const resp = await rpcCall("nostr_nip44_decrypt", params);
|
||||
nip44DecOutEl.textContent = requireStringResult(resp, "NIP-44 decrypt");
|
||||
} catch (e) {
|
||||
nip44DecOutEl.textContent = String(e);
|
||||
|
||||
@@ -369,7 +369,7 @@
|
||||
|
||||
async function fetchOwnPubkeyAndFillPeers() {
|
||||
const params = [getIndexOptions()];
|
||||
const resp = await rpcCall("get_public_key", params, "web-own-pubkey");
|
||||
const resp = await rpcCall("nostr_get_public_key", params, "web-own-pubkey");
|
||||
if (resp && typeof resp.result === "string") {
|
||||
ownPubkey = resp.result.trim().toLowerCase();
|
||||
pubkeyOutEl.textContent = pretty(resp);
|
||||
@@ -383,7 +383,7 @@
|
||||
}
|
||||
|
||||
async function connect() {
|
||||
dev = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x303a }] });
|
||||
dev = await navigator.usb.requestDevice({ filters: [{}] });
|
||||
await dev.open();
|
||||
if (dev.configuration === null) {
|
||||
await dev.selectConfiguration(1);
|
||||
@@ -460,7 +460,7 @@
|
||||
};
|
||||
|
||||
const params = [unsignedEvent, getIndexOptions()];
|
||||
const resp = await rpcCall("sign_event", params, "web-sign-kind1");
|
||||
const resp = await rpcCall("nostr_sign_event", params, "web-sign-kind1");
|
||||
signOutEl.textContent = pretty(resp?.result ?? resp);
|
||||
} catch (e) {
|
||||
signOutEl.textContent = String(e);
|
||||
@@ -472,7 +472,7 @@
|
||||
const peer = requirePeerHex(nip04PeerEl.value);
|
||||
const msg = String(nip04MsgEl.value || "");
|
||||
const params = [peer, msg, getIndexOptions()];
|
||||
const resp = await rpcCall("nip04_encrypt", params, "web-nip04-enc");
|
||||
const resp = await rpcCall("nostr_nip04_encrypt", params, "web-nip04-enc");
|
||||
nip04OutEl.textContent = pretty(resp?.result ?? resp);
|
||||
if (resp && typeof resp.result === "string") {
|
||||
nip04DecPeerEl.value = peer;
|
||||
@@ -488,7 +488,7 @@
|
||||
const peer = requirePeerHex(nip04DecPeerEl.value);
|
||||
const ciphertext = String(nip04CipherEl.value || "");
|
||||
const params = [peer, ciphertext, getIndexOptions()];
|
||||
const resp = await rpcCall("nip04_decrypt", params, "web-nip04-dec");
|
||||
const resp = await rpcCall("nostr_nip04_decrypt", params, "web-nip04-dec");
|
||||
nip04DecOutEl.textContent = requireStringResult(resp, "NIP-04 decrypt");
|
||||
} catch (e) {
|
||||
nip04DecOutEl.textContent = String(e);
|
||||
@@ -500,7 +500,7 @@
|
||||
const peer = requirePeerHex(nip44PeerEl.value);
|
||||
const msg = String(nip44MsgEl.value || "");
|
||||
const params = [peer, msg, getIndexOptions()];
|
||||
const resp = await rpcCall("nip44_encrypt", params, "web-nip44-enc");
|
||||
const resp = await rpcCall("nostr_nip44_encrypt", params, "web-nip44-enc");
|
||||
nip44OutEl.textContent = pretty(resp?.result ?? resp);
|
||||
if (resp && typeof resp.result === "string") {
|
||||
nip44DecPeerEl.value = peer;
|
||||
@@ -516,7 +516,7 @@
|
||||
const peer = requirePeerHex(nip44DecPeerEl.value);
|
||||
const ciphertext = String(nip44CipherEl.value || "");
|
||||
const params = [peer, ciphertext, getIndexOptions()];
|
||||
const resp = await rpcCall("nip44_decrypt", params, "web-nip44-dec");
|
||||
const resp = await rpcCall("nostr_nip44_decrypt", params, "web-nip44-dec");
|
||||
nip44DecOutEl.textContent = requireStringResult(resp, "NIP-44 decrypt");
|
||||
} catch (e) {
|
||||
nip44DecOutEl.textContent = String(e);
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.1.19
|
||||
0.1.22
|
||||
|
||||
+2
-2
@@ -2005,8 +2005,8 @@ class AuthManager {
|
||||
}
|
||||
|
||||
const paired = await window.NSignerWebUSB.getPairedDevice({
|
||||
vendorId: nsigner.deviceVid ?? 0x303a,
|
||||
productId: nsigner.deviceProductId ?? 0x4001,
|
||||
vendorId: nsigner.deviceVid ?? null,
|
||||
productId: nsigner.deviceProductId ?? null,
|
||||
serialNumber: nsigner.deviceSerial || undefined
|
||||
});
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
class NSignerWebSerial {
|
||||
// CH340 VID:PID 0x1a86:0x7523 (most CYD revisions)
|
||||
// CP2102 VID:PID 0x10c4:0xea60 (some CYD revisions)
|
||||
static FILTERS = [
|
||||
{ usbVendorId: 0x1a86, usbProductId: 0x7523 },
|
||||
{ usbVendorId: 0x10c4, usbProductId: 0xea60 }
|
||||
];
|
||||
// Keep Web Serial chooser unfiltered so users can select any serial port.
|
||||
static FILTERS = [];
|
||||
|
||||
static async requestAndConnect(options = {}) {
|
||||
if (!('serial' in navigator)) {
|
||||
throw new Error('Web Serial API not available in this browser (requires Chrome 89+, Edge 89+, or Brave)');
|
||||
}
|
||||
|
||||
const port = await navigator.serial.requestPort({ filters: NSignerWebSerial.FILTERS });
|
||||
const port = NSignerWebSerial.FILTERS.length
|
||||
? await navigator.serial.requestPort({ filters: NSignerWebSerial.FILTERS })
|
||||
: await navigator.serial.requestPort();
|
||||
const driver = new NSignerWebSerial(port, options);
|
||||
await driver.open();
|
||||
return driver;
|
||||
@@ -190,43 +188,43 @@ class NSignerWebSerial {
|
||||
|
||||
async getPublicKey() {
|
||||
const params = [{ nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('get_public_key', params);
|
||||
const resp = await this._rpcCall('nostr_get_public_key', params);
|
||||
if (!resp || typeof resp.result !== 'string') {
|
||||
throw new Error('Invalid get_public_key response');
|
||||
throw new Error('Invalid nostr_get_public_key response');
|
||||
}
|
||||
return resp.result.trim().toLowerCase();
|
||||
}
|
||||
|
||||
async signEvent(unsignedEvent) {
|
||||
const params = [unsignedEvent, { nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('sign_event', params);
|
||||
const resp = await this._rpcCall('nostr_sign_event', params);
|
||||
if (!resp || typeof resp.result !== 'object') {
|
||||
throw new Error('Invalid sign_event response');
|
||||
throw new Error('Invalid nostr_sign_event response');
|
||||
}
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
@@ -442,12 +440,15 @@ class NSignerWebSerial {
|
||||
const vid = matchInfo?.usbVendorId;
|
||||
const pid = matchInfo?.usbProductId;
|
||||
|
||||
return ports.find((p) => {
|
||||
// Prefer exact VID/PID match when available, but do not require it.
|
||||
const exact = ports.find((p) => {
|
||||
const i = p.getInfo?.() || {};
|
||||
if (vid != null && i.usbVendorId !== vid) return false;
|
||||
if (pid != null && i.usbProductId !== pid) return false;
|
||||
return true;
|
||||
}) || ports[0] || null;
|
||||
});
|
||||
|
||||
return exact || ports[0] || null;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class NSignerWebUSB {
|
||||
// Keep picker broad (vendor-level) so Chromium can show all matching Feather states.
|
||||
// Product-level checks still happen during open()/RPC.
|
||||
static FILTERS = [{ vendorId: 0x303a }];
|
||||
// Keep WebUSB chooser unfiltered so users can select any USB device.
|
||||
// WebUSB requires a non-empty filters array; {} matches all devices.
|
||||
static FILTERS = [{}];
|
||||
|
||||
static async requestAndConnect(options = {}) {
|
||||
if (!('usb' in navigator)) {
|
||||
@@ -20,13 +20,14 @@ class NSignerWebUSB {
|
||||
const devices = await navigator.usb.getDevices();
|
||||
if (!devices || devices.length === 0) return null;
|
||||
|
||||
const vendorId = options.vendorId ?? 0x303a;
|
||||
const vendorId = options.vendorId ?? null;
|
||||
const productId = options.productId ?? null;
|
||||
const serial = options.serialNumber || null;
|
||||
|
||||
return devices.find((d) => {
|
||||
const vendorMatch = d.vendorId === vendorId;
|
||||
if (!vendorMatch) return false;
|
||||
if (vendorId !== null && vendorId !== undefined && d.vendorId !== vendorId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (productId !== null && productId !== undefined && d.productId !== productId) {
|
||||
return false;
|
||||
@@ -153,43 +154,43 @@ class NSignerWebUSB {
|
||||
|
||||
async getPublicKey() {
|
||||
const params = [{ nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('get_public_key', params);
|
||||
const resp = await this._rpcCall('nostr_get_public_key', params);
|
||||
if (!resp || typeof resp.result !== 'string') {
|
||||
throw new Error('Invalid get_public_key response');
|
||||
throw new Error('Invalid nostr_get_public_key response');
|
||||
}
|
||||
return resp.result.trim().toLowerCase();
|
||||
}
|
||||
|
||||
async signEvent(unsignedEvent) {
|
||||
const params = [unsignedEvent, { nostr_index: this.nostrIndex }];
|
||||
const resp = await this._rpcCall('sign_event', params);
|
||||
const resp = await this._rpcCall('nostr_sign_event', params);
|
||||
if (!resp || typeof resp.result !== 'object') {
|
||||
throw new Error('Invalid sign_event response');
|
||||
throw new Error('Invalid nostr_sign_event response');
|
||||
}
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip04Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip04_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip04_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip04_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Encrypt(peerHex, plaintext) {
|
||||
const resp = await this._rpcCall('nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_encrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_encrypt', [peerHex, plaintext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_encrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
async nip44Decrypt(peerHex, ciphertext) {
|
||||
const resp = await this._rpcCall('nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nip44_decrypt response');
|
||||
const resp = await this._rpcCall('nostr_nip44_decrypt', [peerHex, ciphertext, { nostr_index: this.nostrIndex }]);
|
||||
if (!resp || typeof resp.result !== 'string') throw new Error('Invalid nostr_nip44_decrypt response');
|
||||
return resp.result;
|
||||
}
|
||||
|
||||
|
||||
+4
-7
@@ -1351,7 +1351,7 @@ class Modal {
|
||||
try {
|
||||
// Incremental step 1:
|
||||
// chooser + capture + driver open only (no getPublicKey/auth yet).
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x303a }] });
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{}] });
|
||||
this._nsignerSelectedDevice = selectedDevice;
|
||||
|
||||
if (!window.NSignerWebUSB || typeof window.NSignerWebUSB !== 'function') {
|
||||
@@ -1696,10 +1696,7 @@ class Modal {
|
||||
|
||||
if (!driver && canUsb) {
|
||||
try {
|
||||
const pairedUsb = await window.NSignerWebUSB.getPairedDevice({
|
||||
vendorId: 0x303a,
|
||||
productId: 0x4001
|
||||
});
|
||||
const pairedUsb = await window.NSignerWebUSB.getPairedDevice();
|
||||
if (pairedUsb) {
|
||||
renderConnectingScreen('Reconnecting to paired WebUSB device...');
|
||||
transport = 'webusb';
|
||||
@@ -1743,7 +1740,7 @@ class Modal {
|
||||
} else if (target === 'webusb') {
|
||||
renderConnectingScreen('Waiting for WebUSB device selection...');
|
||||
try {
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x303a }] });
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{}] });
|
||||
transport = 'webusb';
|
||||
driver = await connectUsbFromDevice(selectedDevice);
|
||||
} catch (usbErr) {
|
||||
@@ -1988,7 +1985,7 @@ class Modal {
|
||||
throw new Error('NSignerWebUSB driver missing');
|
||||
}
|
||||
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{ vendorId: 0x303a }] });
|
||||
const selectedDevice = await navigator.usb.requestDevice({ filters: [{}] });
|
||||
|
||||
const driver = new window.NSignerWebUSB(selectedDevice, {
|
||||
callerSecretKey: caller.secret,
|
||||
|
||||
Reference in New Issue
Block a user