nip47_notifier_test.go raw
1 package notifications
2
3 import (
4 "context"
5 "encoding/json"
6 "testing"
7 "time"
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/constants"
14 "github.com/getAlby/hub/db"
15 "github.com/getAlby/hub/events"
16 "github.com/getAlby/hub/lnclient"
17 "github.com/getAlby/hub/nip47/permissions"
18 "github.com/getAlby/hub/tests"
19 )
20
21 type mockConsumer struct {
22 nip47NotificationQueue Nip47NotificationQueue
23 }
24
25 func NewMockConsumer(nip47NotificationQueue Nip47NotificationQueue) *mockConsumer {
26 return &mockConsumer{
27 nip47NotificationQueue: nip47NotificationQueue,
28 }
29 }
30
31 func (svc *mockConsumer) ConsumeEvent(ctx context.Context, event *events.Event, globalProperties map[string]interface{}) {
32 svc.nip47NotificationQueue.AddToQueue(event)
33 }
34
35 func doTestSendNotificationPaymentReceived(t *testing.T, svc *tests.TestService, createAppFn tests.CreateAppFn, nip47Encryption string) {
36 ctx := context.TODO()
37
38 app, cipher, err := createAppFn(svc, nostr.GeneratePrivateKey(), nip47Encryption)
39 assert.NoError(t, err)
40
41 appPermission := &db.AppPermission{
42 AppId: app.ID,
43 App: *app,
44 Scope: constants.NOTIFICATIONS_SCOPE,
45 }
46 err = svc.DB.Create(appPermission).Error
47 assert.NoError(t, err)
48
49 settledAt := time.Unix(*tests.MockLNClientTransaction.SettledAt, 0)
50 initialTransaction := db.Transaction{
51 Type: constants.TRANSACTION_TYPE_INCOMING,
52 PaymentRequest: tests.MockLNClientTransaction.Invoice,
53 Description: tests.MockLNClientTransaction.Description,
54 DescriptionHash: tests.MockLNClientTransaction.DescriptionHash,
55 Preimage: &tests.MockLNClientTransaction.Preimage,
56 PaymentHash: tests.MockLNClientTransaction.PaymentHash,
57 AmountMsat: uint64(tests.MockLNClientTransaction.AmountMsat),
58 FeeMsat: uint64(tests.MockLNClientTransaction.FeesPaidMsat),
59 SettledAt: &settledAt,
60 AppId: &app.ID,
61 State: constants.TRANSACTION_STATE_SETTLED,
62 }
63 err = svc.DB.Create(&initialTransaction).Error
64 assert.NoError(t, err)
65
66 nip47NotificationQueue := NewNip47NotificationQueue()
67 svc.EventPublisher.RegisterSubscriber(NewMockConsumer(nip47NotificationQueue))
68
69 testEvent := &events.Event{
70 Event: "nwc_payment_received",
71 Properties: &initialTransaction,
72 }
73
74 svc.EventPublisher.Publish(testEvent)
75
76 receivedEvent := <-nip47NotificationQueue.Channel()
77 assert.Equal(t, testEvent, receivedEvent)
78
79 pool := tests.NewMockSimplePool()
80
81 permissionsSvc := permissions.NewPermissionsService(svc.DB, svc.EventPublisher)
82
83 notifier := NewNip47Notifier(pool, svc.DB, svc.Cfg, svc.Keys, permissionsSvc)
84 notifier.ConsumeEvent(ctx, receivedEvent)
85
86 var publishedEvent *nostr.Event
87 if nip47Encryption == constants.ENCRYPTION_TYPE_NIP04 {
88 publishedEvent = pool.PublishedEvents[0]
89 } else {
90 publishedEvent = pool.PublishedEvents[1]
91 }
92
93 assert.NotNil(t, publishedEvent)
94 assert.NotEmpty(t, publishedEvent.Content)
95
96 decrypted, err := cipher.Decrypt(publishedEvent.Content)
97 assert.NoError(t, err)
98 unmarshalledResponse := Notification{
99 Notification: &PaymentReceivedNotification{},
100 }
101
102 err = json.Unmarshal([]byte(decrypted), &unmarshalledResponse)
103 assert.NoError(t, err)
104 assert.Equal(t, PAYMENT_RECEIVED_NOTIFICATION, unmarshalledResponse.NotificationType)
105
106 transaction := (unmarshalledResponse.Notification.(*PaymentReceivedNotification))
107 assert.Equal(t, constants.TRANSACTION_TYPE_INCOMING, transaction.Type)
108 assert.Equal(t, tests.MockLNClientTransaction.Invoice, transaction.Invoice)
109 assert.Equal(t, tests.MockLNClientTransaction.Description, transaction.Description)
110 assert.Equal(t, tests.MockLNClientTransaction.DescriptionHash, transaction.DescriptionHash)
111 assert.Equal(t, tests.MockLNClientTransaction.Preimage, transaction.Preimage)
112 assert.Equal(t, tests.MockLNClientTransaction.PaymentHash, transaction.PaymentHash)
113 assert.Equal(t, tests.MockLNClientTransaction.AmountMsat, transaction.Amount)
114 assert.Equal(t, tests.MockLNClientTransaction.FeesPaidMsat, transaction.FeesPaid)
115 assert.Equal(t, tests.MockLNClientTransaction.SettledAt, transaction.SettledAt)
116 }
117
118 func TestSendNotification_Nip04_PaymentReceived(t *testing.T) {
119 svc, err := tests.CreateTestService(t)
120 require.NoError(t, err)
121 defer svc.Remove()
122
123 doTestSendNotificationPaymentReceived(t, svc, tests.CreateAppWithPrivateKey, constants.ENCRYPTION_TYPE_NIP04)
124 }
125
126 func TestSendNotification_Nip44_PaymentReceived(t *testing.T) {
127 svc, err := tests.CreateTestService(t)
128 require.NoError(t, err)
129 defer svc.Remove()
130
131 doTestSendNotificationPaymentReceived(t, svc, tests.CreateAppWithPrivateKey, constants.ENCRYPTION_TYPE_NIP44_V2)
132 }
133
134 func TestSendNotification_SharedWalletPubkey_Nip04_PaymentReceived(t *testing.T) {
135 svc, err := tests.CreateTestService(t)
136 defer svc.Remove()
137 require.NoError(t, err)
138
139 doTestSendNotificationPaymentReceived(t, svc, tests.CreateAppWithSharedWalletPubkey, constants.ENCRYPTION_TYPE_NIP04)
140 }
141
142 func TestSendNotification_SharedWalletPubkey_Nip44_PaymentReceived(t *testing.T) {
143 svc, err := tests.CreateTestService(t)
144 defer svc.Remove()
145 require.NoError(t, err)
146
147 doTestSendNotificationPaymentReceived(t, svc, tests.CreateAppWithSharedWalletPubkey, constants.ENCRYPTION_TYPE_NIP44_V2)
148 }
149
150 func doTestSendNotificationPaymentSent(t *testing.T, svc *tests.TestService, createAppFn tests.CreateAppFn, nip47Encryption string) {
151 ctx := context.TODO()
152
153 app, cipher, err := createAppFn(svc, nostr.GeneratePrivateKey(), nip47Encryption)
154 assert.NoError(t, err)
155
156 appPermission := &db.AppPermission{
157 AppId: app.ID,
158 App: *app,
159 Scope: constants.NOTIFICATIONS_SCOPE,
160 }
161 err = svc.DB.Create(appPermission).Error
162 assert.NoError(t, err)
163
164 settledAt := time.Unix(*tests.MockLNClientTransaction.SettledAt, 0)
165 initialTransaction := db.Transaction{
166 Type: constants.TRANSACTION_TYPE_OUTGOING,
167 PaymentRequest: tests.MockLNClientTransaction.Invoice,
168 Description: tests.MockLNClientTransaction.Description,
169 DescriptionHash: tests.MockLNClientTransaction.DescriptionHash,
170 Preimage: &tests.MockLNClientTransaction.Preimage,
171 PaymentHash: tests.MockLNClientTransaction.PaymentHash,
172 AmountMsat: uint64(tests.MockLNClientTransaction.AmountMsat),
173 FeeMsat: uint64(tests.MockLNClientTransaction.FeesPaidMsat),
174 SettledAt: &settledAt,
175 AppId: &app.ID,
176 }
177 err = svc.DB.Create(&initialTransaction).Error
178 assert.NoError(t, err)
179
180 nip47NotificationQueue := NewNip47NotificationQueue()
181 svc.EventPublisher.RegisterSubscriber(NewMockConsumer(nip47NotificationQueue))
182
183 testEvent := &events.Event{
184 Event: "nwc_payment_sent",
185 Properties: &initialTransaction,
186 }
187
188 svc.EventPublisher.Publish(testEvent)
189
190 receivedEvent := <-nip47NotificationQueue.Channel()
191 assert.Equal(t, testEvent, receivedEvent)
192
193 pool := tests.NewMockSimplePool()
194
195 permissionsSvc := permissions.NewPermissionsService(svc.DB, svc.EventPublisher)
196
197 notifier := NewNip47Notifier(pool, svc.DB, svc.Cfg, svc.Keys, permissionsSvc)
198 notifier.ConsumeEvent(ctx, receivedEvent)
199
200 var publishedEvent *nostr.Event
201 if nip47Encryption == constants.ENCRYPTION_TYPE_NIP04 {
202 publishedEvent = pool.PublishedEvents[0]
203 } else {
204 publishedEvent = pool.PublishedEvents[1]
205 }
206
207 assert.NotNil(t, publishedEvent)
208 assert.NotEmpty(t, publishedEvent.Content)
209
210 decrypted, err := cipher.Decrypt(publishedEvent.Content)
211 assert.NoError(t, err)
212 unmarshalledResponse := Notification{
213 Notification: &PaymentReceivedNotification{},
214 }
215
216 err = json.Unmarshal([]byte(decrypted), &unmarshalledResponse)
217 assert.NoError(t, err)
218 assert.Equal(t, PAYMENT_SENT_NOTIFICATION, unmarshalledResponse.NotificationType)
219
220 transaction := (unmarshalledResponse.Notification.(*PaymentReceivedNotification))
221 assert.Equal(t, constants.TRANSACTION_TYPE_OUTGOING, transaction.Type)
222 assert.Equal(t, tests.MockLNClientTransaction.Invoice, transaction.Invoice)
223 assert.Equal(t, tests.MockLNClientTransaction.Description, transaction.Description)
224 assert.Equal(t, tests.MockLNClientTransaction.DescriptionHash, transaction.DescriptionHash)
225 assert.Equal(t, tests.MockLNClientTransaction.Preimage, transaction.Preimage)
226 assert.Equal(t, tests.MockLNClientTransaction.PaymentHash, transaction.PaymentHash)
227 assert.Equal(t, tests.MockLNClientTransaction.AmountMsat, transaction.Amount)
228 assert.Equal(t, tests.MockLNClientTransaction.FeesPaidMsat, transaction.FeesPaid)
229 assert.Equal(t, tests.MockLNClientTransaction.SettledAt, transaction.SettledAt)
230 }
231
232 func TestSendNotification_Nip04_PaymentSent(t *testing.T) {
233 svc, err := tests.CreateTestService(t)
234 require.NoError(t, err)
235 defer svc.Remove()
236
237 doTestSendNotificationPaymentSent(t, svc, tests.CreateAppWithPrivateKey, constants.ENCRYPTION_TYPE_NIP04)
238 }
239
240 func TestSendNotification_Nip44_PaymentSent(t *testing.T) {
241 svc, err := tests.CreateTestService(t)
242 require.NoError(t, err)
243 defer svc.Remove()
244
245 doTestSendNotificationPaymentSent(t, svc, tests.CreateAppWithPrivateKey, constants.ENCRYPTION_TYPE_NIP44_V2)
246 }
247
248 func TestSendNotification_SharedWalletPubkey_Nip04_PaymentSent(t *testing.T) {
249 svc, err := tests.CreateTestService(t)
250 require.NoError(t, err)
251 defer svc.Remove()
252
253 doTestSendNotificationPaymentSent(t, svc, tests.CreateAppWithSharedWalletPubkey, constants.ENCRYPTION_TYPE_NIP04)
254 }
255
256 func TestSendNotification_SharedWalletPubkey_Nip44_PaymentSent(t *testing.T) {
257 svc, err := tests.CreateTestService(t)
258 require.NoError(t, err)
259 defer svc.Remove()
260
261 doTestSendNotificationPaymentSent(t, svc, tests.CreateAppWithSharedWalletPubkey, constants.ENCRYPTION_TYPE_NIP44_V2)
262 }
263
264 func doTestSendNotificationNoPermission(t *testing.T, svc *tests.TestService) {
265 ctx := context.TODO()
266
267 svc.DB.Create(&db.Transaction{
268 PaymentHash: tests.MockPaymentHash,
269 })
270
271 nip47NotificationQueue := NewNip47NotificationQueue()
272 svc.EventPublisher.RegisterSubscriber(NewMockConsumer(nip47NotificationQueue))
273
274 testEvent := &events.Event{
275 Event: "nwc_payment_received",
276 Properties: &lnclient.Transaction{
277 PaymentHash: tests.MockPaymentHash,
278 },
279 }
280
281 svc.EventPublisher.Publish(testEvent)
282
283 receivedEvent := <-nip47NotificationQueue.Channel()
284 assert.Equal(t, testEvent, receivedEvent)
285
286 pool := tests.NewMockSimplePool()
287
288 permissionsSvc := permissions.NewPermissionsService(svc.DB, svc.EventPublisher)
289
290 notifier := NewNip47Notifier(pool, svc.DB, svc.Cfg, svc.Keys, permissionsSvc)
291 notifier.ConsumeEvent(ctx, receivedEvent)
292
293 assert.Nil(t, pool.PublishedEvents)
294 }
295
296 func TestSendNotification_NoPermission(t *testing.T) {
297 svc, err := tests.CreateTestService(t)
298 require.NoError(t, err)
299 defer svc.Remove()
300 _, _, err = tests.CreateAppWithPrivateKey(svc, nostr.GeneratePrivateKey(), constants.ENCRYPTION_TYPE_NIP44_V2)
301 assert.NoError(t, err)
302 doTestSendNotificationNoPermission(t, svc)
303 }
304
305 func TestSendNotification_SharedWalletPubkey_NoPermission(t *testing.T) {
306 svc, err := tests.CreateTestService(t)
307 require.NoError(t, err)
308 defer svc.Remove()
309 _, _, err = tests.CreateAppWithSharedWalletPubkey(svc, nostr.GeneratePrivateKey(), constants.ENCRYPTION_TYPE_NIP44_V2)
310 assert.NoError(t, err)
311 doTestSendNotificationNoPermission(t, svc)
312 }
313