@@ -342,6 +342,16 @@ async function handleContentScriptMessage({ type, params, host, protocol }) {
342342
343343 return nip44 . v2 . decrypt ( ciphertext , key ) ;
344344 }
345+ case 'nip60.signSecret' : {
346+ if ( ! validateNut10Secret ( params . secret ) ) {
347+ return { error : { message : "invalid Cashu secret" } } ;
348+ }
349+ const utf8Encoder = new TextEncoder ( ) ;
350+ const hash = bytesToHex ( sha256 ( utf8Encoder . encode ( params . secret ) ) ) ;
351+ const sig = bytesToHex ( schnorr . sign ( hash , sk ) ) ;
352+ const pubkey = bytesToHex ( schnorr . getPublicKey ( sk ) ) ;
353+ return { hash : hash , sig : sig , pubkey : pubkey } ;
354+ }
345355 }
346356 } catch ( error ) {
347357 return {
@@ -350,6 +360,34 @@ async function handleContentScriptMessage({ type, params, host, protocol }) {
350360 }
351361}
352362
363+ function validateNut10Secret ( proof_secret ) {
364+ try {
365+ if ( typeof proof_secret !== 'string' ) return false ;
366+ const secret = JSON . parse ( proof_secret ) ;
367+ if ( ! Array . isArray ( secret ) || secret . length !== 2 ) return false ;
368+ const [ kind , payload ] = secret ;
369+ if ( typeof kind !== 'string' || ! kind . trim ( ) ) return false ;
370+ if ( ! payload || ! payload . nonce ?. trim ( ) || ! payload . data ?. trim ( ) ) return false ;
371+ if ( payload . tags ) {
372+ if ( ! Array . isArray ( payload . tags ) ) return false ;
373+ const year = new Date ( ) . getUTCFullYear ( ) ; // for deprecation check
374+ for ( const tag of payload . tags ) {
375+ if ( ! Array . isArray ( tag ) || tag . length < 2 ) return false ;
376+ // Some older secret tags may include integers (now deprecated)
377+ // Enforce strings only from 2026 onwards
378+ for ( const e of tag ) {
379+ if ( typeof e !== 'string' && ( year > 2025 || typeof e !== 'number' || ! Number . isInteger ( e ) ) ) {
380+ return false ;
381+ }
382+ }
383+ }
384+ }
385+ return true ;
386+ } catch {
387+ return false ;
388+ }
389+ }
390+
353391async function handlePromptMessage ( result , sender ) {
354392 // console.log("handlePromptMessage received " + JSON.stringify(result));
355393 const { host, type, accept, conditions, pubkey } = result ;
0 commit comments