Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
517974699d |
309
lite/build.js
309
lite/build.js
@@ -1093,10 +1093,8 @@ class NostrLite {
|
|||||||
// Apply the selected theme (CSS-only)
|
// Apply the selected theme (CSS-only)
|
||||||
this.switchTheme(this.options.theme);
|
this.switchTheme(this.options.theme);
|
||||||
|
|
||||||
// Set up window.nostr facade if no extension detected
|
// Always set up window.nostr facade to handle multiple extensions properly
|
||||||
if (this.extensionBridge.getExtensionCount() === 0) {
|
|
||||||
this._setupWindowNostrFacade();
|
this._setupWindowNostrFacade();
|
||||||
}
|
|
||||||
|
|
||||||
// Create modal during init (matching original git architecture)
|
// Create modal during init (matching original git architecture)
|
||||||
this.modal = new Modal(this.options);
|
this.modal = new Modal(this.options);
|
||||||
@@ -1115,9 +1113,14 @@ class NostrLite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_setupWindowNostrFacade() {
|
_setupWindowNostrFacade() {
|
||||||
if (typeof window !== 'undefined' && !window.nostr) {
|
if (typeof window !== 'undefined') {
|
||||||
window.nostr = new WindowNostr(this);
|
// Store existing window.nostr if it exists (from extensions)
|
||||||
console.log('NOSTR_LOGIN_LITE: window.nostr facade installed');
|
const existingNostr = window.nostr;
|
||||||
|
|
||||||
|
// Always install our facade
|
||||||
|
window.nostr = new WindowNostr(this, existingNostr);
|
||||||
|
console.log('NOSTR_LOGIN_LITE: window.nostr facade installed',
|
||||||
|
existingNostr ? '(with extension passthrough)' : '(no existing extension)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1231,45 +1234,313 @@ class NostrLite {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window.nostr facade for when no extension is available
|
// NIP-07 compliant window.nostr provider
|
||||||
class WindowNostr {
|
class WindowNostr {
|
||||||
constructor(nostrLite) {
|
constructor(nostrLite, existingNostr = null) {
|
||||||
this.nostrLite = nostrLite;
|
this.nostrLite = nostrLite;
|
||||||
|
this.authState = null;
|
||||||
|
this.existingNostr = existingNostr;
|
||||||
|
this.authenticatedExtension = null;
|
||||||
|
this._setupEventListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
_setupEventListeners() {
|
||||||
|
// Listen for authentication events to store auth state
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
window.addEventListener('nlMethodSelected', (event) => {
|
||||||
|
this.authState = event.detail;
|
||||||
|
|
||||||
|
// If extension method, capture the specific extension the user chose
|
||||||
|
if (event.detail.method === 'extension') {
|
||||||
|
this.authenticatedExtension = event.detail.extension;
|
||||||
|
console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name);
|
||||||
|
|
||||||
|
// Re-install our facade to ensure we intercept signEvent calls
|
||||||
|
// Extensions may overwrite window.nostr after authentication
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
console.log('WindowNostr: Re-installing facade after authentication');
|
||||||
|
window.nostr = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('WindowNostr: Auth state updated:', this.authState?.method);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('nlLogout', () => {
|
||||||
|
this.authState = null;
|
||||||
|
this.authenticatedExtension = null;
|
||||||
|
console.log('WindowNostr: Auth state cleared');
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPublicKey() {
|
async getPublicKey() {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension':
|
||||||
|
// Use the captured authenticated extension, not current window.nostr
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.getPublicKey();
|
||||||
|
|
||||||
|
case 'local':
|
||||||
|
case 'nip46':
|
||||||
|
return this.authState.pubkey;
|
||||||
|
|
||||||
|
case 'readonly':
|
||||||
|
throw new Error('Read-only mode - cannot get public key');
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(\`Unsupported auth method: \${this.authState.method}\`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async signEvent(event) {
|
async signEvent(event) {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot sign events');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension':
|
||||||
|
// Use the captured authenticated extension, not current window.nostr
|
||||||
|
console.log('WindowNostr: signEvent - authenticatedExtension:', this.authenticatedExtension);
|
||||||
|
console.log('WindowNostr: signEvent - authState.extension:', this.authState.extension);
|
||||||
|
console.log('WindowNostr: signEvent - existingNostr:', this.existingNostr);
|
||||||
|
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
console.log('WindowNostr: signEvent - using extension:', ext);
|
||||||
|
console.log('WindowNostr: signEvent - extension constructor:', ext?.constructor?.name);
|
||||||
|
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.signEvent(event);
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
// Use nostr-tools to sign with local secret key
|
||||||
|
const { nip19, finalizeEvent } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
// Convert hex to Uint8Array
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalizeEvent(event, secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
// Use BunkerSigner for NIP-46
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.signEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(\`Unsupported auth method: \${this.authState.method}\`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRelays() {
|
async getRelays() {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
// Return configured relays from nostr-lite options
|
||||||
|
return this.nostrLite.options?.relays || ['wss://relay.damus.io'];
|
||||||
}
|
}
|
||||||
|
|
||||||
get nip04() {
|
get nip04() {
|
||||||
return {
|
return {
|
||||||
async encrypt(pubkey, plaintext) {
|
encrypt: async (pubkey, plaintext) => {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot encrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip04.encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip04, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await nip04.encrypt(secretKey, pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip04Encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(\`Unsupported auth method: \${this.authState.method}\`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async decrypt(pubkey, ciphertext) {
|
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
decrypt: async (pubkey, ciphertext) => {
|
||||||
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot decrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip04.decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip04, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await nip04.decrypt(secretKey, pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip04Decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(\`Unsupported auth method: \${this.authState.method}\`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get nip44() {
|
get nip44() {
|
||||||
return {
|
return {
|
||||||
async encrypt(pubkey, plaintext) {
|
encrypt: async (pubkey, plaintext) => {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot encrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip44.encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip44, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nip44.encrypt(plaintext, nip44.getConversationKey(secretKey, pubkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip44Encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(\`Unsupported auth method: \${this.authState.method}\`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async decrypt(pubkey, ciphertext) {
|
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
decrypt: async (pubkey, ciphertext) => {
|
||||||
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot decrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip44.decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip44, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nip44.decrypt(ciphertext, nip44.getConversationKey(secretKey, pubkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip44Decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(\`Unsupported auth method: \${this.authState.method}\`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hexToUint8Array(hex) {
|
||||||
|
if (hex.length % 2 !== 0) {
|
||||||
|
throw new Error('Invalid hex string length');
|
||||||
|
}
|
||||||
|
const bytes = new Uint8Array(hex.length / 2);
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize and export
|
// Initialize and export
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* Two-file architecture:
|
* Two-file architecture:
|
||||||
* 1. Load nostr.bundle.js (official nostr-tools bundle)
|
* 1. Load nostr.bundle.js (official nostr-tools bundle)
|
||||||
* 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes)
|
* 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes)
|
||||||
* Generated on: 2025-09-14T20:06:51.995Z
|
* Generated on: 2025-09-15T17:48:16.817Z
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Verify dependencies are loaded
|
// Verify dependencies are loaded
|
||||||
@@ -2401,10 +2401,8 @@ class NostrLite {
|
|||||||
// Apply the selected theme (CSS-only)
|
// Apply the selected theme (CSS-only)
|
||||||
this.switchTheme(this.options.theme);
|
this.switchTheme(this.options.theme);
|
||||||
|
|
||||||
// Set up window.nostr facade if no extension detected
|
// Always set up window.nostr facade to handle multiple extensions properly
|
||||||
if (this.extensionBridge.getExtensionCount() === 0) {
|
|
||||||
this._setupWindowNostrFacade();
|
this._setupWindowNostrFacade();
|
||||||
}
|
|
||||||
|
|
||||||
// Create modal during init (matching original git architecture)
|
// Create modal during init (matching original git architecture)
|
||||||
this.modal = new Modal(this.options);
|
this.modal = new Modal(this.options);
|
||||||
@@ -2423,9 +2421,14 @@ class NostrLite {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_setupWindowNostrFacade() {
|
_setupWindowNostrFacade() {
|
||||||
if (typeof window !== 'undefined' && !window.nostr) {
|
if (typeof window !== 'undefined') {
|
||||||
window.nostr = new WindowNostr(this);
|
// Store existing window.nostr if it exists (from extensions)
|
||||||
console.log('NOSTR_LOGIN_LITE: window.nostr facade installed');
|
const existingNostr = window.nostr;
|
||||||
|
|
||||||
|
// Always install our facade
|
||||||
|
window.nostr = new WindowNostr(this, existingNostr);
|
||||||
|
console.log('NOSTR_LOGIN_LITE: window.nostr facade installed',
|
||||||
|
existingNostr ? '(with extension passthrough)' : '(no existing extension)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2539,45 +2542,313 @@ class NostrLite {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window.nostr facade for when no extension is available
|
// NIP-07 compliant window.nostr provider
|
||||||
class WindowNostr {
|
class WindowNostr {
|
||||||
constructor(nostrLite) {
|
constructor(nostrLite, existingNostr = null) {
|
||||||
this.nostrLite = nostrLite;
|
this.nostrLite = nostrLite;
|
||||||
|
this.authState = null;
|
||||||
|
this.existingNostr = existingNostr;
|
||||||
|
this.authenticatedExtension = null;
|
||||||
|
this._setupEventListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
_setupEventListeners() {
|
||||||
|
// Listen for authentication events to store auth state
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
window.addEventListener('nlMethodSelected', (event) => {
|
||||||
|
this.authState = event.detail;
|
||||||
|
|
||||||
|
// If extension method, capture the specific extension the user chose
|
||||||
|
if (event.detail.method === 'extension') {
|
||||||
|
this.authenticatedExtension = event.detail.extension;
|
||||||
|
console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name);
|
||||||
|
|
||||||
|
// Re-install our facade to ensure we intercept signEvent calls
|
||||||
|
// Extensions may overwrite window.nostr after authentication
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
console.log('WindowNostr: Re-installing facade after authentication');
|
||||||
|
window.nostr = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('WindowNostr: Auth state updated:', this.authState?.method);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('nlLogout', () => {
|
||||||
|
this.authState = null;
|
||||||
|
this.authenticatedExtension = null;
|
||||||
|
console.log('WindowNostr: Auth state cleared');
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPublicKey() {
|
async getPublicKey() {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension':
|
||||||
|
// Use the captured authenticated extension, not current window.nostr
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.getPublicKey();
|
||||||
|
|
||||||
|
case 'local':
|
||||||
|
case 'nip46':
|
||||||
|
return this.authState.pubkey;
|
||||||
|
|
||||||
|
case 'readonly':
|
||||||
|
throw new Error('Read-only mode - cannot get public key');
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported auth method: ${this.authState.method}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async signEvent(event) {
|
async signEvent(event) {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot sign events');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension':
|
||||||
|
// Use the captured authenticated extension, not current window.nostr
|
||||||
|
console.log('WindowNostr: signEvent - authenticatedExtension:', this.authenticatedExtension);
|
||||||
|
console.log('WindowNostr: signEvent - authState.extension:', this.authState.extension);
|
||||||
|
console.log('WindowNostr: signEvent - existingNostr:', this.existingNostr);
|
||||||
|
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
console.log('WindowNostr: signEvent - using extension:', ext);
|
||||||
|
console.log('WindowNostr: signEvent - extension constructor:', ext?.constructor?.name);
|
||||||
|
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.signEvent(event);
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
// Use nostr-tools to sign with local secret key
|
||||||
|
const { nip19, finalizeEvent } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
// Convert hex to Uint8Array
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalizeEvent(event, secretKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
// Use BunkerSigner for NIP-46
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.signEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported auth method: ${this.authState.method}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRelays() {
|
async getRelays() {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
// Return configured relays from nostr-lite options
|
||||||
|
return this.nostrLite.options?.relays || ['wss://relay.damus.io'];
|
||||||
}
|
}
|
||||||
|
|
||||||
get nip04() {
|
get nip04() {
|
||||||
return {
|
return {
|
||||||
async encrypt(pubkey, plaintext) {
|
encrypt: async (pubkey, plaintext) => {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot encrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip04.encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip04, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await nip04.encrypt(secretKey, pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip04Encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported auth method: ${this.authState.method}`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async decrypt(pubkey, ciphertext) {
|
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
decrypt: async (pubkey, ciphertext) => {
|
||||||
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot decrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip04.decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip04, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return await nip04.decrypt(secretKey, pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip04Decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported auth method: ${this.authState.method}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get nip44() {
|
get nip44() {
|
||||||
return {
|
return {
|
||||||
async encrypt(pubkey, plaintext) {
|
encrypt: async (pubkey, plaintext) => {
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot encrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip44.encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip44, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nip44.encrypt(plaintext, nip44.getConversationKey(secretKey, pubkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip44Encrypt(pubkey, plaintext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported auth method: ${this.authState.method}`);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async decrypt(pubkey, ciphertext) {
|
|
||||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
decrypt: async (pubkey, ciphertext) => {
|
||||||
|
if (!this.authState) {
|
||||||
|
throw new Error('Not authenticated - use NOSTR_LOGIN_LITE.launch()');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.authState.method === 'readonly') {
|
||||||
|
throw new Error('Read-only mode - cannot decrypt');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.authState.method) {
|
||||||
|
case 'extension': {
|
||||||
|
const ext = this.authenticatedExtension || this.authState.extension || this.existingNostr;
|
||||||
|
if (!ext) throw new Error('Extension not available');
|
||||||
|
return await ext.nip44.decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'local': {
|
||||||
|
const { nip44, nip19 } = window.NostrTools;
|
||||||
|
let secretKey;
|
||||||
|
|
||||||
|
if (this.authState.secret.startsWith('nsec')) {
|
||||||
|
const decoded = nip19.decode(this.authState.secret);
|
||||||
|
secretKey = decoded.data;
|
||||||
|
} else {
|
||||||
|
secretKey = this._hexToUint8Array(this.authState.secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nip44.decrypt(ciphertext, nip44.getConversationKey(secretKey, pubkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'nip46': {
|
||||||
|
if (!this.authState.signer?.bunkerSigner) {
|
||||||
|
throw new Error('NIP-46 signer not available');
|
||||||
|
}
|
||||||
|
return await this.authState.signer.bunkerSigner.nip44Decrypt(pubkey, ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported auth method: ${this.authState.method}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_hexToUint8Array(hex) {
|
||||||
|
if (hex.length % 2 !== 0) {
|
||||||
|
throw new Error('Invalid hex string length');
|
||||||
|
}
|
||||||
|
const bytes = new Uint8Array(hex.length / 2);
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize and export
|
// Initialize and export
|
||||||
|
|||||||
Reference in New Issue
Block a user