1
+ using System . Text . Json ;
2
+ using System . Text . Json . Serialization ;
1
3
using System . Web ;
2
4
using NBitcoin . Secp256k1 ;
3
5
@@ -8,7 +10,7 @@ public static class NIP67
8
10
public static int EventKind = 33194 ;
9
11
public record NIP67UriPayload (
10
12
ECXOnlyPubKey Pubkey ,
11
- ECPrivKey Secret ,
13
+ string Secret ,
12
14
string [ ] Relays ,
13
15
string [ ] RequiredCommands ,
14
16
string [ ] OptionalCommands ,
@@ -18,7 +20,7 @@ public record NIP67UriPayload(
18
20
public override string ToString ( )
19
21
{
20
22
var result =
21
- $ "nostr+walletauth ://{ Pubkey . ToHex ( ) } ?relay={ string . Join ( "&relay=" , Relays ) } &secret={ Secret . CreateXOnlyPubKey ( ) . ToHex ( ) } &required_commands={ string . Join ( " " , RequiredCommands ) } ";
23
+ $ "{ UriScheme } ://{ Pubkey . ToHex ( ) } ?relay={ string . Join ( "&relay=" , Relays ) } &secret={ Secret } &required_commands={ string . Join ( " " , RequiredCommands ) } ";
22
24
23
25
if ( OptionalCommands . Length > 0 )
24
26
result += $ "&optional_commands={ string . Join ( " " , OptionalCommands ) } ";
@@ -37,15 +39,76 @@ public override string ToString()
37
39
38
40
public static NIP67UriPayload ParseUri ( Uri uri )
39
41
{
42
+ if ( ! uri . Scheme . Equals ( UriScheme , StringComparison . InvariantCultureIgnoreCase ) )
43
+ throw new ArgumentException ( "Invalid scheme" , nameof ( uri ) ) ;
40
44
var query = HttpUtility . ParseQueryString ( uri . Query ) ;
41
45
42
46
var relays = query . GetValues ( "relay" ) ?? Array . Empty < string > ( ) ;
43
- var secret = NostrExtensions . ParseKey ( query [ "secret" ] ) ;
47
+ var secret = query [ "secret" ] ;
44
48
var requiredCommands = query . GetValues ( "required_commands" ) ? . SelectMany ( s => s . Split ( " " ) ) . Distinct ( ) . ToArray ( ) ?? Array . Empty < string > ( ) ;
45
49
var optionalCommands = query . GetValues ( "optional_commands" ) ? . SelectMany ( s => s . Split ( " " ) ) . Distinct ( ) . ToArray ( ) ?? Array . Empty < string > ( ) ;
46
50
var budget = query . GetValues ( "budget" ) ? . FirstOrDefault ( ) ;
47
51
var identity = query . GetValues ( "identity" ) ? . FirstOrDefault ( ) ;
48
52
49
53
return new NIP67UriPayload ( NostrExtensions . ParsePubKey ( uri . Host ) , secret , relays , requiredCommands , optionalCommands , budget , identity ) ;
50
54
}
55
+
56
+ public record Nip67ConfirmationEventContent ( )
57
+ {
58
+ //format is :
59
+ /*
60
+ *{
61
+ "secret": "b8a30fafa48d4795b6c0eec169a383de", // string, the secret from the URI
62
+ "commands": [ // array of strings, commands that the wallet agrees to support
63
+ "pay_invoice",
64
+ "pay_keysend",
65
+ "make_invoice",
66
+ "lookup_invoice",
67
+ "list_transactions",
68
+ ],
69
+ "relay": "wss://relay.damus.io", // Optional string, alternative relay that the wallet will use
70
+ "lud16": "[email protected] ", // Optional string, user's lightning address
71
+ }
72
+ *
73
+ */
74
+ [ JsonPropertyName ( "secret" ) ]
75
+ public string Secret { get ; set ; }
76
+
77
+ [ JsonPropertyName ( "commands" ) ]
78
+ public string [ ] Commands { get ; set ; }
79
+ [ JsonPropertyName ( "relay" ) ]
80
+ [ JsonIgnore ( Condition = JsonIgnoreCondition . WhenWritingNull ) ]
81
+ public string ? Relay { get ; set ; }
82
+ [ JsonPropertyName ( "lud16" ) ]
83
+ [ JsonIgnore ( Condition = JsonIgnoreCondition . WhenWritingNull ) ]
84
+ public string ? Lud16 { get ; set ; }
85
+
86
+
87
+ }
88
+ public static async Task < NostrEvent > ConstructNip67ConfirmationEvent ( NIP67UriPayload payload , Nip67ConfirmationEventContent conf , ECPrivKey key )
89
+ {
90
+ var confirmationEvent = new NostrEvent ( )
91
+ {
92
+ Kind = EventKind ,
93
+ Content = JsonSerializer . Serialize ( conf ) ,
94
+
95
+ } . SetTag ( "d" , payload . Pubkey . ToHex ( ) ) ;
96
+ await confirmationEvent . EncryptNip04EventAsync ( key , null , true ) ;
97
+ return confirmationEvent ;
98
+ }
99
+
100
+ public static async Task < ( Uri Nip47Url , Nip67ConfirmationEventContent Nip67Payload ) > Nip47FromNip67Event ( NostrEvent e , ECPrivKey key , Uri ? relay = null )
101
+ {
102
+ if ( e . Kind != EventKind )
103
+ throw new ArgumentException ( "Invalid event kind" , nameof ( e ) ) ;
104
+
105
+ var content = await e . DecryptNip04EventAsync ( key , null , true ) ;
106
+
107
+ var payload = JsonSerializer . Deserialize < Nip67ConfirmationEventContent > ( content ) ;
108
+ relay ??= new Uri ( payload . Relay ?? throw new ArgumentException ( "Relay is required" ) ) ;
109
+
110
+ return ( NIP47 . CreateUri ( e . GetPublicKey ( ) , key , relay , lud16 : payload . Lud16 ) , payload ) ;
111
+ }
112
+
113
+
51
114
}
0 commit comments