@@ -21,12 +21,11 @@ import {
2121import { sha256 } from '@noble/hashes/sha256' ;
2222import { bytesToHex } from '@noble/hashes/utils' ;
2323
24- console . log ( '[Podkey] Background service worker started' ) ;
24+ // Set DEBUG=true to emit verbose diagnostics. Off by default so the extension
25+ // never logs public keys, DIDs, NIP-98 events, or Authorization headers.
26+ const DEBUG = false ;
2527
26- // NIP-98 events are always created fresh to avoid replay issues
27-
28- // Track retry state to prevent infinite loops: key = requestId, value = true
29- const retryState = new Map ( ) ;
28+ if ( DEBUG ) console . log ( '[Podkey] Background service worker started' ) ;
3029
3130// Initialize extension
3231chrome . runtime . onInstalled . addListener ( async ( ) => {
@@ -57,7 +56,9 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
5756
5857 handleMessage ( message , sender )
5958 . then ( result => {
60- console . log ( '[Podkey] Message handled successfully:' , message . type , result ) ;
59+ // Never log `result`: it may be a public key, signed event, or
60+ // Authorization header (token). Log only the message type under DEBUG.
61+ if ( DEBUG ) console . log ( '[Podkey] Message handled:' , message . type ) ;
6162 sendResponse ( result ) ;
6263 } )
6364 . catch ( error => {
@@ -74,7 +75,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
7475async function handleMessage ( message , sender ) {
7576 const { type, origin } = message ;
7677
77- console . log ( '[Podkey] Message received:' , type , 'from' , origin || 'popup' ) ;
78+ if ( DEBUG ) console . log ( '[Podkey] Message received:' , type , 'from' , origin || 'popup' ) ;
7879
7980 switch ( type ) {
8081 case 'GET_PUBLIC_KEY' :
@@ -92,14 +93,6 @@ async function handleMessage (message, sender) {
9293 case 'GET_KEYPAIR_STATUS' :
9394 return await handleGetKeypairStatus ( ) ;
9495
95- case 'GET_RELAYS' :
96- // TODO: Implement relay management
97- return { } ;
98-
99- case 'NIP04_ENCRYPT' :
100- case 'NIP04_DECRYPT' :
101- throw new Error ( 'NIP-04 encryption not yet implemented' ) ;
102-
10396 case 'NIP44_ENCRYPT' :
10497 return await handleNip44Encrypt ( message . pubkey , message . plaintext , origin ) ;
10598
@@ -113,7 +106,8 @@ async function handleMessage (message, sender) {
113106 return await createNip98AuthHeader (
114107 message . url ,
115108 message . method ,
116- message . body
109+ message . body ,
110+ message . bodyHash
117111 ) ;
118112
119113 default :
@@ -196,7 +190,7 @@ async function handleSignEvent (event, origin, sender) {
196190 // Sign the event
197191 const signedEvent = await signEvent ( event , keypair . privateKey ) ;
198192
199- console . log ( '[Podkey] Event signed:' , signedEvent . id . substring ( 0 , 16 ) + '...' ) ;
193+ if ( DEBUG ) console . log ( '[Podkey] Event signed:' , signedEvent . id . substring ( 0 , 16 ) + '...' ) ;
200194
201195 // Ensure event structure is correct (tags should be array, content should be string)
202196 // Preserve original event structure but ensure required fields are correct types
@@ -298,23 +292,14 @@ async function handleNip44GetConversationKey (peerPubkey, origin) {
298292 */
299293async function handleGenerateKeypair ( ) {
300294 try {
301- console . log ( '[Podkey] Starting keypair generation...' ) ;
302295 const keypair = await generateKeypair ( ) ;
303- console . log ( '[Podkey] Keypair generated:' , {
304- privateKeyLength : keypair . privateKey . length ,
305- publicKeyLength : keypair . publicKey . length
306- } ) ;
307-
308296 await storeKeypair ( keypair . privateKey , keypair . publicKey ) ;
309- console . log ( '[Podkey] Keypair stored' ) ;
297+ if ( DEBUG ) console . log ( '[Podkey] Keypair generated and stored' ) ;
310298
311- const result = {
299+ return {
312300 publicKey : keypair . publicKey ,
313301 did : `did:nostr:${ keypair . publicKey } `
314302 } ;
315-
316- console . log ( '[Podkey] Returning result:' , result ) ;
317- return result ;
318303 } catch ( error ) {
319304 console . error ( '[Podkey] Error generating keypair:' , error ) ;
320305 throw error ;
@@ -340,7 +325,7 @@ async function handleImportKeypair (privateKey) {
340325 // Store keypair
341326 await storeKeypair ( privateKey , publicKey ) ;
342327
343- console . log ( '[Podkey] Keypair imported' ) ;
328+ if ( DEBUG ) console . log ( '[Podkey] Keypair imported' ) ;
344329
345330 return {
346331 publicKey,
@@ -415,29 +400,6 @@ async function showPermissionPrompt (origin, action, eventPreview) {
415400 } ) ;
416401}
417402
418- /**
419- * Format event for display in prompt
420- */
421- function formatEventForPrompt ( event ) {
422- const lines = [ ] ;
423- lines . push ( `Kind: ${ event . kind } ` ) ;
424-
425- if ( event . tags && event . tags . length > 0 ) {
426- lines . push ( `Tags: ${ event . tags . length } ` ) ;
427- event . tags . slice ( 0 , 3 ) . forEach ( tag => {
428- lines . push ( ` [${ tag . join ( ', ' ) } ]` ) ;
429- } ) ;
430- }
431-
432- if ( event . content ) {
433- const preview = event . content . substring ( 0 , 100 ) ;
434- lines . push ( `Content: ${ preview } ${ event . content . length > 100 ? '...' : '' } ` ) ;
435- }
436-
437- return lines . join ( '\n' ) ;
438- }
439-
440-
441403/**
442404 * Encode signed event to Authorization header value
443405 * @param {object } signedEvent - Signed Nostr event
@@ -482,7 +444,7 @@ function isLikelySolidServer (origin) {
482444 ) ;
483445}
484446
485- async function createNip98AuthHeader ( url , method , body = null ) {
447+ async function createNip98AuthHeader ( url , method , body = null , bodyHash = null ) {
486448 try {
487449 // Check if we should add auth
488450 const origin = new URL ( url ) . origin ;
@@ -491,73 +453,69 @@ async function createNip98AuthHeader (url, method, body = null) {
491453 const keyExists = await hasKeypair ( ) ;
492454 const isSolid = isLikelySolidServer ( origin ) ;
493455
494- console . log ( '[Podkey] NIP-98 auth check:' , {
495- url,
496- origin,
497- keyExists,
498- trusted,
499- autoSign,
500- isSolid
501- } ) ;
456+ if ( DEBUG ) console . log ( '[Podkey] NIP-98 auth check:' , { url, origin, keyExists, trusted, autoSign, isSolid } ) ;
502457
503458 if ( ! keyExists ) {
504- console . log ( '[Podkey] No keypair found, skipping NIP-98 auth' ) ;
459+ if ( DEBUG ) console . log ( '[Podkey] No keypair found, skipping NIP-98 auth' ) ;
505460 return null ;
506461 }
507462
508463 // For Solid servers, auto-trust on first use if auto-sign is enabled
509464 if ( ! trusted && isSolid && autoSign ) {
510- console . log ( '[Podkey] Auto-trusting Solid server:' , origin ) ;
465+ if ( DEBUG ) console . log ( '[Podkey] Auto-trusting Solid server:' , origin ) ;
511466 await addTrustedOrigin ( origin ) ;
512467 } else if ( ! trusted ) {
513- console . log ( '[Podkey] Origin not trusted, skipping NIP-98 auth' ) ;
468+ if ( DEBUG ) console . log ( '[Podkey] Origin not trusted, skipping NIP-98 auth' ) ;
514469 return null ;
515470 }
516471
517472 if ( ! autoSign ) {
518- console . log ( '[Podkey] Auto-sign disabled, skipping NIP-98 auth' ) ;
473+ if ( DEBUG ) console . log ( '[Podkey] Auto-sign disabled, skipping NIP-98 auth' ) ;
519474 return null ;
520475 }
521476
522- // Hash body if present
523- let bodyHash = '' ;
524- if ( body ) {
477+ // Prefer a body hash computed in the page context (the only place where
478+ // FormData / URLSearchParams / streamed bodies survive intact). Fall back
479+ // to hashing here for body types that cross the message channel losslessly.
480+ let resolvedBodyHash = typeof bodyHash === 'string' ? bodyHash : '' ;
481+ if ( ! resolvedBodyHash && body ) {
525482 if ( typeof body === 'string' ) {
526- bodyHash = bytesToHex ( sha256 ( new TextEncoder ( ) . encode ( body ) ) ) ;
483+ resolvedBodyHash = bytesToHex ( sha256 ( new TextEncoder ( ) . encode ( body ) ) ) ;
527484 } else if ( body instanceof ArrayBuffer ) {
528- bodyHash = bytesToHex ( sha256 ( new Uint8Array ( body ) ) ) ;
485+ resolvedBodyHash = bytesToHex ( sha256 ( new Uint8Array ( body ) ) ) ;
529486 } else if ( body instanceof Blob ) {
530- const arrayBuffer = await body . arrayBuffer ( ) ;
531- bodyHash = bytesToHex ( sha256 ( new Uint8Array ( arrayBuffer ) ) ) ;
487+ resolvedBodyHash = bytesToHex ( sha256 ( new Uint8Array ( await body . arrayBuffer ( ) ) ) ) ;
532488 }
533489 }
534490
535491 // Always create a fresh signed event (no caching -- reusing signed events
536- // causes replay issues and servers with replay protection reject duplicates)
492+ // causes replay issues and servers with replay protection reject them).
493+ // created_at has 1-second resolution, so a random nonce tag guarantees a
494+ // distinct event id for repeated identical requests within the same second.
537495 const event = {
538496 kind : 27235 ,
539497 content : '' ,
540498 created_at : Math . floor ( Date . now ( ) / 1000 ) ,
541499 tags : [
542500 [ 'u' , url ] ,
543- [ 'method' , method ]
501+ [ 'method' , method ] ,
502+ [ 'nonce' , bytesToHex ( crypto . getRandomValues ( new Uint8Array ( 16 ) ) ) ]
544503 ]
545504 } ;
546505
547- if ( bodyHash ) {
548- event . tags . push ( [ 'payload' , bodyHash ] ) ;
506+ if ( resolvedBodyHash ) {
507+ event . tags . push ( [ 'payload' , resolvedBodyHash ] ) ;
549508 }
550509
551510 const keypair = await getKeypair ( ) ;
552511 const signedEvent = await signEvent ( event , keypair . privateKey ) ;
553512
554- console . log ( '[Podkey] Created and signed NIP-98 auth event for' , url ) ;
555- console . log ( '[Podkey] NIP-98 event:' , JSON . stringify ( signedEvent , null , 2 ) ) ;
556- console . log ( '[Podkey] Public key (did:nostr):' , `did:nostr:${ keypair . publicKey } ` ) ;
513+ if ( DEBUG ) {
514+ console . log ( '[Podkey] NIP-98 event:' , JSON . stringify ( signedEvent ) ) ;
515+ console . log ( '[Podkey] Public key (did:nostr):' , `did:nostr:${ keypair . publicKey } ` ) ;
516+ }
557517
558- const authHeader = `Nostr ${ encodeNip98Header ( signedEvent ) } ` ;
559- console . log ( '[Podkey] Authorization header (first 100 chars):' , authHeader . substring ( 0 , 100 ) + '...' ) ;
560- return authHeader ;
518+ return `Nostr ${ encodeNip98Header ( signedEvent ) } ` ;
561519 } catch ( error ) {
562520 console . error ( '[Podkey] Error creating NIP-98 auth header:' , error ) ;
563521 return null ;
@@ -569,4 +527,4 @@ async function createNip98AuthHeader (url, method, body = null) {
569527// Instead, we use JavaScript-level interception via content scripts.
570528// See src/injected.js for fetch/XMLHttpRequest interception.
571529
572- console . log ( '[Podkey] NIP-98 auto-auth: Using JavaScript-level interception (see injected.js)' ) ;
530+ if ( DEBUG ) console . log ( '[Podkey] NIP-98 auto-auth: Using JavaScript-level interception (see injected.js)' ) ;
0 commit comments