diff --git a/account/connect.go b/account/connect.go index e4c58258..572155bc 100644 --- a/account/connect.go +++ b/account/connect.go @@ -235,7 +235,7 @@ func (a *Service) openChannel(l lsp, force bool) error { a.log.Info("openChannel started...") _, err, _ := createChannelGroup.Do("createChannel", func() (interface{}, error) { err := a.connectAndOpenChannel(l, force) - a.log.Info("openChannel finished, error = %v", err) + a.log.Infof("openChannel finished, error = %v", err) return nil, err }) return err diff --git a/account/lnurl.go b/account/lnurl.go index a220f657..eb82dd24 100644 --- a/account/lnurl.go +++ b/account/lnurl.go @@ -500,7 +500,7 @@ func (a *Service) DecryptLNUrlPayMessage(paymentHash string, preimage []byte) (s return "", fmt.Errorf("Could not save deciphered message: %s", err) } - a.log.Info("DecryptLNUrlPayMessage: message = %q", info.SuccessAction.Message) + a.log.Infof("DecryptLNUrlPayMessage: message = %q", info.SuccessAction.Message) return info.SuccessAction.Message, nil } diff --git a/account/payments.go b/account/payments.go index bccb75e1..4e1fff4c 100644 --- a/account/payments.go +++ b/account/payments.go @@ -12,7 +12,6 @@ import ( "net/http" "sort" "strings" - "time" breezservice "github.com/breez/breez/breez" @@ -228,9 +227,17 @@ func (a *Service) sendPaymentForRequest(paymentRequest string, amountSatoshi int maxParts = 1 } // At this stage we are ready to send asynchronously the payment through the daemon. + var timeoutSeconds int32 = 60 + if useTor, _ := a.breezDB.GetUseTor(); useTor { + /* @nochiel: If Tor is active, extend the timeout to avoid + frequent payment timeout failures observed in testing. + */ + timeoutSeconds *= 2 + } + return a.sendPayment(decodedReq.PaymentHash, decodedReq, &routerrpc.SendPaymentRequest{ PaymentRequest: paymentRequest, - TimeoutSeconds: 60, + TimeoutSeconds: timeoutSeconds, FeeLimitSat: math.MaxInt64, MaxParts: maxParts, Amt: amountSatoshi, @@ -447,7 +454,6 @@ func (a *Service) sendPayment(paymentHash string, payReq *lnrpc.PayReq, sendRequ } a.log.Infof("sendPaymentForRequest finished successfully") a.syncSentPayments() - // TODO(@nochiel) FINDOUT Should we notify client here? If we do, what breaks? // a.notifyPaymentResult(true, sendRequest.PaymentRequest, paymentHash, "", "") return "", nil } diff --git a/app.go b/app.go index 911fd1ce..d489e9fa 100644 --- a/app.go +++ b/app.go @@ -17,6 +17,7 @@ import ( "github.com/breez/breez/db" "github.com/breez/breez/doubleratchet" "github.com/breez/breez/lnnode" + "github.com/breez/breez/tor" "github.com/btcsuite/btcwallet/walletdb" "github.com/lightninglabs/neutrino/filterdb" "github.com/lightningnetwork/lnd/channeldb" @@ -24,7 +25,7 @@ import ( "github.com/lightningnetwork/lnd/lnrpc/breezbackuprpc" ) -//Service is the interface to be implemeted by all breez services +// Service is the interface to be implemeted by all breez services type Service interface { Start() error Stop() error @@ -40,10 +41,41 @@ func (a *App) Start() error { a.log.Info("app.start before bootstrap") if err := chainservice.Bootstrap(a.cfg.WorkingDir); err != nil { - a.log.Info("app.start bootstrap error %v", err) + a.log.Infof("app.start bootstrap error %v", err) return err } + if useTor, _ := a.breezDB.GetUseTor(); useTor { + a.log.Info("app.Start: useTor.") + var err error + if a.tor, err = tor.StartTor(); err != nil { + a.breezDB.SetUseTor(false) + err = fmt.Errorf("app.Start: app unable to start Tor: %w", err) + a.log.Errorf("%v", err) + return err + } else { + + /* The current backup provider has a pointer to a.tor + but if a.tor was nil, then setting a.BackupManager.Tor + will only affect newly created backup providers. + Reset the current provider's tor pointer here. + */ + provider := a.BackupManager.GetProvider() + provider.SetTor(a.tor) + a.BackupManager.SetProvider(provider) + + a.BackupManager.Tor = a.tor + + if a.lnDaemon.TorConfig, err = a.tor.GetTorConfig(); err != nil { + a.breezDB.SetUseTor(false) + err = fmt.Errorf("app.Start: unable to get Tor config for daemon : %w", err) + a.log.Errorf("%v", err) + return err + } + + } + } + services := []Service{ a.lnDaemon, a.ServicesClient, @@ -85,6 +117,10 @@ func (a *App) Stop() error { doubleratchet.Stop() a.releaseBreezDB() + if a.tor != nil { + a.tor.Close() + } + a.wg.Wait() a.log.Infof("BreezApp shutdown successfully") return nil @@ -397,3 +433,18 @@ func (a *App) CheckLSPClosedChannelMismatch( } return &data.CheckLSPClosedChannelMismatchResponse{Mismatch: mismatch}, nil } + +func (a *App) EnableOrDisableTor(enable bool) error { + a.log.Infof("EnableOrDisableTor: setting enabled = %v", enable) + return a.breezDB.SetUseTor(enable) +} + +func (a *App) IsTorActive() bool { + a.log.Info("IsTorActive?") + + b, err := a.breezDB.GetUseTor() + if err != nil { + a.log.Infof("IsTorActive: %v", err) + } + return b +} diff --git a/app_init.go b/app_init.go index 0504fa60..703ad3bb 100644 --- a/app_init.go +++ b/app_init.go @@ -19,6 +19,7 @@ import ( breezlog "github.com/breez/breez/log" "github.com/breez/breez/services" "github.com/breez/breez/swapfunds" + "github.com/breez/breez/tor" "github.com/btcsuite/btclog" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lnrpc/breezbackuprpc" @@ -54,6 +55,8 @@ type App struct { notificationsChan chan data.NotificationEvent lspChanStateSyncer *lspChanStateSync + + tor *tor.Tor } // AppServices defined the interface needed in Breez library in order to functional @@ -132,6 +135,7 @@ func NewApp(workingDir string, applicationServices AppServices, startBeforeSync if err != nil { return nil, err } + app.BackupManager, err = backup.NewManager( applicationServices.BackupProviderName(), &AuthService{appServices: applicationServices}, diff --git a/backup/drive.go b/backup/drive.go index 587f7f9c..cf7b8fdf 100644 --- a/backup/drive.go +++ b/backup/drive.go @@ -13,6 +13,8 @@ import ( "strings" "time" + "github.com/breez/breez/tor" + "github.com/btcsuite/btclog" "golang.org/x/oauth2" drive "google.golang.org/api/drive/v3" @@ -35,6 +37,7 @@ type driveServiceError struct { func (d *driveServiceError) Error() string { return d.err.Error() } + func (d *driveServiceError) IsAuthError() bool { if ferr, ok := d.err.(*googleapi.Error); ok { return ferr.Code == 401 || ferr.Code == 403 @@ -196,7 +199,8 @@ func (p *GoogleDriveProvider) UploadBackupFiles(file string, nodeID string, encr p.log.Infof("Uploading file %v size: %v", fileName, info.Size()) uploadedFile, err := p.driveService.Files.Create(&drive.File{ Name: fileName, - Parents: []string{newBackupFolder.Id}}, + Parents: []string{newBackupFolder.Id}, + }, ).Media(file).Fields("md5Checksum").Do() if err != nil { p.log.Infof("uploadBackupFiles failed to upload file at folder:%v", newBackupFolder.Id) @@ -313,6 +317,10 @@ func (p *GoogleDriveProvider) DownloadBackupFiles(nodeID, backupID string) ([]st return downloaded, nil } +func (p *GoogleDriveProvider) SetTor(tor *tor.Tor) { + return +} + // nodeFolder is responsible for fetching the node folder. If it doesn't exist it creates it. func (p *GoogleDriveProvider) nodeFolder(nodeID string) (*drive.File, error) { r, err := p.driveService.Files.List().Spaces("appDataFolder"). diff --git a/backup/init.go b/backup/init.go index 32d87a96..ea9261e2 100644 --- a/backup/init.go +++ b/backup/init.go @@ -8,26 +8,37 @@ import ( "github.com/breez/breez/config" "github.com/breez/breez/data" + "github.com/breez/breez/tor" + "github.com/btcsuite/btclog" ) +type ProviderFactoryInfo struct { + authService AuthService + authData string + log btclog.Logger + tor *tor.Tor +} + // ProviderFactory is a factory for create a specific provider. // This is the function needed to be implemented for a new provider // to be registered and used. -type ProviderFactory func(authService AuthService, authData string, log btclog.Logger) (Provider, error) +type ProviderFactory func(providerFactoryInfo ProviderFactoryInfo) (Provider, error) -var ( - providersFactory = map[string]ProviderFactory{ - "gdrive": func(authService AuthService, authData string, log btclog.Logger) (Provider, error) { - return NewGoogleDriveProvider(authService, log) - }, - "remoteserver": func(authService AuthService, authData string, log btclog.Logger) (Provider, error) { - var providerData ProviderData - _ = json.Unmarshal([]byte(authData), &providerData) - return NewRemoteServerProvider(providerData, log) - }, - } -) +var providersFactory = map[string]ProviderFactory{ + "gdrive": func(providerFactoryInfo ProviderFactoryInfo) (Provider, error) { + return NewGoogleDriveProvider(providerFactoryInfo.authService, providerFactoryInfo.log) + }, + "remoteserver": func(providerFactoryInfo ProviderFactoryInfo) (Provider, error) { + var providerData ProviderData + _ = json.Unmarshal([]byte(providerFactoryInfo.authData), &providerData) + return NewRemoteServerProvider( + providerData, + providerFactoryInfo.log, + providerFactoryInfo.tor, + ) + }, +} // Manager holds the data needed for the backup to execute its work. type Manager struct { @@ -47,6 +58,8 @@ type Manager struct { encryptionType string mu sync.Mutex wg sync.WaitGroup + + Tor *tor.Tor } // NewManager creates a new Manager @@ -61,7 +74,7 @@ func NewManager( var provider Provider var err error if providerName != "" { - provider, err = createBackupProvider(providerName, authService, "", log) + provider, err = createBackupProvider(providerName, ProviderFactoryInfo{authService, "", log, nil}) if err != nil { return nil, err } @@ -91,10 +104,10 @@ func RegisterProvider(providerName string, factory ProviderFactory) { providersFactory[providerName] = factory } -func createBackupProvider(providerName string, authService AuthService, authData string, log btclog.Logger) (Provider, error) { +func createBackupProvider(providerName string, providerFactoryInfo ProviderFactoryInfo) (Provider, error) { factory, ok := providersFactory[providerName] if !ok { return nil, fmt.Errorf("provider not found for %v", providerName) } - return factory(authService, authData, log) + return factory(providerFactoryInfo) } diff --git a/backup/interface.go b/backup/interface.go index 813d52aa..b58e403f 100644 --- a/backup/interface.go +++ b/backup/interface.go @@ -1,5 +1,7 @@ package backup +import "github.com/breez/breez/tor" + // SnapshotInfo is an existing backup information for a specific node id. type SnapshotInfo struct { NodeID string @@ -23,6 +25,7 @@ type Provider interface { UploadBackupFiles(file string, nodeID string, encryptionType string) (string, error) AvailableSnapshots() ([]SnapshotInfo, error) DownloadBackupFiles(nodeID, backupID string) ([]string, error) + SetTor(t *tor.Tor) } // ProviderError is the error that is used by the Provider to tell the BackupService diff --git a/backup/manager.go b/backup/manager.go index 2617a1b9..b9eaea9e 100644 --- a/backup/manager.go +++ b/backup/manager.go @@ -201,6 +201,7 @@ func (b *Manager) Start() error { return nil } b.wg.Add(1) + go func() { defer b.wg.Done() @@ -453,7 +454,7 @@ func (b *Manager) getBackupIdentifier() (string, error) { func (b *Manager) SetBackupProvider(providerName, authData string) error { b.log.Infof("setting backup provider %v, authData: %v", providerName, authData) - provider, err := createBackupProvider(providerName, b.authService, authData, b.log) + provider, err := createBackupProvider(providerName, ProviderFactoryInfo{b.authService, authData, b.log, b.Tor}) if err != nil { return err } diff --git a/backup/manager_test.go b/backup/manager_test.go index b7a8e6f5..4fa920c0 100644 --- a/backup/manager_test.go +++ b/backup/manager_test.go @@ -12,6 +12,7 @@ import ( "github.com/breez/breez/config" "github.com/breez/breez/data" + "github.com/breez/breez/tor" "github.com/btcsuite/btclog" ) @@ -30,6 +31,7 @@ type MockTester struct { AvailableSnapshotsImpl func() ([]SnapshotInfo, error) DownloadBackupFilesImpl func(nodeID, backupID string) ([]string, error) MsgChannel chan data.NotificationEvent + tor *tor.Tor } func newDefaultMockTester() *MockTester { @@ -63,13 +65,17 @@ func (m *MockTester) DownloadBackupFiles(nodeID, backupID string) ([]string, err return m.DownloadBackupFilesImpl(nodeID, backupID) } +func (m *MockTester) SetTor(tor *tor.Tor) { + m.tor = tor +} + func prepareBackupData() (paths []string, nodeID string, err error) { return []string{"file1"}, "test-node-id", nil } func createTestManager(mp *MockTester) (manager *Manager, err error) { backupDelay = time.Duration(0) - RegisterProvider("mock", func(authServie AuthService, logger btclog.Logger) (Provider, error) { return mp, nil }) + RegisterProvider("mock", func(providerFactoryInfo ProviderFactoryInfo) (Provider, error) { return mp, nil }) ntfnChan := make(chan data.NotificationEvent, 100) dir := os.TempDir() diff --git a/backup/webdav.go b/backup/webdav.go index 4f4a8af5..3f9b84bf 100644 --- a/backup/webdav.go +++ b/backup/webdav.go @@ -9,6 +9,8 @@ import ( "net/url" "path/filepath" "strings" + + "github.com/breez/breez/tor" ) // A client represents a client connection to a {own|next}cloud @@ -16,6 +18,7 @@ type WebdavClient struct { Url *url.URL Username string Password string + Tor *tor.Tor } type WebdavRequestError struct { @@ -57,6 +60,7 @@ type FilePropStats struct { XMLName xml.Name `xml:"propstat"` props []FileProp `xml:"prop"` } + type FileProp struct { XMLName xml.Name `xml:"prop"` LastModified string `xml:"getlastmodified"` @@ -164,11 +168,26 @@ func (c *WebdavClient) ListDir(path string) (*ListFileResponse, error) { return &response, err } -func (c *WebdavClient) sendWebDavRequest(request string, path string, data []byte, headers map[string]string) ([]byte, error) { - fmt.Printf("webdav request %v: %v\n", request, path) +func (c *WebdavClient) sendWebDavRequest( + request string, + path string, + data []byte, + headers map[string]string, +) ([]byte, error) { + fmt.Printf("sendWebDavRequest %v: %v\n", request, path) - client := &http.Client{} - //joined := strings.Join([]string{c.Url.String(), relativeURL}, "/") + var client *http.Client + var err error + if t := c.Tor; t != nil { + fmt.Println("sendWebDavRequest: proxying request using Tor.") + client, err = t.NewHttpClient() + if err != nil { + return nil, fmt.Errorf("sendWebDavRequest: unable to create tor http client: %w", err) + } + } else { + client = &http.Client{} + } + // joined := strings.Join([]string{c.Url.String(), relativeURL}, "/") joined := joinPath(c.Url.String(), path) req, err := http.NewRequest(request, joined, bytes.NewReader(data)) if err != nil { @@ -205,7 +224,6 @@ func (c *WebdavClient) sendWebDavRequest(request string, path string, data []byt return nil, err } } - } return body, nil } diff --git a/backup/webdav_provider.go b/backup/webdav_provider.go index 62c86868..cd8b2ea3 100644 --- a/backup/webdav_provider.go +++ b/backup/webdav_provider.go @@ -11,6 +11,8 @@ import ( "strings" "time" + "github.com/breez/breez/tor" + "github.com/btcsuite/btclog" ) @@ -21,6 +23,7 @@ const ( type RemoteServerProvider struct { authData ProviderData log btclog.Logger + tor *tor.Tor } type ProviderData struct { @@ -42,6 +45,7 @@ type webdavProviderError struct { func (d *webdavProviderError) Error() string { return d.err.Error() } + func (d *webdavProviderError) IsAuthError() bool { if ferr, ok := d.err.(*WebdavRequestError); ok { status := ferr.StatusCode @@ -51,15 +55,21 @@ func (d *webdavProviderError) IsAuthError() bool { return false } -func NewRemoteServerProvider(authData ProviderData, log btclog.Logger) (*RemoteServerProvider, error) { +func NewRemoteServerProvider( + authData ProviderData, + log btclog.Logger, + tor *tor.Tor, +) (*RemoteServerProvider, error) { return &RemoteServerProvider{ authData: authData, log: log, + tor: tor, }, nil } func (n *RemoteServerProvider) getClient() (string, *WebdavClient, error) { c, err := Dial(n.authData.Url, n.authData.User, n.authData.Password) + c.Tor = n.tor return n.authData.BreezDir, c, err } @@ -109,7 +119,8 @@ func (n *RemoteServerProvider) UploadBackupFiles(file string, nodeID string, enc Encrypted: encryptionType != "", EncryptionType: encryptionType, ModifiedTime: time.Now().Format(time.RFC3339), - }} + }, + } data, err := json.Marshal(backupInfo) if err != nil { return "", err @@ -232,3 +243,7 @@ func (n *RemoteServerProvider) DownloadBackupFiles(nodeID, backupID string) ([]s } return downloaded, nil } + +func (p *RemoteServerProvider) SetTor(tor *tor.Tor) { + p.tor = tor +} diff --git a/bindings/api.go b/bindings/api.go index f84a669b..d39fdf18 100644 --- a/bindings/api.go +++ b/bindings/api.go @@ -948,6 +948,14 @@ func PublishTransaction(tx []byte) error { return getBreezApp().AccountService.PublishTransaction(tx) } +func EnableOrDisableTor(enable bool) (err error) { + return getBreezApp().EnableOrDisableTor(enable) +} + +func IsTorActive() bool { + return getBreezApp().IsTorActive() +} + func deliverNotifications(notificationsChan chan data.NotificationEvent, appServices AppServices) { for { notification := <-notificationsChan diff --git a/bindings/native_backup_provider.go b/bindings/native_backup_provider.go index 307161a5..8b672fb6 100644 --- a/bindings/native_backup_provider.go +++ b/bindings/native_backup_provider.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/breez/breez/backup" - "github.com/btcsuite/btclog" + "github.com/breez/breez/tor" ) // NativeBackupProvider is interface that serves as backup provider and is intended to be @@ -27,6 +27,7 @@ type nativeProviderError struct { func (d *nativeProviderError) Error() string { return d.err.Error() } + func (d *nativeProviderError) IsAuthError() bool { if strings.Contains(d.err.Error(), "AuthError") { return true @@ -72,9 +73,13 @@ func (b *NativeBackupProviderBridge) DownloadBackupFiles(nodeID, backupID string return strings.Split(files, ","), nil } +func (b *NativeBackupProviderBridge) SetTor(tor *tor.Tor) { + return +} + // RegisterNativeBackupProvider registered a native backup provider func RegisterNativeBackupProvider(name string, provider NativeBackupProvider) { - backup.RegisterProvider(name, func(authService backup.AuthService, authData string, log btclog.Logger) (backup.Provider, error) { + backup.RegisterProvider(name, func(providerFactoryInfo backup.ProviderFactoryInfo) (backup.Provider, error) { return &NativeBackupProviderBridge{nativeProvider: provider}, nil }) } diff --git a/config/init.go b/config/init.go index 2d81b56d..5bae11cc 100644 --- a/config/init.go +++ b/config/init.go @@ -42,7 +42,7 @@ type Config struct { BugReportURLSecret string `long:"bugreporturlsecret"` TxSpentURL string `long:"txspenturl"` - //Job Options + // Job Options JobCfg JobConfig `group:"Job Options"` } diff --git a/data/messages.pb.go b/data/messages.pb.go index 4b459010..4f0c6fca 100644 --- a/data/messages.pb.go +++ b/data/messages.pb.go @@ -1,17 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.15.8 +// protoc-gen-go v1.26.0 +// protoc v3.14.0 // source: messages.proto package data import ( - context "context" - proto "github.com/golang/protobuf/proto" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -25,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type SwapError int32 const ( @@ -7110,335 +7101,3 @@ func file_messages_proto_init() { file_messages_proto_goTypes = nil file_messages_proto_depIdxs = nil } - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConnInterface - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion6 - -// BreezAPIClient is the client API for BreezAPI service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type BreezAPIClient interface { - GetLSPList(ctx context.Context, in *LSPListRequest, opts ...grpc.CallOption) (*LSPList, error) - ConnectToLSP(ctx context.Context, in *ConnectLSPRequest, opts ...grpc.CallOption) (*ConnectLSPReply, error) - AddFundInit(ctx context.Context, in *AddFundInitRequest, opts ...grpc.CallOption) (*AddFundInitReply, error) - GetFundStatus(ctx context.Context, in *FundStatusRequest, opts ...grpc.CallOption) (*FundStatusReply, error) - AddInvoice(ctx context.Context, in *AddInvoiceRequest, opts ...grpc.CallOption) (*AddInvoiceReply, error) - PayInvoice(ctx context.Context, in *PayInvoiceRequest, opts ...grpc.CallOption) (*PaymentResponse, error) - RestartDaemon(ctx context.Context, in *RestartDaemonRequest, opts ...grpc.CallOption) (*RestartDaemonReply, error) - ListPayments(ctx context.Context, in *ListPaymentsRequest, opts ...grpc.CallOption) (*PaymentsList, error) -} - -type breezAPIClient struct { - cc grpc.ClientConnInterface -} - -func NewBreezAPIClient(cc grpc.ClientConnInterface) BreezAPIClient { - return &breezAPIClient{cc} -} - -func (c *breezAPIClient) GetLSPList(ctx context.Context, in *LSPListRequest, opts ...grpc.CallOption) (*LSPList, error) { - out := new(LSPList) - err := c.cc.Invoke(ctx, "/data.BreezAPI/GetLSPList", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *breezAPIClient) ConnectToLSP(ctx context.Context, in *ConnectLSPRequest, opts ...grpc.CallOption) (*ConnectLSPReply, error) { - out := new(ConnectLSPReply) - err := c.cc.Invoke(ctx, "/data.BreezAPI/ConnectToLSP", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *breezAPIClient) AddFundInit(ctx context.Context, in *AddFundInitRequest, opts ...grpc.CallOption) (*AddFundInitReply, error) { - out := new(AddFundInitReply) - err := c.cc.Invoke(ctx, "/data.BreezAPI/AddFundInit", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *breezAPIClient) GetFundStatus(ctx context.Context, in *FundStatusRequest, opts ...grpc.CallOption) (*FundStatusReply, error) { - out := new(FundStatusReply) - err := c.cc.Invoke(ctx, "/data.BreezAPI/GetFundStatus", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *breezAPIClient) AddInvoice(ctx context.Context, in *AddInvoiceRequest, opts ...grpc.CallOption) (*AddInvoiceReply, error) { - out := new(AddInvoiceReply) - err := c.cc.Invoke(ctx, "/data.BreezAPI/AddInvoice", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *breezAPIClient) PayInvoice(ctx context.Context, in *PayInvoiceRequest, opts ...grpc.CallOption) (*PaymentResponse, error) { - out := new(PaymentResponse) - err := c.cc.Invoke(ctx, "/data.BreezAPI/PayInvoice", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *breezAPIClient) RestartDaemon(ctx context.Context, in *RestartDaemonRequest, opts ...grpc.CallOption) (*RestartDaemonReply, error) { - out := new(RestartDaemonReply) - err := c.cc.Invoke(ctx, "/data.BreezAPI/RestartDaemon", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *breezAPIClient) ListPayments(ctx context.Context, in *ListPaymentsRequest, opts ...grpc.CallOption) (*PaymentsList, error) { - out := new(PaymentsList) - err := c.cc.Invoke(ctx, "/data.BreezAPI/ListPayments", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// BreezAPIServer is the server API for BreezAPI service. -type BreezAPIServer interface { - GetLSPList(context.Context, *LSPListRequest) (*LSPList, error) - ConnectToLSP(context.Context, *ConnectLSPRequest) (*ConnectLSPReply, error) - AddFundInit(context.Context, *AddFundInitRequest) (*AddFundInitReply, error) - GetFundStatus(context.Context, *FundStatusRequest) (*FundStatusReply, error) - AddInvoice(context.Context, *AddInvoiceRequest) (*AddInvoiceReply, error) - PayInvoice(context.Context, *PayInvoiceRequest) (*PaymentResponse, error) - RestartDaemon(context.Context, *RestartDaemonRequest) (*RestartDaemonReply, error) - ListPayments(context.Context, *ListPaymentsRequest) (*PaymentsList, error) -} - -// UnimplementedBreezAPIServer can be embedded to have forward compatible implementations. -type UnimplementedBreezAPIServer struct { -} - -func (*UnimplementedBreezAPIServer) GetLSPList(context.Context, *LSPListRequest) (*LSPList, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetLSPList not implemented") -} -func (*UnimplementedBreezAPIServer) ConnectToLSP(context.Context, *ConnectLSPRequest) (*ConnectLSPReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method ConnectToLSP not implemented") -} -func (*UnimplementedBreezAPIServer) AddFundInit(context.Context, *AddFundInitRequest) (*AddFundInitReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method AddFundInit not implemented") -} -func (*UnimplementedBreezAPIServer) GetFundStatus(context.Context, *FundStatusRequest) (*FundStatusReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetFundStatus not implemented") -} -func (*UnimplementedBreezAPIServer) AddInvoice(context.Context, *AddInvoiceRequest) (*AddInvoiceReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method AddInvoice not implemented") -} -func (*UnimplementedBreezAPIServer) PayInvoice(context.Context, *PayInvoiceRequest) (*PaymentResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method PayInvoice not implemented") -} -func (*UnimplementedBreezAPIServer) RestartDaemon(context.Context, *RestartDaemonRequest) (*RestartDaemonReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method RestartDaemon not implemented") -} -func (*UnimplementedBreezAPIServer) ListPayments(context.Context, *ListPaymentsRequest) (*PaymentsList, error) { - return nil, status.Errorf(codes.Unimplemented, "method ListPayments not implemented") -} - -func RegisterBreezAPIServer(s *grpc.Server, srv BreezAPIServer) { - s.RegisterService(&_BreezAPI_serviceDesc, srv) -} - -func _BreezAPI_GetLSPList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(LSPListRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).GetLSPList(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/GetLSPList", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).GetLSPList(ctx, req.(*LSPListRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BreezAPI_ConnectToLSP_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ConnectLSPRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).ConnectToLSP(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/ConnectToLSP", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).ConnectToLSP(ctx, req.(*ConnectLSPRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BreezAPI_AddFundInit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AddFundInitRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).AddFundInit(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/AddFundInit", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).AddFundInit(ctx, req.(*AddFundInitRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BreezAPI_GetFundStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FundStatusRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).GetFundStatus(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/GetFundStatus", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).GetFundStatus(ctx, req.(*FundStatusRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BreezAPI_AddInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AddInvoiceRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).AddInvoice(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/AddInvoice", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).AddInvoice(ctx, req.(*AddInvoiceRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BreezAPI_PayInvoice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(PayInvoiceRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).PayInvoice(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/PayInvoice", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).PayInvoice(ctx, req.(*PayInvoiceRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BreezAPI_RestartDaemon_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(RestartDaemonRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).RestartDaemon(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/RestartDaemon", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).RestartDaemon(ctx, req.(*RestartDaemonRequest)) - } - return interceptor(ctx, in, info, handler) -} - -func _BreezAPI_ListPayments_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(ListPaymentsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(BreezAPIServer).ListPayments(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/data.BreezAPI/ListPayments", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(BreezAPIServer).ListPayments(ctx, req.(*ListPaymentsRequest)) - } - return interceptor(ctx, in, info, handler) -} - -var _BreezAPI_serviceDesc = grpc.ServiceDesc{ - ServiceName: "data.BreezAPI", - HandlerType: (*BreezAPIServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetLSPList", - Handler: _BreezAPI_GetLSPList_Handler, - }, - { - MethodName: "ConnectToLSP", - Handler: _BreezAPI_ConnectToLSP_Handler, - }, - { - MethodName: "AddFundInit", - Handler: _BreezAPI_AddFundInit_Handler, - }, - { - MethodName: "GetFundStatus", - Handler: _BreezAPI_GetFundStatus_Handler, - }, - { - MethodName: "AddInvoice", - Handler: _BreezAPI_AddInvoice_Handler, - }, - { - MethodName: "PayInvoice", - Handler: _BreezAPI_PayInvoice_Handler, - }, - { - MethodName: "RestartDaemon", - Handler: _BreezAPI_RestartDaemon_Handler, - }, - { - MethodName: "ListPayments", - Handler: _BreezAPI_ListPayments_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "messages.proto", -} diff --git a/db/db.go b/db/db.go index 71afa77a..f3dbf4e9 100644 --- a/db/db.go +++ b/db/db.go @@ -51,6 +51,9 @@ const ( //lnurl-pay lnurlPayBucket = "lnurl-pay-bucket" + + //Tor + torBucket = "tor" ) var ( @@ -183,6 +186,11 @@ func openDB(dbPath string, log btclog.Logger) (*DB, error) { return err } + _, err = tx.CreateBucketIfNotExists([]byte(torBucket)) + if err != nil { + return err + } + return nil }) if err != nil { diff --git a/db/tor.go b/db/tor.go new file mode 100644 index 00000000..27fcb4c2 --- /dev/null +++ b/db/tor.go @@ -0,0 +1,26 @@ +package db + +const ( + useTorKey = "useTor" +) + +func (db *DB) SetUseTor(useTor bool) error { + + var _useTor byte + if useTor { + _useTor = 1 + } + + return db.saveItem([]byte(torBucket), []byte(useTorKey), []byte{_useTor}) +} + +func (db *DB) GetUseTor() (result bool, err error) { + + if useTor, err := db.fetchItem([]byte(torBucket), []byte(useTorKey)); err == nil { + if useTor != nil && useTor[0] == 1 { + result = true + } + } + + return result, err +} diff --git a/go.mod b/go.mod index 0ce60fa2..d8ec663b 100644 --- a/go.mod +++ b/go.mod @@ -12,10 +12,12 @@ require ( github.com/btcsuite/btcwallet/walletdb v1.3.4 github.com/btcsuite/btcwallet/wtxmgr v1.2.1-0.20200616004619-ca24ed58cf8a github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e // indirect + github.com/cretz/bine v0.2.0 github.com/decred/dcrd/lru v1.1.0 // indirect github.com/dustin/go-humanize v1.0.0 github.com/fiatjaf/go-lnurl v1.3.1 github.com/golang/protobuf v1.4.2 + github.com/ipsn/go-libtor v1.0.380 github.com/jessevdk/go-flags v1.4.0 github.com/kkdai/bstream v1.0.0 // indirect github.com/lightninglabs/neutrino v0.11.1-0.20201210023533-e1978372d15e @@ -27,11 +29,13 @@ require ( github.com/tyler-smith/go-bip32 v0.0.0-20170922074101-2c9cfd177564 github.com/urfave/cli v1.22.1 go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50 - golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a + golang.org/dl v0.0.0-20210713194856-38ddc79c2163 // indirect + golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 golang.org/x/mobile v0.0.0-20210220033013-bdb1ca9a1e08 // indirect - golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 + golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e + golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect google.golang.org/api v0.20.0 google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98 // indirect google.golang.org/grpc v1.29.1 diff --git a/go.sum b/go.sum index d634ddc3..f225df2a 100644 --- a/go.sum +++ b/go.sum @@ -210,6 +210,9 @@ github.com/cpu/goacmedns v0.0.2/go.mod h1:4MipLkI+qScwqtVxcNO6okBhbgRrr7/tKXUSgS github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw= +github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= +github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -331,6 +334,10 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= +github.com/ipsn/go-libtor v1.0.99 h1:zV0uWk9I38goHThA7lIgJfOb3vsZoo3ym/EyNmSPN3Q= +github.com/ipsn/go-libtor v1.0.99/go.mod h1:6rIeHU7irp8ZH8E/JqaEOKlD6s4vSSUh4ngHelhlSMw= +github.com/ipsn/go-libtor v1.0.380 h1:hCmALDBe3bPpgwMunonMLArrG41MxzpE91Bk8KQYnYM= +github.com/ipsn/go-libtor v1.0.380/go.mod h1:6rIeHU7irp8ZH8E/JqaEOKlD6s4vSSUh4ngHelhlSMw= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= @@ -568,6 +575,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/studio-b12/gowebdav v0.0.0-20210427212133-86f8378cf140 h1:JCSn/2k3AQ0aJGs5Yx2xv6qrW0CAULc1E+xtSxeeQ/E= github.com/studio-b12/gowebdav v0.0.0-20210427212133-86f8378cf140/go.mod h1:gCcfDlA1Y7GqOaeEKw5l9dOGx1VLdc/HuQSlQAaZ30s= github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= @@ -621,11 +630,14 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +golang.org/dl v0.0.0-20210713194856-38ddc79c2163 h1:jXLgj2BCnzX1kzp3/qXSSiXUud5aMgfJ8eVxlhBJ9cA= +golang.org/dl v0.0.0-20210713194856-38ddc79c2163/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -644,6 +656,8 @@ golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf h1:B2n+Zi5QeYRDAEodEu72OS golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -714,6 +728,10 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3ob golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -764,6 +782,11 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -772,6 +795,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -921,6 +946,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/lnnode/daemon.go b/lnnode/daemon.go index 87ef6bb0..2a74328c 100644 --- a/lnnode/daemon.go +++ b/lnnode/daemon.go @@ -12,6 +12,8 @@ import ( "github.com/breez/breez/chainservice" "github.com/breez/breez/channeldbservice" breezlog "github.com/breez/breez/log" + "github.com/breez/breez/tor" + "github.com/dustin/go-humanize" "github.com/jessevdk/go-flags" "github.com/lightningnetwork/lnd" @@ -30,10 +32,12 @@ const ( activeGraceDuration = time.Second * 15 ) +var ErrDaemonAlreadyStarted = errors.New("Daemon already started.") + // Start is used to start the lightning network daemon. func (d *Daemon) Start() error { if atomic.SwapInt32(&d.started, 1) == 1 { - return errors.New("Daemon already started") + return ErrDaemonAlreadyStarted } d.startTime = time.Now() @@ -264,11 +268,12 @@ func (d *Daemon) startDaemon() error { chainService: chainSevice, readyChan: readyChan, chanDB: chanDB} - lndConfig, err := d.createConfig(deps.workingDir) + lndConfig, err := d.createConfig(deps.workingDir, d.TorConfig) if err != nil { d.log.Errorf("failed to create config %v", err) } - d.log.Infof("Stating LND Daemon") + + d.log.Info("Starting LND Daemon.") err = lnd.Main(lndConfig, lnd.ListenerCfg{}, signal.ShutdownChannel(), deps) if err != nil { d.log.Errorf("Breez main function returned with error: %v", err) @@ -281,7 +286,7 @@ func (d *Daemon) startDaemon() error { return nil } -func (d *Daemon) createConfig(workingDir string) (*lnd.Config, error) { +func (d *Daemon) createConfig(workingDir string, torConfig *tor.TorConfig) (*lnd.Config, error) { lndConfig := lnd.DefaultConfig() lndConfig.Bitcoin.Active = true if d.cfg.Network == "mainnet" { @@ -299,6 +304,16 @@ func (d *Daemon) createConfig(workingDir string) (*lnd.Config, error) { d.log.Errorf("Failed to parse config %v", err) return nil, err } + + if torConfig != nil { + if torConfig.SOCKSPort > 0 { + d.log.Infof("Configuring daemon with Tor settings. torConfig.Active : %v.", torConfig.Active) + cfg.Tor.Active = torConfig.Active + cfg.Tor.SOCKS = fmt.Sprint(torConfig.SOCKSPort) + cfg.Tor.Control = fmt.Sprint(torConfig.ControlPort) + } + } + if d.startBeforeSync { lndConfig.InitialHeadersSyncDelta = time.Hour * 2 } diff --git a/lnnode/init.go b/lnnode/init.go index 0988b1a6..3badfa87 100644 --- a/lnnode/init.go +++ b/lnnode/init.go @@ -11,6 +11,7 @@ import ( "github.com/breez/breez/config" "github.com/breez/breez/db" breezlog "github.com/breez/breez/log" + "github.com/breez/breez/tor" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btclog" "github.com/lightningnetwork/lnd/channeldb" @@ -69,6 +70,8 @@ type Daemon struct { ntfnServer *subscribe.Server quitChan chan struct{} startBeforeSync bool + + TorConfig *tor.TorConfig } // NewDaemon is used to create a new daemon that wraps a lightning diff --git a/lsp_chan_state.go b/lsp_chan_state.go index 3277ea3f..3ea9df46 100644 --- a/lsp_chan_state.go +++ b/lsp_chan_state.go @@ -354,7 +354,7 @@ func (a *lspChanStateSync) collectChannelsStatus() ( func (a *lspChanStateSync) unconfirmedChannelsStatus(oldStatus *data.UnconfirmedChannelsStatus) ( *data.UnconfirmedChannelsStatus, error) { - a.log.Info("unconfirmedChannelsStatus started: %v", oldStatus) + a.log.Infof("unconfirmedChannelsStatus started: %v", oldStatus) lspList, err := a.breezAPI.LSPList() if err != nil { diff --git a/swapfunds/addfunds.go b/swapfunds/addfunds.go index 787891b2..617f7ad6 100644 --- a/swapfunds/addfunds.go +++ b/swapfunds/addfunds.go @@ -571,7 +571,7 @@ func (s *Service) createSwapInvoice(addressInfo *db.SwapAddressInfo) (payReq str }) if err != nil { - s.log.Error("unable to create invoice: %v", err) + s.log.Errorf("unable to create invoice: %v", err) return "", data.SwapError_NO_ERROR, err } diff --git a/sync/channelswatcher.go b/sync/channelswatcher.go index bed0186a..bf9eae04 100644 --- a/sync/channelswatcher.go +++ b/sync/channelswatcher.go @@ -92,7 +92,7 @@ func NewChannelsWatcher( if err != nil && err != chainntnfs.ErrSpendHintNotFound { return nil, fmt.Errorf("failed to query spent hint %v", err) } - log.Info("Query hint for channel %v = %v", fundingOut.String(), startBlock) + log.Infof("Query hint for channel %v = %v", fundingOut.String(), startBlock) if channelBlockHeight < uint64(startBlock) { channelBlockHeight = uint64(startBlock) } @@ -126,7 +126,7 @@ func (b *ChannelsWatcher) Scan(tipHeight uint64) (bool, error) { if err != nil { return false, err } - b.log.Info("fetchChannelsWatcherBlockHeight = %v", startHeight) + b.log.Infof("fetchChannelsWatcherBlockHeight = %v", startHeight) if b.firstChannelBlockHeight > startHeight { startHeight = b.firstChannelBlockHeight } diff --git a/tor/tor.go b/tor/tor.go new file mode 100644 index 00000000..470c28eb --- /dev/null +++ b/tor/tor.go @@ -0,0 +1,190 @@ +// TODO(nochiel) Add useful commands to manage Tor to the developer panel. +// NB. We can use Tor ControlPort commands to change config or query Tor at runtime. +// Ref. https://gitweb.torproject.org/torspec.git/tree/control-spec.txt +package tor + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "os" + "strconv" + "strings" + "time" + + "github.com/cretz/bine/tor" + "github.com/ipsn/go-libtor" +) + +type Tor tor.Tor + +var ( + TorController *Tor +) + +/* +func init() { + TorController, _ = startTor() +} +*/ + +func (t *Tor) NewHttpClient() (*http.Client, error) { + + _t := tor.Tor(*t) + dialer, err := _t.Dialer(nil, nil) + if err != nil { + return nil, fmt.Errorf("NewHttpClient: %w", err) + } + + transport := &http.Transport{DialContext: dialer.DialContext} + client := &http.Client{Transport: transport} + + return client, nil +} + +func StartTor() (result *Tor, err error) { + // FIXME(nochiel) Give Tor a logger. + + // a.log.Info("StartTor: Starting Tor.") + + // FIXME(nochiel) Use breez's error log for DebugWriter + torStartConf := &tor.StartConf{ + ProcessCreator: libtor.Creator, + UseEmbeddedControlConn: true, + TempDataDirBase: os.TempDir(), + EnableNetwork: true, + DebugWriter: os.Stderr, + // /* FIXME(nochiel) DebugWriter: a.log, */ + } + t, err := tor.Start(nil, torStartConf) + if err != nil { + // a.log.Errorf("StartTor failed: %v", err) + return nil, err + } + + dialCtx, dialCancel := context.WithTimeout(context.Background(), time.Minute) + defer dialCancel() + + dialer, err := t.Dialer(dialCtx, nil) + if err != nil { + t.Close() + return nil, err + } + + transport := &http.Transport{DialContext: dialer.DialContext} + client := &http.Client{Transport: transport} + // a.log.Info("StartTor: Attempting to GET https://check.torproject.org.") + resp, err := client.Get("https://check.torproject.org") + if err != nil { + t.Close() + return nil, err + } + + if resp.StatusCode != 200 && resp.StatusCode != 320 { + return nil, fmt.Errorf("StartTor: Error in http request: %s", resp.Status) + } + + const ( + torIsNotInUseMessage = "Sorry. You are not using Tor." + torIsInUseMessage = "Congratulations. This browser is configured to use Tor." + ) + + // a.log.Info("StartTor: Parsing response body from Tor request.") + parsed, err := io.ReadAll(resp.Body) + defer resp.Body.Close() + if err != nil { + t.Close() + return nil, err + } + + // a.log.Info("StartTor: Checking if Tor has started.") + if strings.Contains(string(parsed), torIsNotInUseMessage) { + t.Close() + err := fmt.Errorf("Tor could not start.") + // a.log.Errorf("StartTor: %v.", err) + return nil, err + } + // FIXME(nochiel): Is this a robust way of testing a Tor connection? + if strings.Contains(string(parsed), torIsInUseMessage) { + // a.log.Info("StartTor: Tor has started.") + } + + _tor := Tor(*t) + + return &_tor, nil +} + +type TorConfig struct { + SOCKSPort int + ControlPort int + Active bool +} + +func (t *Tor) GetTorConfig() (torConfig *TorConfig, err error) { + // FIXME(nochiel) Add logging. + + getTorProxyAddress := func(t *Tor) (proxyAddress string, err error) { + if t != nil { + control := t.Control + info, err := control.GetInfo("net/listeners/socks") + if err != nil { + return "", err + } + if len(info) != 1 || info[0].Key != "net/listeners/socks" { + return "", fmt.Errorf("Unable to get socks proxy address") + } + + fmt.Printf("getTorProxyAddress got info: %v\n", *info[0]) + // proxyNetwork := "tcp" + proxyAddress = info[0].Val + if strings.HasPrefix(proxyAddress, "unix:") { + proxyAddress = proxyAddress[5:] + // proxyNetwork = "unix" + } else { + // proxyNetwork = "tcp" + } + + return "socks://" + proxyAddress, nil + } + + return "", fmt.Errorf("getTorProxyAddress: tor is not initialised.") + } + + proxyAddress, err := getTorProxyAddress(t) + if err != nil { + t.Close() + // d.log.Errorf("StartTor: Unable to get Tor Proxy address: %s.", err) + return nil, err + } + + proxyUrl, err := url.Parse(proxyAddress) + if err != nil { + t.Close() + // d.log.Errorf("Unable to parse Tor Proxy address: %s.", err) + return nil, err + } + + torConfig = &TorConfig{Active: true} + torConfig.SOCKSPort, err = strconv.Atoi(proxyUrl.Port()) + if err != nil { + t.Close() + return nil, fmt.Errorf("Failed to parse Tor config for proxyUrl.Port: %v.", err) + } + + torConfig.ControlPort = t.ControlPort + + // d.log.Infof("startTor: saving Tor configuration for lnnode.") + return torConfig, nil + +} + +func (t *Tor) Close() { + + if t != nil { + temp := tor.Tor(*t) + _t := &temp + _t.Close() + } +}