alby-hub/nip47/controllers/create_connection_controller_test.go
daywalker90 6a15ebadad
Some checks are pending
Multiplatform Docker build & push / build (push) Waiting to run
Code quality - linting and typechecking / linting (push) Waiting to run
Backend testing with Postgres / test-postgres (push) Waiting to run
feat: generate CLN invoice preimage ourselves to support sub-wallets (#2412)
2026-06-08 21:20:51 +07:00

363 lines
11 KiB
Go

package controllers
import (
"context"
"encoding/json"
"fmt"
"testing"
"github.com/getAlby/go-nostr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/getAlby/hub/apps"
"github.com/getAlby/hub/config"
"github.com/getAlby/hub/constants"
"github.com/getAlby/hub/db"
"github.com/getAlby/hub/nip47/models"
"github.com/getAlby/hub/tests"
)
func TestHandleCreateConnectionEvent(t *testing.T) {
ctx := context.TODO()
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
svc.Cfg.SetUpdate("LNBackendType", config.LDKBackendType, "")
pairingSecretKey := nostr.GeneratePrivateKey()
pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
require.NoError(t, err)
nip47CreateConnectionJson := fmt.Sprintf(`
{
"method": "create_connection",
"params": {
"pubkey": "%s",
"name": "Test 123",
"request_methods": ["get_info", "pay_invoice"],
"notification_types": ["payment_received"],
"max_amount": 100000000,
"budget_renewal": "monthly",
"isolated": true
}
}
`, pairingPublicKey)
nip47Request := &models.Request{}
err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
assert.NoError(t, err)
dbRequestEvent := &db.RequestEvent{}
err = svc.DB.Create(&dbRequestEvent).Error
assert.NoError(t, err)
var publishedResponse *models.Response
publishResponse := func(response *models.Response, tags nostr.Tags) {
publishedResponse = response
}
NewTestNip47Controller(svc).
HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
assert.Nil(t, publishedResponse.Error)
assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
createAppResult := publishedResponse.Result.(createConnectionResponse)
assert.NotNil(t, createAppResult.WalletPubkey)
app := db.App{}
err = svc.DB.First(&app).Error
assert.NoError(t, err)
assert.Equal(t, pairingPublicKey, app.AppPubkey)
assert.Equal(t, createAppResult.WalletPubkey, *app.WalletPubkey)
permissions := []db.AppPermission{}
err = svc.DB.Find(&permissions).Error
assert.NoError(t, err)
assert.Equal(t, 3, len(permissions))
assert.Equal(t, constants.GET_INFO_SCOPE, permissions[0].Scope)
assert.Equal(t, constants.PAY_INVOICE_SCOPE, permissions[1].Scope)
assert.Equal(t, constants.NOTIFICATIONS_SCOPE, permissions[2].Scope)
assert.True(t, app.Isolated)
assert.Equal(t, 100_000, permissions[1].MaxAmountSat)
assert.Equal(t, constants.BUDGET_RENEWAL_MONTHLY, permissions[1].BudgetRenewal)
}
func TestHandleCreateConnectionEvent_IsolatedUnsupportedBackendType(t *testing.T) {
ctx := context.TODO()
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
svc.Cfg.SetUpdate("BackendType", config.CashuBackendType, "")
pairingSecretKey := nostr.GeneratePrivateKey()
pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
require.NoError(t, err)
nip47CreateConnectionJson := fmt.Sprintf(`
{
"method": "create_connection",
"params": {
"pubkey": "%s",
"name": "Test 123",
"request_methods": ["get_info", "pay_invoice"],
"notification_types": ["payment_received"],
"max_amount": 100000000,
"budget_renewal": "monthly",
"isolated": true
}
}
`, pairingPublicKey)
nip47Request := &models.Request{}
err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
assert.NoError(t, err)
dbRequestEvent := &db.RequestEvent{}
err = svc.DB.Create(&dbRequestEvent).Error
assert.NoError(t, err)
var publishedResponse *models.Response
publishResponse := func(response *models.Response, tags nostr.Tags) {
publishedResponse = response
}
NewTestNip47Controller(svc).
HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
assert.NotNil(t, publishedResponse.Error)
assert.Equal(t, constants.ERROR_INTERNAL, publishedResponse.Error.Code)
assert.Equal(t, "sub-wallets are currently not supported on your node backend. Try LDK, LND, PHOENIX, BARK, or CLN", publishedResponse.Error.Message)
assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
}
func TestHandleCreateConnectionEvent_PubkeyAlreadyExists(t *testing.T) {
ctx := context.TODO()
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
pairingSecretKey := nostr.GeneratePrivateKey()
pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
require.NoError(t, err)
appsSvc := apps.NewAppsService(svc.DB, svc.EventPublisher, svc.Keys, svc.Cfg)
_, _, err = appsSvc.CreateApp("Existing App", pairingPublicKey, 0, constants.BUDGET_RENEWAL_NEVER, nil, []string{models.GET_INFO_METHOD}, false, nil)
nip47CreateConnectionJson := fmt.Sprintf(`
{
"method": "create_connection",
"params": {
"pubkey": "%s",
"name": "Test 123",
"request_methods": ["get_info"]
}
}
`, pairingPublicKey)
nip47Request := &models.Request{}
err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
assert.NoError(t, err)
dbRequestEvent := &db.RequestEvent{}
err = svc.DB.Create(&dbRequestEvent).Error
assert.NoError(t, err)
var publishedResponse *models.Response
publishResponse := func(response *models.Response, tags nostr.Tags) {
publishedResponse = response
}
NewTestNip47Controller(svc).
HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
assert.NotNil(t, publishedResponse.Error)
assert.Equal(t, constants.ERROR_INTERNAL, publishedResponse.Error.Code)
assert.Equal(t, "duplicated key not allowed", publishedResponse.Error.Message)
assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
assert.Nil(t, publishedResponse.Result)
}
func TestHandleCreateConnectionEvent_NoMethods(t *testing.T) {
ctx := context.TODO()
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
pairingSecretKey := nostr.GeneratePrivateKey()
pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
require.NoError(t, err)
nip47CreateConnectionJson := fmt.Sprintf(`
{
"method": "create_connection",
"params": {
"pubkey": "%s",
"name": "Test 123"
}
}
`, pairingPublicKey)
nip47Request := &models.Request{}
err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
assert.NoError(t, err)
dbRequestEvent := &db.RequestEvent{}
err = svc.DB.Create(&dbRequestEvent).Error
assert.NoError(t, err)
var publishedResponse *models.Response
publishResponse := func(response *models.Response, tags nostr.Tags) {
publishedResponse = response
}
NewTestNip47Controller(svc).
HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
assert.NotNil(t, publishedResponse.Error)
assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
assert.Equal(t, "No request methods provided", publishedResponse.Error.Message)
assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
assert.Nil(t, publishedResponse.Result)
}
func TestHandleCreateConnectionEvent_UnsupportedMethod(t *testing.T) {
ctx := context.TODO()
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
pairingSecretKey := nostr.GeneratePrivateKey()
pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
require.NoError(t, err)
nip47CreateConnectionJson := fmt.Sprintf(`
{
"method": "create_connection",
"params": {
"pubkey": "%s",
"name": "Test 123",
"request_methods": ["non_existent"]
}
}
`, pairingPublicKey)
nip47Request := &models.Request{}
err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
assert.NoError(t, err)
dbRequestEvent := &db.RequestEvent{}
err = svc.DB.Create(&dbRequestEvent).Error
assert.NoError(t, err)
var publishedResponse *models.Response
publishResponse := func(response *models.Response, tags nostr.Tags) {
publishedResponse = response
}
NewTestNip47Controller(svc).
HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
assert.NotNil(t, publishedResponse.Error)
assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
assert.Equal(t, "One or more methods are not supported by the current LNClient", publishedResponse.Error.Message)
assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
assert.Nil(t, publishedResponse.Result)
}
func TestHandleCreateConnectionEvent_UnsupportedNotificationType(t *testing.T) {
ctx := context.TODO()
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
pairingSecretKey := nostr.GeneratePrivateKey()
pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
require.NoError(t, err)
nip47CreateConnectionJson := fmt.Sprintf(`
{
"method": "create_connection",
"params": {
"pubkey": "%s",
"name": "Test 123",
"request_methods": ["get_info"],
"notification_types": ["non_existent"]
}
}
`, pairingPublicKey)
nip47Request := &models.Request{}
err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
assert.NoError(t, err)
dbRequestEvent := &db.RequestEvent{}
err = svc.DB.Create(&dbRequestEvent).Error
assert.NoError(t, err)
var publishedResponse *models.Response
publishResponse := func(response *models.Response, tags nostr.Tags) {
publishedResponse = response
}
NewTestNip47Controller(svc).
HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
assert.NotNil(t, publishedResponse.Error)
assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
assert.Equal(t, "One or more notification types are not supported by the current LNClient", publishedResponse.Error.Message)
assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
assert.Nil(t, publishedResponse.Result)
}
func TestHandleCreateConnectionEvent_DoNotAllowCreateConnectionMethod(t *testing.T) {
ctx := context.TODO()
svc, err := tests.CreateTestService(t)
require.NoError(t, err)
defer svc.Remove()
pairingSecretKey := nostr.GeneratePrivateKey()
pairingPublicKey, err := nostr.GetPublicKey(pairingSecretKey)
require.NoError(t, err)
nip47CreateConnectionJson := fmt.Sprintf(`
{
"method": "create_connection",
"params": {
"pubkey": "%s",
"name": "Test 123",
"request_methods": ["create_connection"]
}
}
`, pairingPublicKey)
nip47Request := &models.Request{}
err = json.Unmarshal([]byte(nip47CreateConnectionJson), nip47Request)
assert.NoError(t, err)
dbRequestEvent := &db.RequestEvent{}
err = svc.DB.Create(&dbRequestEvent).Error
assert.NoError(t, err)
var publishedResponse *models.Response
publishResponse := func(response *models.Response, tags nostr.Tags) {
publishedResponse = response
}
NewTestNip47Controller(svc).
HandleCreateConnectionEvent(ctx, nip47Request, dbRequestEvent.ID, publishResponse)
assert.NotNil(t, publishedResponse.Error)
assert.Equal(t, constants.ERROR_BAD_REQUEST, publishedResponse.Error.Code)
assert.Equal(t, "cannot create a new app that has create_connection permission via NWC", publishedResponse.Error.Message)
assert.Equal(t, models.CREATE_CONNECTION_METHOD, publishedResponse.ResultType)
assert.Nil(t, publishedResponse.Result)
}