Support CAT token in bunker URLs for NIP-46 connections (v0.2.2)
- Add 'bunker' to SignerType with isRemote getter and displayName - Parse CAT token from bunker URL (?cat= parameter) - Pass CAT token to BunkerSigner constructor - Store bunkerCatToken in account for reconnection - Add deploy command documentation Files modified: - src/domain/identity/SignerType.ts: Add bunker signer type - src/providers/NostrProvider/bunker.signer.ts: Parse and use CAT tokens - src/providers/NostrProvider/index.tsx: Pass CAT to login/reconnect - src/types/index.d.ts: Add bunkerCatToken to TAccount 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,12 +59,13 @@ function generateRequestId(): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a bunker URL (bunker://<pubkey>?relay=<url>&secret=<secret>).
|
||||
* Parse a bunker URL (bunker://<pubkey>?relay=<url>&secret=<secret>&cat=<token>).
|
||||
*/
|
||||
export function parseBunkerUrl(url: string): {
|
||||
pubkey: string
|
||||
relays: string[]
|
||||
secret?: string
|
||||
catToken?: string
|
||||
} {
|
||||
if (!url.startsWith('bunker://')) {
|
||||
throw new Error('Invalid bunker URL: must start with bunker://')
|
||||
@@ -80,6 +81,7 @@ export function parseBunkerUrl(url: string): {
|
||||
const params = new URLSearchParams(queryPart || '')
|
||||
const relays = params.getAll('relay')
|
||||
const secret = params.get('secret') || undefined
|
||||
const catToken = params.get('cat') || undefined
|
||||
|
||||
if (relays.length === 0) {
|
||||
throw new Error('Invalid bunker URL: no relay specified')
|
||||
@@ -88,7 +90,8 @@ export function parseBunkerUrl(url: string): {
|
||||
return {
|
||||
pubkey: pubkeyPart,
|
||||
relays,
|
||||
secret
|
||||
secret,
|
||||
catToken
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,19 +178,28 @@ export class BunkerSigner implements ISigner {
|
||||
// Whether we're waiting for signer to connect (reverse flow)
|
||||
private awaitingConnection = false
|
||||
private connectionResolve: ((pubkey: string) => void) | null = null
|
||||
private connectionReject: ((error: Error) => void) | null = null
|
||||
|
||||
/**
|
||||
* Create a BunkerSigner.
|
||||
* @param bunkerPubkey - The bunker's public key (hex)
|
||||
* @param relayUrls - Relay URLs to connect to
|
||||
* @param connectionSecret - Optional connection secret for initial handshake
|
||||
* @param catToken - Optional CAT token (encoded string) for authorization
|
||||
*/
|
||||
constructor(bunkerPubkey: string, relayUrls: string[], connectionSecret?: string) {
|
||||
constructor(bunkerPubkey: string, relayUrls: string[], connectionSecret?: string, catToken?: string) {
|
||||
this.bunkerPubkey = bunkerPubkey
|
||||
this.relayUrls = relayUrls
|
||||
this.connectionSecret = connectionSecret
|
||||
|
||||
// Decode CAT token if provided
|
||||
if (catToken) {
|
||||
try {
|
||||
this.token = cashuTokenService.decodeToken(catToken)
|
||||
} catch (err) {
|
||||
console.warn('Failed to decode CAT token from URL:', err)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate local ephemeral keypair for NIP-46 communication
|
||||
this.localPrivkey = secp256k1.utils.randomPrivateKey()
|
||||
this.localPubkey = nGetPublicKey(this.localPrivkey)
|
||||
@@ -230,8 +242,6 @@ export class BunkerSigner implements ISigner {
|
||||
signer.awaitingConnection = false
|
||||
resolve(signer)
|
||||
}
|
||||
signer.connectionReject = reject
|
||||
|
||||
// Set timeout
|
||||
setTimeout(() => {
|
||||
if (signer.awaitingConnection) {
|
||||
@@ -407,7 +417,7 @@ export class BunkerSigner implements ISigner {
|
||||
return
|
||||
}
|
||||
|
||||
const mintInfo = await infoResponse.json()
|
||||
await infoResponse.json() // Validate JSON response
|
||||
console.log(`Relay ${relayUrl} requires Cashu token, acquiring...`)
|
||||
|
||||
// Configure the mint
|
||||
|
||||
Reference in New Issue
Block a user