From daa8f220a413a2c2ffb62e8b3991854f39cd19a6 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Thu, 19 Mar 2026 00:59:02 +0530 Subject: [PATCH 1/3] fix: return app metadata and lud16 in get_info without scope --- nip47/controllers/get_info_controller.go | 56 +++++++++---------- nip47/controllers/get_info_controller_test.go | 20 ++++++- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/nip47/controllers/get_info_controller.go b/nip47/controllers/get_info_controller.go index a81ab1129..e81c72425 100644 --- a/nip47/controllers/get_info_controller.go +++ b/nip47/controllers/get_info_controller.go @@ -36,6 +36,34 @@ func (controller *nip47Controller) HandleGetInfoEvent(ctx context.Context, nip47 Notifications: supportedNotifications, } + if app != nil { + metadata := map[string]interface{}{} + if app.Metadata != nil { + jsonErr := json.Unmarshal(app.Metadata, &metadata) + if jsonErr != nil { + logger.Logger.WithError(jsonErr).WithFields(logrus.Fields{ + "id": app.ID, + "metadata": app.Metadata, + }).Error("Failed to deserialize app metadata") + } + } + if metadata["id"] == nil { + metadata["id"] = app.ID + } + if metadata["name"] == nil { + metadata["name"] = app.Name + } + if !app.Isolated { + lightningAddress, _ := controller.albyOAuthService.GetLightningAddress() + responsePayload.LightningAddress = &lightningAddress + } else if metadata[constants.METADATA_APPSTORE_APP_ID_KEY] == constants.SUBWALLET_APPSTORE_APP_ID && metadata["lud16"] != nil { + lightningAddress := metadata["lud16"].(string) + responsePayload.LightningAddress = &lightningAddress + } + + responsePayload.Metadata = metadata + } + // basic permissions check // this is inconsistent with other methods. Ideally we move fetching node info to a separate method, // so that get_info does not require its own scope. This would require a change in the NIP-47 spec. @@ -70,34 +98,6 @@ func (controller *nip47Controller) HandleGetInfoEvent(ctx context.Context, nip47 responsePayload.Network = &network responsePayload.BlockHeight = &info.BlockHeight responsePayload.BlockHash = &info.BlockHash - - if app != nil { - metadata := map[string]interface{}{} - if app.Metadata != nil { - jsonErr := json.Unmarshal(app.Metadata, &metadata) - if jsonErr != nil { - logger.Logger.WithError(jsonErr).WithFields(logrus.Fields{ - "id": app.ID, - "metadata": app.Metadata, - }).Error("Failed to deserialize app metadata") - } - } - if metadata["id"] == nil { - metadata["id"] = app.ID - } - if metadata["name"] == nil { - metadata["name"] = app.Name - } - if !app.Isolated { - lightningAddress, _ := controller.albyOAuthService.GetLightningAddress() - responsePayload.LightningAddress = &lightningAddress - } else if metadata[constants.METADATA_APPSTORE_APP_ID_KEY] == constants.SUBWALLET_APPSTORE_APP_ID && metadata["lud16"] != nil { - lightningAddress := metadata["lud16"].(string) - responsePayload.LightningAddress = &lightningAddress - } - - responsePayload.Metadata = metadata - } } publishResponse(&models.Response{ diff --git a/nip47/controllers/get_info_controller_test.go b/nip47/controllers/get_info_controller_test.go index 732898732..588a67975 100644 --- a/nip47/controllers/get_info_controller_test.go +++ b/nip47/controllers/get_info_controller_test.go @@ -28,7 +28,11 @@ func TestHandleGetInfoEvent_NoPermission(t *testing.T) { require.NoError(t, err) defer svc.Remove() - app, _, err := tests.CreateApp(svc) + metadata := map[string]interface{}{ + "a": 123, + } + + app, _, err := svc.AppsService.CreateApp("test", "", 0, "monthly", nil, []string{constants.GET_INFO_SCOPE}, false, metadata) assert.NoError(t, err) lightningAddress := "hello@getalby.com" @@ -70,10 +74,15 @@ func TestHandleGetInfoEvent_NoPermission(t *testing.T) { assert.Nil(t, nodeInfo.Network) assert.Nil(t, nodeInfo.BlockHeight) assert.Nil(t, nodeInfo.BlockHash) - assert.Nil(t, nodeInfo.LightningAddress) + require.NotNil(t, nodeInfo.LightningAddress) + assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) // get_info method is always granted, but does not return pubkey assert.Contains(t, nodeInfo.Methods, models.GET_INFO_METHOD) assert.Equal(t, []string{}, nodeInfo.Notifications) + require.NotNil(t, nodeInfo.Metadata) + assert.Equal(t, float64(123), nodeInfo.Metadata.(map[string]interface{})["a"]) + assert.Equal(t, app.ID, nodeInfo.Metadata.(map[string]interface{})["id"]) + assert.Equal(t, app.Name, nodeInfo.Metadata.(map[string]interface{})["name"]) } func TestHandleGetInfoEvent_SubwalletNoPermission(t *testing.T) { @@ -130,10 +139,15 @@ func TestHandleGetInfoEvent_SubwalletNoPermission(t *testing.T) { assert.Nil(t, nodeInfo.Network) assert.Nil(t, nodeInfo.BlockHeight) assert.Nil(t, nodeInfo.BlockHash) - assert.Nil(t, nodeInfo.LightningAddress) + require.NotNil(t, nodeInfo.LightningAddress) + assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) // get_info method is always granted, but does not return pubkey assert.Contains(t, nodeInfo.Methods, models.GET_INFO_METHOD) assert.Equal(t, []string{}, nodeInfo.Notifications) + require.NotNil(t, nodeInfo.Metadata) + assert.Equal(t, lightningAddress, nodeInfo.Metadata.(map[string]interface{})["lud16"]) + assert.Equal(t, app.ID, nodeInfo.Metadata.(map[string]interface{})["id"]) + assert.Equal(t, app.Name, nodeInfo.Metadata.(map[string]interface{})["name"]) } func TestHandleGetInfoEvent_WithPermission(t *testing.T) { From 31eb5111c99bf7f3f185dd7120d7dc4fde3c1d64 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Thu, 19 Mar 2026 04:03:39 +0530 Subject: [PATCH 2/3] chore: remove unnecessary no error check --- nip47/controllers/get_info_controller_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/nip47/controllers/get_info_controller_test.go b/nip47/controllers/get_info_controller_test.go index 588a67975..aa1cda536 100644 --- a/nip47/controllers/get_info_controller_test.go +++ b/nip47/controllers/get_info_controller_test.go @@ -248,8 +248,6 @@ func TestHandleGetInfoEvent_WithMetadata(t *testing.T) { assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) assert.Contains(t, nodeInfo.Methods, "get_info") assert.Equal(t, []string{}, nodeInfo.Notifications) - - assert.NoError(t, err) assert.Equal(t, float64(123), nodeInfo.Metadata.(map[string]interface{})["a"]) } @@ -307,8 +305,6 @@ func TestHandleGetInfoEvent_SubwalletWithMetadata(t *testing.T) { assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) assert.Contains(t, nodeInfo.Methods, "get_info") assert.Equal(t, []string{}, nodeInfo.Notifications) - - assert.NoError(t, err) assert.Equal(t, float64(123), nodeInfo.Metadata.(map[string]interface{})["a"]) } From d27deabe300d02314dc57c477bafc53fd8de8ff8 Mon Sep 17 00:00:00 2001 From: im-adithya Date: Wed, 25 Mar 2026 22:34:46 +0530 Subject: [PATCH 3/3] chore: rename nodeInfo to infoResponse in get info tests --- nip47/controllers/get_info_controller_test.go | 140 +++++++++--------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/nip47/controllers/get_info_controller_test.go b/nip47/controllers/get_info_controller_test.go index aa1cda536..1dc169d0c 100644 --- a/nip47/controllers/get_info_controller_test.go +++ b/nip47/controllers/get_info_controller_test.go @@ -67,22 +67,22 @@ func TestHandleGetInfoEvent_NoPermission(t *testing.T) { HandleGetInfoEvent(ctx, nip47Request, dbRequestEvent.ID, app, publishResponse) assert.Nil(t, publishedResponse.Error) - nodeInfo := publishedResponse.Result.(*getInfoResponse) - assert.Nil(t, nodeInfo.Alias) - assert.Nil(t, nodeInfo.Color) - assert.Nil(t, nodeInfo.Pubkey) - assert.Nil(t, nodeInfo.Network) - assert.Nil(t, nodeInfo.BlockHeight) - assert.Nil(t, nodeInfo.BlockHash) - require.NotNil(t, nodeInfo.LightningAddress) - assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) + infoResponse := publishedResponse.Result.(*getInfoResponse) + assert.Nil(t, infoResponse.Alias) + assert.Nil(t, infoResponse.Color) + assert.Nil(t, infoResponse.Pubkey) + assert.Nil(t, infoResponse.Network) + assert.Nil(t, infoResponse.BlockHeight) + assert.Nil(t, infoResponse.BlockHash) + require.NotNil(t, infoResponse.LightningAddress) + assert.Equal(t, lightningAddress, *infoResponse.LightningAddress) // get_info method is always granted, but does not return pubkey - assert.Contains(t, nodeInfo.Methods, models.GET_INFO_METHOD) - assert.Equal(t, []string{}, nodeInfo.Notifications) - require.NotNil(t, nodeInfo.Metadata) - assert.Equal(t, float64(123), nodeInfo.Metadata.(map[string]interface{})["a"]) - assert.Equal(t, app.ID, nodeInfo.Metadata.(map[string]interface{})["id"]) - assert.Equal(t, app.Name, nodeInfo.Metadata.(map[string]interface{})["name"]) + assert.Contains(t, infoResponse.Methods, models.GET_INFO_METHOD) + assert.Equal(t, []string{}, infoResponse.Notifications) + require.NotNil(t, infoResponse.Metadata) + assert.Equal(t, float64(123), infoResponse.Metadata.(map[string]interface{})["a"]) + assert.Equal(t, app.ID, infoResponse.Metadata.(map[string]interface{})["id"]) + assert.Equal(t, app.Name, infoResponse.Metadata.(map[string]interface{})["name"]) } func TestHandleGetInfoEvent_SubwalletNoPermission(t *testing.T) { @@ -132,22 +132,22 @@ func TestHandleGetInfoEvent_SubwalletNoPermission(t *testing.T) { HandleGetInfoEvent(ctx, nip47Request, dbRequestEvent.ID, app, publishResponse) assert.Nil(t, publishedResponse.Error) - nodeInfo := publishedResponse.Result.(*getInfoResponse) - assert.Nil(t, nodeInfo.Alias) - assert.Nil(t, nodeInfo.Color) - assert.Nil(t, nodeInfo.Pubkey) - assert.Nil(t, nodeInfo.Network) - assert.Nil(t, nodeInfo.BlockHeight) - assert.Nil(t, nodeInfo.BlockHash) - require.NotNil(t, nodeInfo.LightningAddress) - assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) + infoResponse := publishedResponse.Result.(*getInfoResponse) + assert.Nil(t, infoResponse.Alias) + assert.Nil(t, infoResponse.Color) + assert.Nil(t, infoResponse.Pubkey) + assert.Nil(t, infoResponse.Network) + assert.Nil(t, infoResponse.BlockHeight) + assert.Nil(t, infoResponse.BlockHash) + require.NotNil(t, infoResponse.LightningAddress) + assert.Equal(t, lightningAddress, *infoResponse.LightningAddress) // get_info method is always granted, but does not return pubkey - assert.Contains(t, nodeInfo.Methods, models.GET_INFO_METHOD) - assert.Equal(t, []string{}, nodeInfo.Notifications) - require.NotNil(t, nodeInfo.Metadata) - assert.Equal(t, lightningAddress, nodeInfo.Metadata.(map[string]interface{})["lud16"]) - assert.Equal(t, app.ID, nodeInfo.Metadata.(map[string]interface{})["id"]) - assert.Equal(t, app.Name, nodeInfo.Metadata.(map[string]interface{})["name"]) + assert.Contains(t, infoResponse.Methods, models.GET_INFO_METHOD) + assert.Equal(t, []string{}, infoResponse.Notifications) + require.NotNil(t, infoResponse.Metadata) + assert.Equal(t, lightningAddress, infoResponse.Metadata.(map[string]interface{})["lud16"]) + assert.Equal(t, app.ID, infoResponse.Metadata.(map[string]interface{})["id"]) + assert.Equal(t, app.Name, infoResponse.Metadata.(map[string]interface{})["name"]) } func TestHandleGetInfoEvent_WithPermission(t *testing.T) { @@ -185,15 +185,15 @@ func TestHandleGetInfoEvent_WithPermission(t *testing.T) { HandleGetInfoEvent(ctx, nip47Request, dbRequestEvent.ID, app, publishResponse) assert.Nil(t, publishedResponse.Error) - nodeInfo := publishedResponse.Result.(*getInfoResponse) - assert.Equal(t, tests.MockNodeInfo.Alias, *nodeInfo.Alias) - assert.Equal(t, tests.MockNodeInfo.Color, *nodeInfo.Color) - assert.Equal(t, tests.MockNodeInfo.Pubkey, *nodeInfo.Pubkey) - assert.Equal(t, tests.MockNodeInfo.Network, *nodeInfo.Network) - assert.Equal(t, tests.MockNodeInfo.BlockHeight, *nodeInfo.BlockHeight) - assert.Equal(t, tests.MockNodeInfo.BlockHash, *nodeInfo.BlockHash) - assert.Contains(t, nodeInfo.Methods, "get_info") - assert.Equal(t, []string{}, nodeInfo.Notifications) + infoResponse := publishedResponse.Result.(*getInfoResponse) + assert.Equal(t, tests.MockNodeInfo.Alias, *infoResponse.Alias) + assert.Equal(t, tests.MockNodeInfo.Color, *infoResponse.Color) + assert.Equal(t, tests.MockNodeInfo.Pubkey, *infoResponse.Pubkey) + assert.Equal(t, tests.MockNodeInfo.Network, *infoResponse.Network) + assert.Equal(t, tests.MockNodeInfo.BlockHeight, *infoResponse.BlockHeight) + assert.Equal(t, tests.MockNodeInfo.BlockHash, *infoResponse.BlockHash) + assert.Contains(t, infoResponse.Methods, "get_info") + assert.Equal(t, []string{}, infoResponse.Notifications) } func TestHandleGetInfoEvent_WithMetadata(t *testing.T) { @@ -238,17 +238,17 @@ func TestHandleGetInfoEvent_WithMetadata(t *testing.T) { HandleGetInfoEvent(ctx, nip47Request, dbRequestEvent.ID, app, publishResponse) assert.Nil(t, publishedResponse.Error) - nodeInfo := publishedResponse.Result.(*getInfoResponse) - assert.Equal(t, tests.MockNodeInfo.Alias, *nodeInfo.Alias) - assert.Equal(t, tests.MockNodeInfo.Color, *nodeInfo.Color) - assert.Equal(t, tests.MockNodeInfo.Pubkey, *nodeInfo.Pubkey) - assert.Equal(t, tests.MockNodeInfo.Network, *nodeInfo.Network) - assert.Equal(t, tests.MockNodeInfo.BlockHeight, *nodeInfo.BlockHeight) - assert.Equal(t, tests.MockNodeInfo.BlockHash, *nodeInfo.BlockHash) - assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) - assert.Contains(t, nodeInfo.Methods, "get_info") - assert.Equal(t, []string{}, nodeInfo.Notifications) - assert.Equal(t, float64(123), nodeInfo.Metadata.(map[string]interface{})["a"]) + infoResponse := publishedResponse.Result.(*getInfoResponse) + assert.Equal(t, tests.MockNodeInfo.Alias, *infoResponse.Alias) + assert.Equal(t, tests.MockNodeInfo.Color, *infoResponse.Color) + assert.Equal(t, tests.MockNodeInfo.Pubkey, *infoResponse.Pubkey) + assert.Equal(t, tests.MockNodeInfo.Network, *infoResponse.Network) + assert.Equal(t, tests.MockNodeInfo.BlockHeight, *infoResponse.BlockHeight) + assert.Equal(t, tests.MockNodeInfo.BlockHash, *infoResponse.BlockHash) + assert.Equal(t, lightningAddress, *infoResponse.LightningAddress) + assert.Contains(t, infoResponse.Methods, "get_info") + assert.Equal(t, []string{}, infoResponse.Notifications) + assert.Equal(t, float64(123), infoResponse.Metadata.(map[string]interface{})["a"]) } func TestHandleGetInfoEvent_SubwalletWithMetadata(t *testing.T) { @@ -295,17 +295,17 @@ func TestHandleGetInfoEvent_SubwalletWithMetadata(t *testing.T) { HandleGetInfoEvent(ctx, nip47Request, dbRequestEvent.ID, app, publishResponse) assert.Nil(t, publishedResponse.Error) - nodeInfo := publishedResponse.Result.(*getInfoResponse) - assert.Equal(t, tests.MockNodeInfo.Alias, *nodeInfo.Alias) - assert.Equal(t, tests.MockNodeInfo.Color, *nodeInfo.Color) - assert.Equal(t, tests.MockNodeInfo.Pubkey, *nodeInfo.Pubkey) - assert.Equal(t, tests.MockNodeInfo.Network, *nodeInfo.Network) - assert.Equal(t, tests.MockNodeInfo.BlockHeight, *nodeInfo.BlockHeight) - assert.Equal(t, tests.MockNodeInfo.BlockHash, *nodeInfo.BlockHash) - assert.Equal(t, lightningAddress, *nodeInfo.LightningAddress) - assert.Contains(t, nodeInfo.Methods, "get_info") - assert.Equal(t, []string{}, nodeInfo.Notifications) - assert.Equal(t, float64(123), nodeInfo.Metadata.(map[string]interface{})["a"]) + infoResponse := publishedResponse.Result.(*getInfoResponse) + assert.Equal(t, tests.MockNodeInfo.Alias, *infoResponse.Alias) + assert.Equal(t, tests.MockNodeInfo.Color, *infoResponse.Color) + assert.Equal(t, tests.MockNodeInfo.Pubkey, *infoResponse.Pubkey) + assert.Equal(t, tests.MockNodeInfo.Network, *infoResponse.Network) + assert.Equal(t, tests.MockNodeInfo.BlockHeight, *infoResponse.BlockHeight) + assert.Equal(t, tests.MockNodeInfo.BlockHash, *infoResponse.BlockHash) + assert.Equal(t, lightningAddress, *infoResponse.LightningAddress) + assert.Contains(t, infoResponse.Methods, "get_info") + assert.Equal(t, []string{}, infoResponse.Notifications) + assert.Equal(t, float64(123), infoResponse.Metadata.(map[string]interface{})["a"]) } func TestHandleGetInfoEvent_WithNotifications(t *testing.T) { @@ -351,13 +351,13 @@ func TestHandleGetInfoEvent_WithNotifications(t *testing.T) { HandleGetInfoEvent(ctx, nip47Request, dbRequestEvent.ID, app, publishResponse) assert.Nil(t, publishedResponse.Error) - nodeInfo := publishedResponse.Result.(*getInfoResponse) - assert.Equal(t, tests.MockNodeInfo.Alias, *nodeInfo.Alias) - assert.Equal(t, tests.MockNodeInfo.Color, *nodeInfo.Color) - assert.Equal(t, tests.MockNodeInfo.Pubkey, *nodeInfo.Pubkey) - assert.Equal(t, tests.MockNodeInfo.Network, *nodeInfo.Network) - assert.Equal(t, tests.MockNodeInfo.BlockHeight, *nodeInfo.BlockHeight) - assert.Equal(t, tests.MockNodeInfo.BlockHash, *nodeInfo.BlockHash) - assert.Contains(t, nodeInfo.Methods, "get_info") - assert.Equal(t, []string{"payment_received", "payment_sent"}, nodeInfo.Notifications) + infoResponse := publishedResponse.Result.(*getInfoResponse) + assert.Equal(t, tests.MockNodeInfo.Alias, *infoResponse.Alias) + assert.Equal(t, tests.MockNodeInfo.Color, *infoResponse.Color) + assert.Equal(t, tests.MockNodeInfo.Pubkey, *infoResponse.Pubkey) + assert.Equal(t, tests.MockNodeInfo.Network, *infoResponse.Network) + assert.Equal(t, tests.MockNodeInfo.BlockHeight, *infoResponse.BlockHeight) + assert.Equal(t, tests.MockNodeInfo.BlockHash, *infoResponse.BlockHash) + assert.Contains(t, infoResponse.Methods, "get_info") + assert.Equal(t, []string{"payment_received", "payment_sent"}, infoResponse.Notifications) }