Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
517974699d |
321
lite/build.js
321
lite/build.js
@@ -1093,10 +1093,8 @@ class NostrLite {
|
||||
// Apply the selected theme (CSS-only)
|
||||
this.switchTheme(this.options.theme);
|
||||
|
||||
// Set up window.nostr facade if no extension detected
|
||||
if (this.extensionBridge.getExtensionCount() === 0) {
|
||||
this._setupWindowNostrFacade();
|
||||
}
|
||||
// Always set up window.nostr facade to handle multiple extensions properly
|
||||
this._setupWindowNostrFacade();
|
||||
|
||||
// Create modal during init (matching original git architecture)
|
||||
this.modal = new Modal(this.options);
|
||||
@@ -1115,9 +1113,14 @@ class NostrLite {
|
||||
}
|
||||
|
||||
_setupWindowNostrFacade() {
|
||||
if (typeof window !== 'undefined' && !window.nostr) {
|
||||
window.nostr = new WindowNostr(this);
|
||||
console.log('NOSTR_LOGIN_LITE: window.nostr facade installed');
|
||||
if (typeof window !== 'undefined') {
|
||||
// Store existing window.nostr if it exists (from extensions)
|
||||
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 {
|
||||
constructor(nostrLite) {
|
||||
constructor(nostrLite, existingNostr = null) {
|
||||
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() {
|
||||
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) {
|
||||
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() {
|
||||
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() {
|
||||
return {
|
||||
async encrypt(pubkey, plaintext) {
|
||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
||||
encrypt: async (pubkey, plaintext) => {
|
||||
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() {
|
||||
return {
|
||||
async encrypt(pubkey, plaintext) {
|
||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
||||
encrypt: async (pubkey, plaintext) => {
|
||||
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
|
||||
|
||||
@@ -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: 2025-09-14T20:06:51.995Z
|
||||
* Generated on: 2025-09-15T17:48:16.817Z
|
||||
*/
|
||||
|
||||
// Verify dependencies are loaded
|
||||
@@ -2401,10 +2401,8 @@ class NostrLite {
|
||||
// Apply the selected theme (CSS-only)
|
||||
this.switchTheme(this.options.theme);
|
||||
|
||||
// Set up window.nostr facade if no extension detected
|
||||
if (this.extensionBridge.getExtensionCount() === 0) {
|
||||
this._setupWindowNostrFacade();
|
||||
}
|
||||
// Always set up window.nostr facade to handle multiple extensions properly
|
||||
this._setupWindowNostrFacade();
|
||||
|
||||
// Create modal during init (matching original git architecture)
|
||||
this.modal = new Modal(this.options);
|
||||
@@ -2423,9 +2421,14 @@ class NostrLite {
|
||||
}
|
||||
|
||||
_setupWindowNostrFacade() {
|
||||
if (typeof window !== 'undefined' && !window.nostr) {
|
||||
window.nostr = new WindowNostr(this);
|
||||
console.log('NOSTR_LOGIN_LITE: window.nostr facade installed');
|
||||
if (typeof window !== 'undefined') {
|
||||
// Store existing window.nostr if it exists (from extensions)
|
||||
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 {
|
||||
constructor(nostrLite) {
|
||||
constructor(nostrLite, existingNostr = null) {
|
||||
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() {
|
||||
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) {
|
||||
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() {
|
||||
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() {
|
||||
return {
|
||||
async encrypt(pubkey, plaintext) {
|
||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
||||
encrypt: async (pubkey, plaintext) => {
|
||||
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() {
|
||||
return {
|
||||
async encrypt(pubkey, plaintext) {
|
||||
throw new Error('Authentication required - use NOSTR_LOGIN_LITE.launch()');
|
||||
encrypt: async (pubkey, plaintext) => {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user