create_connection_controller_test.go raw
1 package controllers
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "testing"
8
9 "github.com/getAlby/go-nostr"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12
13 "github.com/getAlby/hub/apps"
14 "github.com/getAlby/hub/config"
15 "github.com/getAlby/hub/constants"
16 "github.com/getAlby/hub/db"
17 "github.com/getAlby/hub/nip47/models"
18 "github.com/getAlby/hub/tests"
19 )
20
21 func TestHandleCreateConnectionEvent(t *testing.T) {
22 ctx := context.TODO()
23 svc, err := tests.CreateTestService(t)
24 require.NoError(t, err)
25 defer svc.Remove()
26 svc.Cfg.SetUpdate("LNBackendType", config.LDKBackendType, "")
27
28 pairingSecretKey := nostr.GeneratePrivateKey()
29 pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
30 require.NoError(t, err)
31
32 nip47CreateConnectionJson := fmt.Sprintf(`
33 {
34 "method": "create_connection",
35 "params": {
36 "pubkey": "%s",
37 "name": "Test 123",
38 "request_methods": ["get_info", "pay_invoice"],
39 "notification_types": ["payment_received"],
40 "max_amount": 100000000,
41 "budget_renewal": "monthly",
42 "isolated": true
43 }
44 }
45 `, pairingPublicKey)
46
47 nip47Request := &models.Request{}
48 err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
49 assert.NoError(t, err)
50
51 dbRequestEvent := &db.RequestEvent{}
52 err = svc.DB.Create(&dbRequestEvent).Error
53 assert.NoError(t, err)
54
55 var publishedResponse *models.Response
56
57 publishResponse := func(response *models.Response, tags nostr.Tags) {
58 publishedResponse = response
59 }
60
61 NewTestNip47Controller(svc).
62 HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
63
64 assert.Nil(t, publishedResponse.Error)
65 assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
66 createAppResult := publishedResponse.Result.(createConnectionResponse)
67
68 assert.NotNil(t, createAppResult.WalletPubkey)
69 app := db.App{}
70 err = svc.DB.First(&app).Error
71 assert.NoError(t, err)
72 assert.Equal(t, pairingPublicKey, app.AppPubkey)
73 assert.Equal(t, createAppResult.WalletPubkey, *app.WalletPubkey)
74
75 permissions := []db.AppPermission{}
76 err = svc.DB.Find(&permissions).Error
77 assert.NoError(t, err)
78 assert.Equal(t, 3, len(permissions))
79 assert.Equal(t, constants.GET_INFO_SCOPE, permissions[0].Scope)
80 assert.Equal(t, constants.PAY_INVOICE_SCOPE, permissions[1].Scope)
81 assert.Equal(t, constants.NOTIFICATIONS_SCOPE, permissions[2].Scope)
82
83 assert.True(t, app.Isolated)
84 assert.Equal(t, 100_000, permissions[1].MaxAmountSat)
85 assert.Equal(t, constants.BUDGET_RENEWAL_MONTHLY, permissions[1].BudgetRenewal)
86 }
87
88 func TestHandleCreateConnectionEvent_IsolatedUnsupportedBackendType(t *testing.T) {
89 ctx := context.TODO()
90 svc, err := tests.CreateTestService(t)
91 require.NoError(t, err)
92 defer svc.Remove()
93 svc.Cfg.SetUpdate("BackendType", config.CashuBackendType, "")
94
95 pairingSecretKey := nostr.GeneratePrivateKey()
96 pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
97 require.NoError(t, err)
98
99 nip47CreateConnectionJson := fmt.Sprintf(`
100 {
101 "method": "create_connection",
102 "params": {
103 "pubkey": "%s",
104 "name": "Test 123",
105 "request_methods": ["get_info", "pay_invoice"],
106 "notification_types": ["payment_received"],
107 "max_amount": 100000000,
108 "budget_renewal": "monthly",
109 "isolated": true
110 }
111 }
112 `, pairingPublicKey)
113
114 nip47Request := &models.Request{}
115 err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
116 assert.NoError(t, err)
117
118 dbRequestEvent := &db.RequestEvent{}
119 err = svc.DB.Create(&dbRequestEvent).Error
120 assert.NoError(t, err)
121
122 var publishedResponse *models.Response
123
124 publishResponse := func(response *models.Response, tags nostr.Tags) {
125 publishedResponse = response
126 }
127
128 NewTestNip47Controller(svc).
129 HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
130
131 assert.NotNil(t, publishedResponse.Error)
132 assert.Equal(t, constants.ERROR_INTERNAL, publishedResponse.Error.Code)
133 assert.Equal(t, "sub-wallets are currently not supported on your node backend. Try LDK, LND, PHOENIX, BARK, or CLN", publishedResponse.Error.Message)
134 assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
135 }
136
137 func TestHandleCreateConnectionEvent_PubkeyAlreadyExists(t *testing.T) {
138 ctx := context.TODO()
139 svc, err := tests.CreateTestService(t)
140 require.NoError(t, err)
141 defer svc.Remove()
142
143 pairingSecretKey := nostr.GeneratePrivateKey()
144 pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
145 require.NoError(t, err)
146
147 appsSvc := apps.NewAppsService(svc.DB, svc.EventPublisher, svc.Keys, svc.Cfg)
148 _, _, err = appsSvc.CreateApp("Existing App", pairingPublicKey, 0, constants.BUDGET_RENEWAL_NEVER, nil, []string{models.GET_INFO_METHOD}, false, nil)
149
150 nip47CreateConnectionJson := fmt.Sprintf(`
151 {
152 "method": "create_connection",
153 "params": {
154 "pubkey": "%s",
155 "name": "Test 123",
156 "request_methods": ["get_info"]
157 }
158 }
159 `, pairingPublicKey)
160
161 nip47Request := &models.Request{}
162 err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
163 assert.NoError(t, err)
164
165 dbRequestEvent := &db.RequestEvent{}
166 err = svc.DB.Create(&dbRequestEvent).Error
167 assert.NoError(t, err)
168
169 var publishedResponse *models.Response
170
171 publishResponse := func(response *models.Response, tags nostr.Tags) {
172 publishedResponse = response
173 }
174
175 NewTestNip47Controller(svc).
176 HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
177
178 assert.NotNil(t, publishedResponse.Error)
179 assert.Equal(t, constants.ERROR_INTERNAL, publishedResponse.Error.Code)
180 assert.Equal(t, "duplicated key not allowed", publishedResponse.Error.Message)
181 assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
182 assert.Nil(t, publishedResponse.Result)
183 }
184
185 func TestHandleCreateConnectionEvent_NoMethods(t *testing.T) {
186 ctx := context.TODO()
187 svc, err := tests.CreateTestService(t)
188 require.NoError(t, err)
189 defer svc.Remove()
190
191 pairingSecretKey := nostr.GeneratePrivateKey()
192 pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
193 require.NoError(t, err)
194
195 nip47CreateConnectionJson := fmt.Sprintf(`
196 {
197 "method": "create_connection",
198 "params": {
199 "pubkey": "%s",
200 "name": "Test 123"
201 }
202 }
203 `, pairingPublicKey)
204
205 nip47Request := &models.Request{}
206 err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
207 assert.NoError(t, err)
208
209 dbRequestEvent := &db.RequestEvent{}
210 err = svc.DB.Create(&dbRequestEvent).Error
211 assert.NoError(t, err)
212
213 var publishedResponse *models.Response
214
215 publishResponse := func(response *models.Response, tags nostr.Tags) {
216 publishedResponse = response
217 }
218
219 NewTestNip47Controller(svc).
220 HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
221
222 assert.NotNil(t, publishedResponse.Error)
223 assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
224 assert.Equal(t, "No request methods provided", publishedResponse.Error.Message)
225 assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
226 assert.Nil(t, publishedResponse.Result)
227 }
228
229 func TestHandleCreateConnectionEvent_UnsupportedMethod(t *testing.T) {
230 ctx := context.TODO()
231 svc, err := tests.CreateTestService(t)
232 require.NoError(t, err)
233 defer svc.Remove()
234
235 pairingSecretKey := nostr.GeneratePrivateKey()
236 pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
237 require.NoError(t, err)
238
239 nip47CreateConnectionJson := fmt.Sprintf(`
240 {
241 "method": "create_connection",
242 "params": {
243 "pubkey": "%s",
244 "name": "Test 123",
245 "request_methods": ["non_existent"]
246 }
247 }
248 `, pairingPublicKey)
249
250 nip47Request := &models.Request{}
251 err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
252 assert.NoError(t, err)
253
254 dbRequestEvent := &db.RequestEvent{}
255 err = svc.DB.Create(&dbRequestEvent).Error
256 assert.NoError(t, err)
257
258 var publishedResponse *models.Response
259
260 publishResponse := func(response *models.Response, tags nostr.Tags) {
261 publishedResponse = response
262 }
263
264 NewTestNip47Controller(svc).
265 HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
266
267 assert.NotNil(t, publishedResponse.Error)
268 assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
269 assert.Equal(t, "One or more methods are not supported by the current LNClient", publishedResponse.Error.Message)
270 assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
271 assert.Nil(t, publishedResponse.Result)
272 }
273
274 func TestHandleCreateConnectionEvent_UnsupportedNotificationType(t *testing.T) {
275 ctx := context.TODO()
276 svc, err := tests.CreateTestService(t)
277 require.NoError(t, err)
278 defer svc.Remove()
279
280 pairingSecretKey := nostr.GeneratePrivateKey()
281 pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
282 require.NoError(t, err)
283
284 nip47CreateConnectionJson := fmt.Sprintf(`
285 {
286 "method": "create_connection",
287 "params": {
288 "pubkey": "%s",
289 "name": "Test 123",
290 "request_methods": ["get_info"],
291 "notification_types": ["non_existent"]
292 }
293 }
294 `, pairingPublicKey)
295
296 nip47Request := &models.Request{}
297 err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
298 assert.NoError(t, err)
299
300 dbRequestEvent := &db.RequestEvent{}
301 err = svc.DB.Create(&dbRequestEvent).Error
302 assert.NoError(t, err)
303
304 var publishedResponse *models.Response
305
306 publishResponse := func(response *models.Response, tags nostr.Tags) {
307 publishedResponse = response
308 }
309
310 NewTestNip47Controller(svc).
311 HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
312
313 assert.NotNil(t, publishedResponse.Error)
314 assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
315 assert.Equal(t, "One or more notification types are not supported by the current LNClient", publishedResponse.Error.Message)
316 assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
317 assert.Nil(t, publishedResponse.Result)
318 }
319
320 func TestHandleCreateConnectionEvent_DoNotAllowCreateConnectionMethod(t *testing.T) {
321 ctx := context.TODO()
322 svc, err := tests.CreateTestService(t)
323 require.NoError(t, err)
324 defer svc.Remove()
325
326 pairingSecretKey := nostr.GeneratePrivateKey()
327 pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
328 require.NoError(t, err)
329
330 nip47CreateConnectionJson := fmt.Sprintf(`
331 {
332 "method": "create_connection",
333 "params": {
334 "pubkey": "%s",
335 "name": "Test 123",
336 "request_methods": ["create_connection"]
337 }
338 }
339 `, pairingPublicKey)
340
341 nip47Request := &models.Request{}
342 err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
343 assert.NoError(t, err)
344
345 dbRequestEvent := &db.RequestEvent{}
346 err = svc.DB.Create(&dbRequestEvent).Error
347 assert.NoError(t, err)
348
349 var publishedResponse *models.Response
350
351 publishResponse := func(response *models.Response, tags nostr.Tags) {
352 publishedResponse = response
353 }
354
355 NewTestNip47Controller(svc).
356 HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
357
358 assert.NotNil(t, publishedResponse.Error)
359 assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
360 assert.Equal(t, "cannot create a new app that has create_connection permission via NWC", publishedResponse.Error.Message)
361 assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
362 assert.Nil(t, publishedResponse.Result)
363 }
364