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