Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into update-node-page
Browse files Browse the repository at this point in the history
  • Loading branch information
rolznz committed Jan 10, 2025
2 parents 234d7c7 + d1da0e4 commit 1ae6617
Show file tree
Hide file tree
Showing 66 changed files with 2,456 additions and 767 deletions.
39 changes: 35 additions & 4 deletions alby/alby_oauth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,20 @@ func (svc *albyOAuthService) GetInfo(ctx context.Context) (*AlbyInfo, error) {
LatestReleaseNotes string `json:"latest_release_notes"`
}

type albyInfoIncident struct {
Name string `json:"name"`
Started string `json:"started"`
Status string `json:"status"`
Impact string `json:"impact"`
Url string `json:"url"`
}

type albyInfo struct {
Hub albyInfoHub `json:"hub"`
// TODO: consider getting healthcheck/incident info and showing in the hub
Hub albyInfoHub `json:"hub"`
Status string `json:"status"`
Healthy bool `json:"healthy"`
AccountAvailable bool `json:"account_available"` // false if country is blocked (can still use Alby Hub without an Alby Account)
Incidents []albyInfoIncident `json:"incidents"`
}

body, err := io.ReadAll(res.Body)
Expand All @@ -279,11 +290,26 @@ func (svc *albyOAuthService) GetInfo(ctx context.Context) (*AlbyInfo, error) {
return nil, err
}

incidents := []AlbyInfoIncident{}
for _, incident := range info.Incidents {
incidents = append(incidents, AlbyInfoIncident{
Name: incident.Name,
Started: incident.Started,
Status: incident.Status,
Impact: incident.Impact,
Url: incident.Url,
})
}

return &AlbyInfo{
Hub: AlbyInfoHub{
LatestVersion: info.Hub.LatestVersion,
LatestReleaseNotes: info.Hub.LatestReleaseNotes,
},
Status: info.Status,
Healthy: info.Healthy,
AccountAvailable: info.AccountAvailable,
Incidents: incidents,
}, nil
}

Expand Down Expand Up @@ -702,8 +728,13 @@ func (svc *albyOAuthService) ConsumeEvent(ctx context.Context, event *events.Eve
}

if event.Event == "nwc_backup_channels" {
if err := svc.backupChannels(ctx, event); err != nil {
logger.Logger.WithError(err).Error("Failed to backup channels")
// if backup fails, try again (max 3 attempts)
for i := 0; i < 3; i++ {
if err := svc.backupChannels(ctx, event); err != nil {
logger.Logger.WithField("attempt", i).WithError(err).Error("Failed to backup channels")
continue
}
break
}
return
}
Expand Down
15 changes: 13 additions & 2 deletions alby/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,20 @@ type AlbyInfoHub struct {
LatestReleaseNotes string `json:"latestReleaseNotes"`
}

type AlbyInfoIncident struct {
Name string `json:"name"`
Started string `json:"started"`
Status string `json:"status"`
Impact string `json:"impact"`
Url string `json:"url"`
}

type AlbyInfo struct {
Hub AlbyInfoHub `json:"hub"`
// TODO: consider getting healthcheck/incident info and showing in the hub
Hub AlbyInfoHub `json:"hub"`
Status string `json:"status"`
Healthy bool `json:"healthy"`
AccountAvailable bool `json:"accountAvailable"` // false if country is blocked (can still use Alby Hub without an Alby Account)
Incidents []AlbyInfoIncident `json:"incidents"`
}

type AlbyMeHub struct {
Expand Down
29 changes: 28 additions & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ func (api *api) ListChannels(ctx context.Context) ([]Channel, error) {
Id: channel.Id,
RemotePubkey: channel.RemotePubkey,
FundingTxId: channel.FundingTxId,
FundingTxVout: channel.FundingTxVout,
Active: channel.Active,
Public: channel.Public,
InternalChannel: channel.InternalChannel,
Expand Down Expand Up @@ -441,7 +442,15 @@ func (api *api) ChangeUnlockPassword(changeUnlockPasswordRequest *ChangeUnlockPa
return errors.New("LNClient not started")
}

err := api.cfg.ChangeUnlockPassword(changeUnlockPasswordRequest.CurrentUnlockPassword, changeUnlockPasswordRequest.NewUnlockPassword)
autoUnlockPassword, err := api.cfg.Get("AutoUnlockPassword", "")
if err != nil {
return err
}
if autoUnlockPassword != "" {
return errors.New("Please disable auto-unlock before using this feature")
}

err = api.cfg.ChangeUnlockPassword(changeUnlockPasswordRequest.CurrentUnlockPassword, changeUnlockPasswordRequest.NewUnlockPassword)

if err != nil {
logger.Logger.WithError(err).Error("failed to change unlock password")
Expand All @@ -453,6 +462,21 @@ func (api *api) ChangeUnlockPassword(changeUnlockPasswordRequest *ChangeUnlockPa
return api.Stop()
}

func (api *api) SetAutoUnlockPassword(unlockPassword string) error {
if api.svc.GetLNClient() == nil {
return errors.New("LNClient not started")
}

err := api.cfg.SetAutoUnlockPassword(unlockPassword)

if err != nil {
logger.Logger.WithError(err).Error("failed to set auto unlock password")
return err
}

return nil
}

func (api *api) Stop() error {
if !startMutex.TryLock() {
// do not allow to stop twice in case this is somehow called twice
Expand Down Expand Up @@ -686,6 +710,7 @@ func (api *api) GetInfo(ctx context.Context) (*InfoResponse, error) {
info := InfoResponse{}
backendType, _ := api.cfg.Get("LNBackendType", "")
ldkVssEnabled, _ := api.cfg.Get("LdkVssEnabled", "")
autoUnlockPassword, _ := api.cfg.Get("AutoUnlockPassword", "")
info.SetupCompleted = api.cfg.SetupCompleted()
if api.startupError != nil {
info.StartupError = api.startupError.Error()
Expand All @@ -699,6 +724,8 @@ func (api *api) GetInfo(ctx context.Context) (*InfoResponse, error) {
info.EnableAdvancedSetup = api.cfg.GetEnv().EnableAdvancedSetup
info.LdkVssEnabled = ldkVssEnabled == "true"
info.VssSupported = backendType == config.LDKBackendType && api.cfg.GetEnv().LDKVssUrl != ""
info.AutoUnlockPasswordEnabled = autoUnlockPassword != ""
info.AutoUnlockPasswordSupported = api.cfg.GetEnv().IsDefaultClientId()
albyUserIdentifier, err := api.albyOAuthSvc.GetUserIdentifier()
if err != nil {
logger.Logger.WithError(err).Error("Failed to get alby user identifier")
Expand Down
8 changes: 8 additions & 0 deletions api/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ func (api *api) CreateBackup(unlockPassword string, w io.Writer) error {
return errors.New("invalid unlock password")
}

autoUnlockPassword, err := api.cfg.Get("AutoUnlockPassword", "")
if err != nil {
return err
}
if autoUnlockPassword != "" {
return errors.New("Please disable auto-unlock before using this feature")
}

workDir, err := filepath.Abs(api.cfg.GetEnv().Workdir)
if err != nil {
return fmt.Errorf("failed to get absolute workdir: %w", err)
Expand Down
41 changes: 24 additions & 17 deletions api/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type API interface {
GetChannelPeerSuggestions(ctx context.Context) ([]alby.ChannelPeerSuggestion, error)
ResetRouter(key string) error
ChangeUnlockPassword(changeUnlockPasswordRequest *ChangeUnlockPasswordRequest) error
SetAutoUnlockPassword(unlockPassword string) error
Stop() error
GetNodeConnectionInfo(ctx context.Context) (*lnclient.NodeConnectionInfo, error)
GetNodeStatus(ctx context.Context) (*lnclient.NodeStatus, error)
Expand Down Expand Up @@ -71,7 +72,7 @@ type App struct {
BudgetUsage uint64 `json:"budgetUsage"`
BudgetRenewal string `json:"budgetRenewal"`
Isolated bool `json:"isolated"`
Balance uint64 `json:"balance"`
Balance int64 `json:"balance"`
Metadata Metadata `json:"metadata,omitempty"`
}

Expand Down Expand Up @@ -159,22 +160,24 @@ type User struct {
}

type InfoResponse struct {
BackendType string `json:"backendType"`
SetupCompleted bool `json:"setupCompleted"`
OAuthRedirect bool `json:"oauthRedirect"`
Running bool `json:"running"`
Unlocked bool `json:"unlocked"`
AlbyAuthUrl string `json:"albyAuthUrl"`
NextBackupReminder string `json:"nextBackupReminder"`
AlbyUserIdentifier string `json:"albyUserIdentifier"`
AlbyAccountConnected bool `json:"albyAccountConnected"`
Version string `json:"version"`
Network string `json:"network"`
EnableAdvancedSetup bool `json:"enableAdvancedSetup"`
LdkVssEnabled bool `json:"ldkVssEnabled"`
VssSupported bool `json:"vssSupported"`
StartupError string `json:"startupError"`
StartupErrorTime time.Time `json:"startupErrorTime"`
BackendType string `json:"backendType"`
SetupCompleted bool `json:"setupCompleted"`
OAuthRedirect bool `json:"oauthRedirect"`
Running bool `json:"running"`
Unlocked bool `json:"unlocked"`
AlbyAuthUrl string `json:"albyAuthUrl"`
NextBackupReminder string `json:"nextBackupReminder"`
AlbyUserIdentifier string `json:"albyUserIdentifier"`
AlbyAccountConnected bool `json:"albyAccountConnected"`
Version string `json:"version"`
Network string `json:"network"`
EnableAdvancedSetup bool `json:"enableAdvancedSetup"`
LdkVssEnabled bool `json:"ldkVssEnabled"`
VssSupported bool `json:"vssSupported"`
StartupError string `json:"startupError"`
StartupErrorTime time.Time `json:"startupErrorTime"`
AutoUnlockPasswordSupported bool `json:"autoUnlockPasswordSupported"`
AutoUnlockPasswordEnabled bool `json:"autoUnlockPasswordEnabled"`
}

type MnemonicRequest struct {
Expand All @@ -189,6 +192,9 @@ type ChangeUnlockPasswordRequest struct {
CurrentUnlockPassword string `json:"currentUnlockPassword"`
NewUnlockPassword string `json:"newUnlockPassword"`
}
type AutoUnlockRequest struct {
UnlockPassword string `json:"unlockPassword"`
}

type ConnectPeerRequest = lnclient.ConnectPeerRequest
type OpenChannelRequest = lnclient.OpenChannelRequest
Expand Down Expand Up @@ -342,6 +348,7 @@ type Channel struct {
Id string `json:"id"`
RemotePubkey string `json:"remotePubkey"`
FundingTxId string `json:"fundingTxId"`
FundingTxVout uint32 `json:"fundingTxVout"`
Active bool `json:"active"`
Public bool `json:"public"`
InternalChannel interface{} `json:"internalChannel"`
Expand Down
14 changes: 14 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,20 @@ func (cfg *config) ChangeUnlockPassword(currentUnlockPassword string, newUnlockP
return nil
}

func (cfg *config) SetAutoUnlockPassword(unlockPassword string) error {
if unlockPassword != "" && !cfg.CheckUnlockPassword(unlockPassword) {
return errors.New("incorrect password")
}

err := cfg.SetUpdate("AutoUnlockPassword", unlockPassword, "")
if err != nil {
logger.Logger.WithError(err).Error("failed to update auto unlock password")
return err
}

return nil
}

func (cfg *config) CheckUnlockPassword(encryptionKey string) bool {
decryptedValue, err := cfg.Get("UnlockPasswordCheck", encryptionKey)

Expand Down
64 changes: 33 additions & 31 deletions config/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,38 @@ const (
)

type AppConfig struct {
Relay string `envconfig:"RELAY" default:"wss://relay.getalby.com/v1"`
LNBackendType string `envconfig:"LN_BACKEND_TYPE"`
LNDAddress string `envconfig:"LND_ADDRESS"`
LNDCertFile string `envconfig:"LND_CERT_FILE"`
LNDMacaroonFile string `envconfig:"LND_MACAROON_FILE"`
Workdir string `envconfig:"WORK_DIR"`
Port string `envconfig:"PORT" default:"8080"`
DatabaseUri string `envconfig:"DATABASE_URI" default:"nwc.db"`
JWTSecret string `envconfig:"JWT_SECRET"`
LogLevel string `envconfig:"LOG_LEVEL" default:"4"`
LogToFile bool `envconfig:"LOG_TO_FILE" default:"true"`
LDKNetwork string `envconfig:"LDK_NETWORK" default:"bitcoin"`
LDKEsploraServer string `envconfig:"LDK_ESPLORA_SERVER" default:"https://electrs.getalbypro.com"` // TODO: remove LDK prefix
LDKGossipSource string `envconfig:"LDK_GOSSIP_SOURCE"`
LDKLogLevel string `envconfig:"LDK_LOG_LEVEL" default:"3"`
LDKVssUrl string `envconfig:"LDK_VSS_URL"`
LDKListeningAddresses string `envconfig:"LDK_LISTENING_ADDRESSES" default:"0.0.0.0:9735,[::]:9735"`
MempoolApi string `envconfig:"MEMPOOL_API" default:"https://mempool.space/api"`
AlbyClientId string `envconfig:"ALBY_OAUTH_CLIENT_ID" default:"J2PbXS1yOf"`
AlbyClientSecret string `envconfig:"ALBY_OAUTH_CLIENT_SECRET" default:"rABK2n16IWjLTZ9M1uKU"`
BaseUrl string `envconfig:"BASE_URL"`
FrontendUrl string `envconfig:"FRONTEND_URL"`
LogEvents bool `envconfig:"LOG_EVENTS" default:"true"`
AutoLinkAlbyAccount bool `envconfig:"AUTO_LINK_ALBY_ACCOUNT" default:"true"`
PhoenixdAddress string `envconfig:"PHOENIXD_ADDRESS"`
PhoenixdAuthorization string `envconfig:"PHOENIXD_AUTHORIZATION"`
GoProfilerAddr string `envconfig:"GO_PROFILER_ADDR"`
DdProfilerEnabled bool `envconfig:"DD_PROFILER_ENABLED" default:"false"`
EnableAdvancedSetup bool `envconfig:"ENABLE_ADVANCED_SETUP" default:"true"`
AutoUnlockPassword string `envconfig:"AUTO_UNLOCK_PASSWORD"`
LogDBQueries bool `envconfig:"LOG_DB_QUERIES" default:"false"`
Relay string `envconfig:"RELAY" default:"wss://relay.getalby.com/v1"`
LNBackendType string `envconfig:"LN_BACKEND_TYPE"`
LNDAddress string `envconfig:"LND_ADDRESS"`
LNDCertFile string `envconfig:"LND_CERT_FILE"`
LNDMacaroonFile string `envconfig:"LND_MACAROON_FILE"`
Workdir string `envconfig:"WORK_DIR"`
Port string `envconfig:"PORT" default:"8080"`
DatabaseUri string `envconfig:"DATABASE_URI" default:"nwc.db"`
JWTSecret string `envconfig:"JWT_SECRET"`
LogLevel string `envconfig:"LOG_LEVEL" default:"4"`
LogToFile bool `envconfig:"LOG_TO_FILE" default:"true"`
LDKNetwork string `envconfig:"LDK_NETWORK" default:"bitcoin"`
LDKEsploraServer string `envconfig:"LDK_ESPLORA_SERVER" default:"https://electrs.getalbypro.com"` // TODO: remove LDK prefix
LDKGossipSource string `envconfig:"LDK_GOSSIP_SOURCE"`
LDKLogLevel string `envconfig:"LDK_LOG_LEVEL" default:"3"`
LDKVssUrl string `envconfig:"LDK_VSS_URL"`
LDKListeningAddresses string `envconfig:"LDK_LISTENING_ADDRESSES" default:"0.0.0.0:9735,[::]:9735"`
LDKTransientNetworkGraph bool `envconfig:"LDK_TRANSIENT_NETWORK_GRAPH" default:"false"`
MempoolApi string `envconfig:"MEMPOOL_API" default:"https://mempool.space/api"`
AlbyClientId string `envconfig:"ALBY_OAUTH_CLIENT_ID" default:"J2PbXS1yOf"`
AlbyClientSecret string `envconfig:"ALBY_OAUTH_CLIENT_SECRET" default:"rABK2n16IWjLTZ9M1uKU"`
BaseUrl string `envconfig:"BASE_URL"`
FrontendUrl string `envconfig:"FRONTEND_URL"`
LogEvents bool `envconfig:"LOG_EVENTS" default:"true"`
AutoLinkAlbyAccount bool `envconfig:"AUTO_LINK_ALBY_ACCOUNT" default:"true"`
PhoenixdAddress string `envconfig:"PHOENIXD_ADDRESS"`
PhoenixdAuthorization string `envconfig:"PHOENIXD_AUTHORIZATION"`
GoProfilerAddr string `envconfig:"GO_PROFILER_ADDR"`
DdProfilerEnabled bool `envconfig:"DD_PROFILER_ENABLED" default:"false"`
EnableAdvancedSetup bool `envconfig:"ENABLE_ADVANCED_SETUP" default:"true"`
AutoUnlockPassword string `envconfig:"AUTO_UNLOCK_PASSWORD"`
LogDBQueries bool `envconfig:"LOG_DB_QUERIES" default:"false"`
}

func (c *AppConfig) IsDefaultClientId() bool {
Expand All @@ -60,6 +61,7 @@ type Config interface {
GetEnv() *AppConfig
CheckUnlockPassword(password string) bool
ChangeUnlockPassword(currentUnlockPassword string, newUnlockPassword string) error
SetAutoUnlockPassword(unlockPassword string) error
SaveUnlockPasswordCheck(encryptionKey string) error
SetupCompleted() bool
}
1 change: 1 addition & 0 deletions constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@ const (
ERROR_RESTRICTED = "RESTRICTED"
ERROR_BAD_REQUEST = "BAD_REQUEST"
ERROR_NOT_FOUND = "NOT_FOUND"
ERROR_UNSUPPORTED_VERSION = "UNSUPPORTED_VERSION"
ERROR_OTHER = "OTHER"
)
6 changes: 3 additions & 3 deletions db/queries/get_isolated_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@ import (
"gorm.io/gorm"
)

func GetIsolatedBalance(tx *gorm.DB, appId uint) uint64 {
func GetIsolatedBalance(tx *gorm.DB, appId uint) int64 {
var received struct {
Sum uint64
Sum int64
}
tx.
Table("transactions").
Select("SUM(amount_msat) as sum").
Where("app_id = ? AND type = ? AND state = ?", appId, constants.TRANSACTION_TYPE_INCOMING, constants.TRANSACTION_STATE_SETTLED).Scan(&received)

var spent struct {
Sum uint64
Sum int64
}

tx.
Expand Down
Loading

0 comments on commit 1ae6617

Please sign in to comment.