From d6001980493dbb1702192646a59e2f36624df660 Mon Sep 17 00:00:00 2001 From: naturallaw77 Date: Tue, 25 Aug 2026 19:11:25 -0500 Subject: [PATCH] feat(albyhub): vendor v1.24.0 LND-only, no-frontend build Replace the nixpkgs albyhub overrideAttrs patch-chain with a fully vendored package at packages/albyhub for v1.24.0. - modules/core/sovran-hub.nix: bump fallback version 1.8.0 -> 1.24.0 - modules/nwc-wallets.nix: build via pkgs.callPackage ../packages/albyhub - packages/albyhub: - drop 0002-isolated-invoice-app-id.patch (fixed upstream) - add 0004-lnd-only.patch: strip LDK/Bark/Cashu/CLN/Phoenix backends from service/start.go, leaving only the LND case - add 0005-no-frontend.patch: remove //go:embed dist and the frontend handler registration - add default.nix: buildGoModule for v1.24.0 with no nodejs/yarn/ bark-ffi-go/ldk-node deps (only stdenv.cc.cc), subPackages cmd/http Keeps 0001-private-route-hints and 0003-loopback-bind-host. Does not touch flake.nix, VERSION, or CHANGELOG. --- modules/core/sovran-hub.nix | 2 +- modules/nwc-wallets.nix | 9 +- .../0002-isolated-invoice-app-id.patch | 71 --------- packages/albyhub/0004-lnd-only.patch | 141 ++++++++++++++++++ packages/albyhub/0005-no-frontend.patch | 45 ++++++ packages/albyhub/default.nix | 55 +++++++ 6 files changed, 244 insertions(+), 79 deletions(-) delete mode 100644 packages/albyhub/0002-isolated-invoice-app-id.patch create mode 100644 packages/albyhub/0004-lnd-only.patch create mode 100644 packages/albyhub/0005-no-frontend.patch create mode 100644 packages/albyhub/default.nix diff --git a/modules/core/sovran-hub.nix b/modules/core/sovran-hub.nix index 82f365c..a3dba58 100644 --- a/modules/core/sovran-hub.nix +++ b/modules/core/sovran-hub.nix @@ -143,7 +143,7 @@ let # module. Read the configured package here rather than pkgs.btcpayserver # (unstable), otherwise the Hub can advertise a version that is not running. "btcpayserver.service" = lib.getVersion config.services.btcpayserver.package; - "albyhub.service" = if pkgs ? albyhub then pkgs.albyhub.version else "1.8.0"; + "albyhub.service" = if pkgs ? albyhub then pkgs.albyhub.version else "1.24.0"; "mempool.service" = if pkgs ? mempool then pkgs.mempool.version else "3.2.1"; "matrix-synapse.service" = if pkgs ? matrix-synapse then pkgs.matrix-synapse.version else "1.115.0"; "livekit.service" = if pkgs ? livekit then pkgs.livekit.version else "1.5.2"; diff --git a/modules/nwc-wallets.nix b/modules/nwc-wallets.nix index a329183..c07d4ed 100644 --- a/modules/nwc-wallets.nix +++ b/modules/nwc-wallets.nix @@ -3,13 +3,8 @@ let albyHubPort = 18080; albyHubApiBase = "http://127.0.0.1:${toString albyHubPort}"; - patchedAlbyHub = pkgs.albyhub.overrideAttrs (old: { - patches = (old.patches or []) ++ [ - ../packages/albyhub/0001-private-route-hints.patch - ../packages/albyhub/0002-isolated-invoice-app-id.patch - ../packages/albyhub/0003-loopback-bind-host.patch - ]; - }); + vendoredAlbyHub = pkgs.callPackage ../packages/albyhub {}; + patchedAlbyHub = vendoredAlbyHub; lndRpcAddress = lib.attrByPath [ "services" "lnd" "rpcAddress" ] "127.0.0.1" config; lndRpcPort = toString (lib.attrByPath [ "services" "lnd" "rpcPort" ] 10009 config); diff --git a/packages/albyhub/0002-isolated-invoice-app-id.patch b/packages/albyhub/0002-isolated-invoice-app-id.patch deleted file mode 100644 index e2836eb..0000000 --- a/packages/albyhub/0002-isolated-invoice-app-id.patch +++ /dev/null @@ -1,71 +0,0 @@ -diff --git a/api/models.go b/api/models.go -index 28bd117..dceb79a 100644 ---- a/api/models.go -+++ b/api/models.go -@@ -46,7 +46,7 @@ type API interface { - ListTransactions(ctx context.Context, appId *uint, limit uint64, offset uint64) (*ListTransactionsResponse, error) - ListOnchainTransactions(ctx context.Context) ([]OnchainTransaction, error) - SendPayment(ctx context.Context, invoice string, amountMsat *uint64, metadata map[string]interface{}, fromAppId *uint) (*SendPaymentResponse, error) -- CreateInvoice(ctx context.Context, amountMsat uint64, description string) (*MakeInvoiceResponse, error) -+ CreateInvoice(ctx context.Context, amountMsat uint64, description string, appId *uint) (*MakeInvoiceResponse, error) - LookupInvoice(ctx context.Context, paymentHash string) (*LookupInvoiceResponse, error) - SetTransactionUserLabels(ctx context.Context, id uint, labels map[string]string) error - RequestMempoolApi(ctx context.Context, endpoint string) (interface{}, error) -@@ -586,6 +586,7 @@ type MakeInvoiceRequest struct { - AmountSat *uint64 `json:"amountSat"` - AmountMsat *uint64 `json:"amountMsat"` - Description string `json:"description"` -+ AppId *uint `json:"appId"` - } - - type ResetRouterRequest struct { -diff --git a/api/transactions.go b/api/transactions.go -index aaf9380..3f9850a 100644 ---- a/api/transactions.go -+++ b/api/transactions.go -@@ -12,12 +12,12 @@ import ( - "github.com/sirupsen/logrus" - ) - --func (api *api) CreateInvoice(ctx context.Context, amountMsat uint64, description string) (*MakeInvoiceResponse, error) { -+func (api *api) CreateInvoice(ctx context.Context, amountMsat uint64, description string, appId *uint) (*MakeInvoiceResponse, error) { - lnClient := api.svc.GetLNClient() - if lnClient == nil { - return nil, ErrLNClientNotStarted - } -- transaction, err := api.svc.GetTransactionsService().MakeInvoice(ctx, amountMsat, description, "", 0, nil, lnClient, nil, nil, nil) -+ transaction, err := api.svc.GetTransactionsService().MakeInvoice(ctx, amountMsat, description, "", 0, nil, lnClient, appId, nil, nil) - if err != nil { - return nil, err - } -diff --git a/http/http_service.go b/http/http_service.go -index bf650b9..cf61250 100644 ---- a/http/http_service.go -+++ b/http/http_service.go -@@ -687,7 +687,12 @@ func (httpSvc *HttpService) makeInvoiceHandler(c echo.Context) error { - amountMsat = *resolvedAmountMsat - } - -- invoice, err := httpSvc.api.CreateInvoice(c.Request().Context(), amountMsat, makeInvoiceRequest.Description) -+ invoice, err := httpSvc.api.CreateInvoice( -+ c.Request().Context(), -+ amountMsat, -+ makeInvoiceRequest.Description, -+ makeInvoiceRequest.AppId, -+ ) - - if err != nil { - return c.JSON(http.StatusInternalServerError, ErrorResponse{ -diff --git a/wails/wails_handlers.go b/wails/wails_handlers.go -index d25259b..c9fe4e8 100644 ---- a/wails/wails_handlers.go -+++ b/wails/wails_handlers.go -@@ -600,7 +600,7 @@ func (app *WailsApp) WailsRequestRouter(route string, method string, body string - if resolvedAmountMsat != nil { - amountMsat = *resolvedAmountMsat - } -- invoice, err := app.api.CreateInvoice(ctx, amountMsat, makeInvoiceRequest.Description) -+ invoice, err := app.api.CreateInvoice(ctx, amountMsat, makeInvoiceRequest.Description, nil) - if err != nil { - return WailsRequestRouterResponse{Body: nil, Error: err.Error()} - } diff --git a/packages/albyhub/0004-lnd-only.patch b/packages/albyhub/0004-lnd-only.patch new file mode 100644 index 0000000..01e1f0c --- /dev/null +++ b/packages/albyhub/0004-lnd-only.patch @@ -0,0 +1,141 @@ +diff --git a/service/start.go b/service/start.go +index 8c9786a..4b992c7 100644 +--- a/service/start.go ++++ b/service/start.go +@@ -5,7 +5,6 @@ import ( + "errors" + "fmt" + "net/http" +- "path" + "strconv" + "time" + +@@ -349,63 +348,12 @@ func (svc *service) launchLNBackend(ctx context.Context, encryptionKey string) e + logger.Logger.Infof("Launching LN Backend: %s", lnBackend) + var lnClient lnclient.LNClient + var err error +- vssEnabled := false + switch lnBackend { + case config.LNDBackendType: + LNDAddress, _ := svc.cfg.Get("LNDAddress", encryptionKey) + LNDCertHex, _ := svc.cfg.Get("LNDCertHex", encryptionKey) + LNDMacaroonHex, _ := svc.cfg.Get("LNDMacaroonHex", encryptionKey) + lnClient, err = lnd.NewLNDService(ctx, svc.eventPublisher, LNDAddress, LNDCertHex, LNDMacaroonHex) +- case config.LDKBackendType: +- mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey) +- ldkWorkdir := path.Join(svc.cfg.GetEnv().Workdir, "ldk") +- var vssToken string +- vssToken, err = svc.requestVssToken(ctx) +- if err != nil { +- logger.Logger.WithError(err).Error("Failed to request VSS token") +- return err +- } +- vssEnabled = vssToken != "" +- +- svc.startupState = "Launching Node" +- setStartupState := func(startupState string) { +- svc.startupState = startupState +- } +- +- channelPeerSuggestions, suggestionsErr := svc.albySvc.GetChannelPeerSuggestions(ctx) +- if suggestionsErr != nil { +- logger.Logger.WithError(suggestionsErr).Warn("Failed to fetch channel peer suggestions for LSPS2 liquidity source") +- } +- lnClient, err = ldk.NewLDKService(ctx, svc.cfg, svc.eventPublisher, mnemonic, ldkWorkdir, vssToken, setStartupState, channelPeerSuggestions) +- case config.PhoenixBackendType: +- PhoenixdAddress, _ := svc.cfg.Get("PhoenixdAddress", encryptionKey) +- PhoenixdAuthorization, _ := svc.cfg.Get("PhoenixdAuthorization", encryptionKey) +- +- lnClient, err = phoenixd.NewPhoenixService(ctx, PhoenixdAddress, PhoenixdAuthorization) +- case config.CashuBackendType: +- mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey) +- cashuMintUrl, _ := svc.cfg.Get("CashuMintUrl", encryptionKey) +- cashuWorkdir := path.Join(svc.cfg.GetEnv().Workdir, "cashu") +- +- lnClient, err = cashu.NewCashuService(svc.cfg, cashuWorkdir, mnemonic, cashuMintUrl) +- case config.BarkBackendType: +- mnemonic, _ := svc.cfg.Get("Mnemonic", encryptionKey) +- env := svc.cfg.GetEnv() +- barkWorkdir := path.Join(env.Workdir, "bark") +- +- lnClient, err = bark.NewBarkService(ctx, svc.eventPublisher, barkWorkdir, mnemonic, bark.Config{ +- Network: svc.cfg.GetNetwork(), +- ServerAddress: env.BarkServer, +- EsploraAddress: env.BarkEsploraServer, +- ServerAccessToken: env.BarkServerAccessToken, +- LogLevel: env.BarkLogLevel, +- LogToFile: env.LogToFile, +- }) +- case config.CLNBackendType: +- CLNAddress, _ := svc.cfg.Get("CLNAddress", encryptionKey) +- CLNLightningDir, _ := svc.cfg.Get("CLNLightningDir", encryptionKey) +- CLNAddressHold, _ := svc.cfg.Get("CLNAddressHold", encryptionKey) +- lnClient, err = cln.NewCLNService(ctx, svc.eventPublisher, CLNAddress, CLNLightningDir, CLNAddressHold) + default: + logger.Logger.WithField("backend_type", lnBackend).Error("Unsupported LNBackendType") + return fmt.Errorf("unsupported backend type: %s", lnBackend) +@@ -439,63 +387,9 @@ func (svc *service) launchLNBackend(ctx context.Context, encryptionKey string) e + svc.eventPublisher.Publish(&events.Event{ + Event: "nwc_node_started", + Properties: map[string]interface{}{ +- "node_type": lnBackend, +- "vss_enabled": vssEnabled, ++ "node_type": lnBackend, + }, + }) + + return nil + } +- +-func (svc *service) requestVssToken(ctx context.Context) (string, error) { +- nodeLastStartTime, _ := svc.cfg.Get("NodeLastStartTime", "") +- +- // for brand new nodes, consider enabling VSS +- if nodeLastStartTime == "" && svc.cfg.GetEnv().LDKVssUrl != "" { +- svc.startupState = "Checking Subscription" +- albyUserIdentifier, err := svc.albyOAuthSvc.GetUserIdentifier() +- if err != nil { +- logger.Logger.WithError(err).Error("Failed to fetch alby user identifier") +- return "", err +- } +- if albyUserIdentifier != "" { +- me, err := svc.albyOAuthSvc.GetMe(ctx) +- if err != nil { +- logger.Logger.WithError(err).Error("Failed to fetch alby user") +- return "", err +- } +- // only activate VSS for Alby paid subscribers +- if me.Subscription.PlanCode != "" { +- svc.cfg.SetUpdate("LdkVssEnabled", "true", "") +- } +- } +- } +- +- vssToken := "" +- vssEnabled, _ := svc.cfg.Get("LdkVssEnabled", "") +- if vssEnabled == "true" { +- svc.startupState = "Fetching VSS token" +- vssNodeIdentifier, err := ldk.GetVssNodeIdentifier(svc.keys) +- if err != nil { +- logger.Logger.WithError(err).Error("Failed to get VSS node identifier") +- return "", err +- } +- vssToken, err = svc.albyOAuthSvc.GetVssAuthToken(ctx, vssNodeIdentifier) +- if err != nil { +- logger.Logger.WithError(err).Error("Failed to fetch VSS JWT token") +- +- existingVssToken, _ := svc.cfg.Get("VssToken", "") +- if existingVssToken != "" { +- logger.Logger.Warn("Using stored VSS JWT token") +- return existingVssToken, nil +- } +- +- return "", err +- } +- err = svc.cfg.SetUpdate("VssToken", vssToken, "") +- if err != nil { +- logger.Logger.WithError(err).Error("Failed to save VSS JWT token to user config") +- } +- } +- return vssToken, nil +-} diff --git a/packages/albyhub/0005-no-frontend.patch b/packages/albyhub/0005-no-frontend.patch new file mode 100644 index 0000000..c7426cf --- /dev/null +++ b/packages/albyhub/0005-no-frontend.patch @@ -0,0 +1,45 @@ +diff --git a/frontend/frontend.go b/frontend/frontend.go +index 203dd9b..9c7f6da 100644 +--- a/frontend/frontend.go ++++ b/frontend/frontend.go +@@ -1,26 +1,7 @@ + package frontend + + import ( +- "embed" +- "net/http" +- + "github.com/labstack/echo/v4" +- "github.com/labstack/echo/v4/middleware" + ) + +-//go:embed dist +-var embeddedReactAssets embed.FS +- +-func RegisterHandlers(e *echo.Echo) { +- e.Use(middleware.StaticWithConfig(middleware.StaticConfig{ +- Skipper: nil, +- // Root directory from where the static content is served. +- Root: "dist", +- // Enable HTML5 mode by forwarding all not-found requests to root so that +- // SPA (single-page application) can handle the routing. +- HTML5: true, +- Browse: false, +- IgnoreBase: false, +- Filesystem: http.FS(embeddedReactAssets), +- })) +-} ++func RegisterHandlers(e *echo.Echo) {} +diff --git a/http/http_service.go b/http/http_service.go +index 63d0ffc..0621bf5 100644 +--- a/http/http_service.go ++++ b/http/http_service.go +@@ -114,8 +114,6 @@ func (httpSvc *HttpService) RegisterSharedRoutes(e *echo.Echo) { + e.POST("/api/backup", httpSvc.createBackupHandler, unlockRateLimiter) + e.GET("/logout", httpSvc.logoutHandler) + +- frontend.RegisterHandlers(e) +- + // restricted routes + // Configure middleware with the custom claims type + jwtConfig := echojwt.Config{ diff --git a/packages/albyhub/default.nix b/packages/albyhub/default.nix new file mode 100644 index 0000000..b715b7e --- /dev/null +++ b/packages/albyhub/default.nix @@ -0,0 +1,55 @@ +{ lib +, buildGoModule +, fetchFromGitHub +, stdenv +}: + +buildGoModule (finalAttrs: { + pname = "albyhub"; + version = "1.24.0"; + + src = fetchFromGitHub { + owner = "getAlby"; + repo = "hub"; + tag = "v${finalAttrs.version}"; + hash = "sha256-IC3rl/9aJ88GgvGfhcJb1/pQb3xIkhYih1hLPJ8itP8="; + }; + + vendorHash = "sha256-A4OsntoJUDkvWJxnZFFxw5AjUPmwRl764nQ5FEA2yeo="; + + patches = [ + ./0001-private-route-hints.patch + ./0003-loopback-bind-host.patch + ./0004-lnd-only.patch + ./0005-no-frontend.patch + ]; + + # LND-only, no-frontend build: the only native dependency needed for + # cgo (sqlite3) is the C/C++ runtime from stdenv.cc.cc. No nodejs/yarn + # (no frontend), no bark-ffi-go or ldk-node (removed backends). + buildInputs = [ + (lib.getLib stdenv.cc.cc) + ]; + + subPackages = [ + "cmd/http" + ]; + + ldflags = [ + "-X github.com/getAlby/hub/version.Tag=v${finalAttrs.version}" + "-s" + "-w" + ]; + + postInstall = '' + mv $out/bin/http $out/bin/albyhub + ''; + + meta = { + description = "Control lightning wallets over nostr"; + homepage = "https://github.com/getAlBy/hub"; + license = lib.licenses.asl20; + platforms = lib.platforms.linux; + mainProgram = "albyhub"; + }; +})