Refactor Nostr auth service

This commit is contained in:
2026-04-20 12:34:44 +04:00
parent c57a665655
commit 1dc0c4119b
3 changed files with 117 additions and 112 deletions

View File

@@ -15,7 +15,7 @@ export default class NostrConnectComponent extends Component {
@action @action
async connectExtension() { async connectExtension() {
try { try {
await this.nostrAuth.login('extension'); await this.nostrAuth.connectWithExtension();
if (this.args.onConnect) { if (this.args.onConnect) {
this.args.onConnect(); this.args.onConnect();
} }
@@ -28,7 +28,7 @@ export default class NostrConnectComponent extends Component {
@action @action
async connectApp() { async connectApp() {
try { try {
await this.nostrAuth.login('connect'); await this.nostrAuth.connectWithApp();
if (this.args.onConnect) { if (this.args.onConnect) {
this.args.onConnect(); this.args.onConnect();
} }

View File

@@ -48,7 +48,7 @@ export default class UserMenuComponent extends Component {
@action @action
disconnectNostr() { disconnectNostr() {
this.nostrAuth.logout(); this.nostrAuth.disconnect();
} }
<template> <template>

View File

@@ -12,6 +12,8 @@ const STORAGE_KEY_CONNECT_LOCAL_KEY = 'marco:nostr_connect_local_key';
const STORAGE_KEY_CONNECT_REMOTE_PUBKEY = 'marco:nostr_connect_remote_pubkey'; const STORAGE_KEY_CONNECT_REMOTE_PUBKEY = 'marco:nostr_connect_remote_pubkey';
const STORAGE_KEY_CONNECT_RELAY = 'marco:nostr_connect_relay'; const STORAGE_KEY_CONNECT_RELAY = 'marco:nostr_connect_relay';
const DEFAULT_CONNECT_RELAY = 'wss://relay.nsec.app';
export default class NostrAuthService extends Service { export default class NostrAuthService extends Service {
@service nostrRelay; @service nostrRelay;
@@ -44,7 +46,7 @@ export default class NostrAuthService extends Service {
async _verifyPubkey() { async _verifyPubkey() {
if (this.signerType === 'extension') { if (this.signerType === 'extension') {
if (typeof window.nostr === 'undefined') { if (typeof window.nostr === 'undefined') {
this.logout(); this.disconnect();
return; return;
} }
try { try {
@@ -56,14 +58,14 @@ export default class NostrAuthService extends Service {
} }
} catch (e) { } catch (e) {
console.warn('Failed to verify extension nostr pubkey, logging out', e); console.warn('Failed to verify extension nostr pubkey, logging out', e);
this.logout(); this.disconnect();
} }
} else if (this.signerType === 'connect') { } else if (this.signerType === 'connect') {
try { try {
await this._initConnectSigner(); await this._initConnectSigner();
} catch (e) { } catch (e) {
console.warn('Failed to verify connect nostr pubkey, logging out', e); console.warn('Failed to verify connect nostr pubkey, logging out', e);
this.logout(); this.disconnect();
} }
} }
} }
@@ -99,8 +101,7 @@ export default class NostrAuthService extends Service {
return null; return null;
} }
async login(type = 'extension') { async connectWithExtension() {
if (type === 'extension') {
if (typeof window.nostr === 'undefined') { if (typeof window.nostr === 'undefined') {
throw new Error('No NIP-07 Nostr extension found (e.g., Alby, nos2x).'); throw new Error('No NIP-07 Nostr extension found (e.g., Alby, nos2x).');
} }
@@ -116,11 +117,9 @@ export default class NostrAuthService extends Service {
console.error('Failed to get public key from extension:', error); console.error('Failed to get public key from extension:', error);
throw error; throw error;
} }
} else if (type === 'connect') { }
this.connectStatus = 'waiting';
try { _getLocalSigner() {
// Generate or retrieve a local ephemeral keypair
let localKeyHex = localStorage.getItem(STORAGE_KEY_CONNECT_LOCAL_KEY); let localKeyHex = localStorage.getItem(STORAGE_KEY_CONNECT_LOCAL_KEY);
let localSigner; let localSigner;
if (localKeyHex) { if (localKeyHex) {
@@ -133,9 +132,17 @@ export default class NostrAuthService extends Service {
.join(''); .join('');
localStorage.setItem(STORAGE_KEY_CONNECT_LOCAL_KEY, localKeyHex); localStorage.setItem(STORAGE_KEY_CONNECT_LOCAL_KEY, localKeyHex);
} }
return localSigner;
}
async connectWithApp() {
this.connectStatus = 'waiting';
try {
const localSigner = this._getLocalSigner();
// We use a specific relay for the connection handshake. // We use a specific relay for the connection handshake.
const relay = 'wss://relay.nsec.app'; const relay = DEFAULT_CONNECT_RELAY;
localStorage.setItem(STORAGE_KEY_CONNECT_RELAY, relay); localStorage.setItem(STORAGE_KEY_CONNECT_RELAY, relay);
// Override aggressive 10s EOSE timeout to allow time for QR scanning // Override aggressive 10s EOSE timeout to allow time for QR scanning
@@ -207,21 +214,19 @@ export default class NostrAuthService extends Service {
throw error; throw error;
} }
} }
}
async _initConnectSigner() { async _initConnectSigner() {
const localKeyHex = localStorage.getItem(STORAGE_KEY_CONNECT_LOCAL_KEY);
const remotePubkey = localStorage.getItem( const remotePubkey = localStorage.getItem(
STORAGE_KEY_CONNECT_REMOTE_PUBKEY STORAGE_KEY_CONNECT_REMOTE_PUBKEY
); );
const relay = const relay =
localStorage.getItem(STORAGE_KEY_CONNECT_RELAY) || 'wss://relay.nsec.app'; localStorage.getItem(STORAGE_KEY_CONNECT_RELAY) || DEFAULT_CONNECT_RELAY;
if (!localKeyHex || !remotePubkey) { if (!remotePubkey) {
throw new Error('Missing Nostr Connect local state.'); throw new Error('Missing Nostr Connect remote pubkey.');
} }
const localSigner = PrivateKeySigner.fromKey(localKeyHex); const localSigner = this._getLocalSigner();
// Override aggressive 10s EOSE timeout to allow time for QR scanning // Override aggressive 10s EOSE timeout to allow time for QR scanning
this.nostrRelay.pool.relay(relay).eoseTimeout = 180000; // 3 minutes this.nostrRelay.pool.relay(relay).eoseTimeout = 180000; // 3 minutes
@@ -259,7 +264,7 @@ export default class NostrAuthService extends Service {
return await this.signer.signEvent(event); return await this.signer.signEvent(event);
} }
async logout() { async disconnect() {
this.pubkey = null; this.pubkey = null;
this.signerType = null; this.signerType = null;
this.connectStatus = null; this.connectStatus = null;