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