get_info_controller.go raw

   1  package controllers
   2  
   3  import (
   4  	"context"
   5  	"encoding/json"
   6  
   7  	"github.com/getAlby/go-nostr"
   8  	"github.com/getAlby/hub/constants"
   9  	"github.com/getAlby/hub/db"
  10  	"github.com/getAlby/hub/logger"
  11  	"github.com/getAlby/hub/nip47/models"
  12  	"github.com/sirupsen/logrus"
  13  )
  14  
  15  type getInfoResponse struct {
  16  	Alias            *string     `json:"alias"`
  17  	Color            *string     `json:"color"`
  18  	Pubkey           *string     `json:"pubkey"`
  19  	Network          *string     `json:"network"`
  20  	BlockHeight      *uint32     `json:"block_height"`
  21  	BlockHash        *string     `json:"block_hash"`
  22  	Methods          []string    `json:"methods"`
  23  	Notifications    []string    `json:"notifications"`
  24  	Metadata         interface{} `json:"metadata,omitempty"`
  25  	LightningAddress *string     `json:"lud16"`
  26  }
  27  
  28  func (controller *nip47Controller) HandleGetInfoEvent(ctx context.Context, nip47Request *models.Request, requestEventId uint, app *db.App, publishResponse publishFunc) {
  29  	supportedNotifications := []string{}
  30  	if controller.permissionsService.PermitsNotifications(app) {
  31  		supportedNotifications = controller.lnClient.GetSupportedNIP47NotificationTypes()
  32  	}
  33  
  34  	responsePayload := &getInfoResponse{
  35  		Methods:       controller.permissionsService.GetPermittedMethods(app, controller.lnClient),
  36  		Notifications: supportedNotifications,
  37  	}
  38  
  39  	if app != nil {
  40  		metadata := map[string]interface{}{}
  41  		if app.Metadata != nil {
  42  			jsonErr := json.Unmarshal(app.Metadata, &metadata)
  43  			if jsonErr != nil {
  44  				logger.Logger.WithError(jsonErr).WithFields(logrus.Fields{
  45  					"id":       app.ID,
  46  					"metadata": app.Metadata,
  47  				}).Error("Failed to deserialize app metadata")
  48  			}
  49  		}
  50  		if metadata["id"] == nil {
  51  			metadata["id"] = app.ID
  52  		}
  53  		if metadata["name"] == nil {
  54  			metadata["name"] = app.Name
  55  		}
  56  		if !app.Isolated {
  57  			lightningAddress, _ := controller.albyOAuthService.GetLightningAddress()
  58  			responsePayload.LightningAddress = &lightningAddress
  59  		} else if metadata[constants.METADATA_APPSTORE_APP_ID_KEY] == constants.SUBWALLET_APPSTORE_APP_ID && metadata["lud16"] != nil {
  60  			lightningAddress := metadata["lud16"].(string)
  61  			responsePayload.LightningAddress = &lightningAddress
  62  		}
  63  
  64  		responsePayload.Metadata = metadata
  65  	}
  66  
  67  	// basic permissions check
  68  	// this is inconsistent with other methods. Ideally we move fetching node info to a separate method,
  69  	// so that get_info does not require its own scope. This would require a change in the NIP-47 spec.
  70  	hasPermission, _, _ := controller.permissionsService.HasPermission(app, constants.GET_INFO_SCOPE)
  71  	if hasPermission {
  72  		logger.Logger.WithFields(logrus.Fields{
  73  			"request_event_id": requestEventId,
  74  		}).Debug("Getting info")
  75  
  76  		info, err := controller.lnClient.GetInfo(ctx)
  77  		if err != nil {
  78  			logger.Logger.WithFields(logrus.Fields{
  79  				"request_event_id": requestEventId,
  80  			}).Infof("Failed to fetch node info: %v", err)
  81  
  82  			publishResponse(&models.Response{
  83  				ResultType: nip47Request.Method,
  84  				Error:      mapNip47Error(err),
  85  			}, nostr.Tags{})
  86  			return
  87  		}
  88  
  89  		network := info.Network
  90  		// Some implementations return "bitcoin" while NIP47 expects "mainnet"
  91  		if network == "bitcoin" {
  92  			network = "mainnet"
  93  		}
  94  
  95  		responsePayload.Alias = &info.Alias
  96  		responsePayload.Color = &info.Color
  97  		responsePayload.Pubkey = &info.Pubkey
  98  		responsePayload.Network = &network
  99  		responsePayload.BlockHeight = &info.BlockHeight
 100  		responsePayload.BlockHash = &info.BlockHash
 101  	}
 102  
 103  	publishResponse(&models.Response{
 104  		ResultType: nip47Request.Method,
 105  		Result:     responsePayload,
 106  	}, nostr.Tags{})
 107  }
 108