From 8d1d453352520ccb177b3c1b2db361f51baa4778 Mon Sep 17 00:00:00 2001 From: beerosagos Date: Wed, 13 May 2026 10:03:13 +0000 Subject: [PATCH] lightning: encrypt stored seed Add platform hooks for storing a Lightning seed encryption key outside the backend config and use them on Android via the keystore. Activation now derives the mnemonic as before, generates a random 32-byte key in the backend, encrypts the mnemonic with AES-GCM, stores only the ciphertext in the Lightning config, and hands the base64-encoded key to the platform environment. On Android, the environment wraps that key with an account-specific AES key from AndroidKeyStore and stores the wrapped blob in SharedPreferences. Unlocking loads and unwraps the stored key, decrypts the mnemonic in the backend, and then connects Breez. Deactivation removes both the wrapped key and the encrypted mnemonic. Android intentionally treats missing wrapped keys as requiring Lightning reactivation. This can affect existing dev wallets created before this change, but the feature has no production users yet and the migration cost is acceptable at this stage. Other platforms keep returning false or stub implementations for now. This is intentional preparatory work so iOS, Qt, and web can adopt secure storage later without another backend API change. --- backend/backend.go | 10 ++ backend/backend_test.go | 8 + backend/bridgecommon/bridgecommon.go | 50 +++++- backend/bridgecommon/bridgecommon_test.go | 8 + backend/handlers/handlers_test.go | 26 ++-- backend/lightning/lightning.go | 144 +++++++++++++++++- backend/lightning/lightning_test.go | 76 ++++++++- backend/mobileserver/mobileserver.go | 26 ++-- cmd/servewallet/main.go | 20 +++ .../app/src/main/AndroidManifest.xml | 2 + .../ch/shiftcrypto/bitboxapp/GoViewModel.java | 20 +++ .../bitboxapp/LightningEncryptionHelper.java | 128 ++++++++++++++++ .../app/src/main/res/xml/backup_rules.xml | 5 + .../main/res/xml/data_extraction_rules.xml | 11 ++ .../BitBoxApp/BitBoxApp/BitBoxAppApp.swift | 14 ++ frontends/qt/server/server.go | 8 +- 16 files changed, 518 insertions(+), 38 deletions(-) create mode 100644 frontends/android/BitBoxApp/app/src/main/java/ch/shiftcrypto/bitboxapp/LightningEncryptionHelper.java create mode 100644 frontends/android/BitBoxApp/app/src/main/res/xml/backup_rules.xml create mode 100644 frontends/android/BitBoxApp/app/src/main/res/xml/data_extraction_rules.xml diff --git a/backend/backend.go b/backend/backend.go index 13c2231bbf..a21d642b22 100644 --- a/backend/backend.go +++ b/backend/backend.go @@ -196,6 +196,15 @@ type Environment interface { // OnAuthSettingChanged is called when the authentication (screen lock) setting is changed. // This is also called when the app launches with the current setting. OnAuthSettingChanged(enabled bool) + // CanEncryptLightningMnemonic reports whether Lightning mnemonics should be stored encrypted on + // this platform. + CanEncryptLightningMnemonic() bool + // StoreLightningEncryptionKey persists a backend-generated Lightning seed encryption key. + StoreLightningEncryptionKey(accountCode string, encryptionKey string) error + // LoadLightningEncryptionKey retrieves the stored Lightning seed encryption key. + LoadLightningEncryptionKey(accountCode string) (string, error) + // DeleteLightningEncryptionKey removes the persisted Lightning seed encryption key. + DeleteLightningEncryptionKey(accountCode string) error // BluetoothConnect tries to connect to the peripheral by the given identifier. // Use `backend.bluetooth.State()` to track failure. BluetoothConnect(identifier string) @@ -349,6 +358,7 @@ func NewBackend(arguments *arguments.Arguments, environment Environment) (*Backe backend.lightning = lightning.NewLightning(backend.config, backend.arguments.CacheDirectoryPath(), + backend.environment, backend.Keystore, backend.httpClient, backend.ratesUpdater, btcCoin) diff --git a/backend/backend_test.go b/backend/backend_test.go index 983af5227e..de1190e40f 100644 --- a/backend/backend_test.go +++ b/backend/backend_test.go @@ -245,6 +245,14 @@ func (e environment) Auth() {} func (e environment) OnAuthSettingChanged(bool) {} +func (e environment) CanEncryptLightningMnemonic() bool { return false } + +func (e environment) StoreLightningEncryptionKey(string, string) error { return nil } + +func (e environment) LoadLightningEncryptionKey(string) (string, error) { return "", nil } + +func (e environment) DeleteLightningEncryptionKey(string) error { return nil } + func (e environment) BluetoothConnect(string) {} type mockTransactionsSource struct { diff --git a/backend/bridgecommon/bridgecommon.go b/backend/bridgecommon/bridgecommon.go index c99dbb9f87..7bfffea77f 100644 --- a/backend/bridgecommon/bridgecommon.go +++ b/backend/bridgecommon/bridgecommon.go @@ -180,13 +180,17 @@ type BackendEnvironment struct { UsingMobileDataFunc func() bool // NativeLocaleFunc is used by the backend to query native app layer for user // preferred UI language. - NativeLocaleFunc func() string - GetSaveFilenameFunc func(string) string - SetDarkThemeFunc func(bool) - DetectDarkThemeFunc func() bool - AuthFunc func() - OnAuthSettingChangedFunc func(bool) - BluetoothConnectFunc func(string) + NativeLocaleFunc func() string + GetSaveFilenameFunc func(string) string + SetDarkThemeFunc func(bool) + DetectDarkThemeFunc func() bool + AuthFunc func() + OnAuthSettingChangedFunc func(bool) + CanEncryptLightningMnemonicFunc func() bool + StoreLightningEncryptionKeyFunc func(string, string) error + LoadLightningEncryptionKeyFunc func(string) (string, error) + DeleteLightningEncryptionKeyFunc func(string) error + BluetoothConnectFunc func(string) } // NotifyUser implements backend.Environment. @@ -265,6 +269,38 @@ func (env *BackendEnvironment) OnAuthSettingChanged(enabled bool) { } } +// CanEncryptLightningMnemonic implements backend.Environment. +func (env *BackendEnvironment) CanEncryptLightningMnemonic() bool { + if env.CanEncryptLightningMnemonicFunc != nil { + return env.CanEncryptLightningMnemonicFunc() + } + return false +} + +// StoreLightningEncryptionKey implements backend.Environment. +func (env *BackendEnvironment) StoreLightningEncryptionKey(accountCode string, encryptionKey string) error { + if env.StoreLightningEncryptionKeyFunc != nil { + return env.StoreLightningEncryptionKeyFunc(accountCode, encryptionKey) + } + return nil +} + +// LoadLightningEncryptionKey implements backend.Environment. +func (env *BackendEnvironment) LoadLightningEncryptionKey(accountCode string) (string, error) { + if env.LoadLightningEncryptionKeyFunc != nil { + return env.LoadLightningEncryptionKeyFunc(accountCode) + } + return "", nil +} + +// DeleteLightningEncryptionKey implements backend.Environment. +func (env *BackendEnvironment) DeleteLightningEncryptionKey(accountCode string) error { + if env.DeleteLightningEncryptionKeyFunc != nil { + return env.DeleteLightningEncryptionKeyFunc(accountCode) + } + return nil +} + // BluetoothConnect implements backend.Environment. func (env *BackendEnvironment) BluetoothConnect(identifier string) { if env.BluetoothConnectFunc != nil { diff --git a/backend/bridgecommon/bridgecommon_test.go b/backend/bridgecommon/bridgecommon_test.go index 296ada0464..1e30c117b6 100644 --- a/backend/bridgecommon/bridgecommon_test.go +++ b/backend/bridgecommon/bridgecommon_test.go @@ -61,6 +61,14 @@ func (e environment) Auth() {} func (e environment) OnAuthSettingChanged(bool) {} +func (e environment) CanEncryptLightningMnemonic() bool { return false } + +func (e environment) StoreLightningEncryptionKey(string, string) error { return nil } + +func (e environment) LoadLightningEncryptionKey(string) (string, error) { return "", nil } + +func (e environment) DeleteLightningEncryptionKey(string) error { return nil } + func (e environment) BluetoothConnect(string) {} // TestServeShutdownServe checks that you can call Serve twice in a row. diff --git a/backend/handlers/handlers_test.go b/backend/handlers/handlers_test.go index fe22e4dd1d..cd936be110 100644 --- a/backend/handlers/handlers_test.go +++ b/backend/handlers/handlers_test.go @@ -38,17 +38,21 @@ type backendEnv struct { Locale string // returned by NativeLocale } -func (e *backendEnv) NotifyUser(string) {} -func (e *backendEnv) SystemOpen(string) error { return nil } -func (e *backendEnv) DeviceInfos() []usb.DeviceInfo { return nil } -func (e *backendEnv) UsingMobileData() bool { return false } -func (e *backendEnv) NativeLocale() string { return e.Locale } -func (e *backendEnv) GetSaveFilename(string) string { return "" } -func (e *backendEnv) SetDarkTheme(bool) {} -func (e *backendEnv) DetectDarkTheme() bool { return false } -func (e *backendEnv) Auth() {} -func (e *backendEnv) OnAuthSettingChanged(bool) {} -func (e *backendEnv) BluetoothConnect(string) {} +func (e *backendEnv) NotifyUser(string) {} +func (e *backendEnv) SystemOpen(string) error { return nil } +func (e *backendEnv) DeviceInfos() []usb.DeviceInfo { return nil } +func (e *backendEnv) UsingMobileData() bool { return false } +func (e *backendEnv) NativeLocale() string { return e.Locale } +func (e *backendEnv) GetSaveFilename(string) string { return "" } +func (e *backendEnv) SetDarkTheme(bool) {} +func (e *backendEnv) DetectDarkTheme() bool { return false } +func (e *backendEnv) Auth() {} +func (e *backendEnv) OnAuthSettingChanged(bool) {} +func (e *backendEnv) CanEncryptLightningMnemonic() bool { return false } +func (e *backendEnv) StoreLightningEncryptionKey(string, string) error { return nil } +func (e *backendEnv) LoadLightningEncryptionKey(string) (string, error) { return "", nil } +func (e *backendEnv) DeleteLightningEncryptionKey(string) error { return nil } +func (e *backendEnv) BluetoothConnect(string) {} func TestGetNativeLocale(t *testing.T) { const ptLocale = "pt" diff --git a/backend/lightning/lightning.go b/backend/lightning/lightning.go index 873a41f981..9e7eec81f4 100644 --- a/backend/lightning/lightning.go +++ b/backend/lightning/lightning.go @@ -3,7 +3,12 @@ package lightning import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" "encoding/hex" + "io" "net/http" "os" "path" @@ -29,12 +34,21 @@ const ( breezApiKeyUrl = "https://bitboxapp.shiftcrypto.dev/lightning/breez-api-key" ) +// Keep this local to avoid importing backend.Environment and creating a package cycle. +type environment interface { + CanEncryptLightningMnemonic() bool + StoreLightningEncryptionKey(accountCode string, encryptionKey string) error + LoadLightningEncryptionKey(accountCode string) (string, error) + DeleteLightningEncryptionKey(accountCode string) error +} + // Lightning manages the Breez SDK lightning node. type Lightning struct { observable.Implementation backendConfig *config.Config cacheDirectoryPath string + environment environment getKeystore func() keystore.Keystore synced bool @@ -48,6 +62,7 @@ type Lightning struct { // NewLightning creates a new instance of the Lightning struct. func NewLightning(config *config.Config, cacheDirectoryPath string, + environment environment, getKeystore func() keystore.Keystore, httpClient *http.Client, ratesUpdater *rates.RateUpdater, @@ -55,6 +70,7 @@ func NewLightning(config *config.Config, return &Lightning{ backendConfig: config, cacheDirectoryPath: cacheDirectoryPath, + environment: environment, getKeystore: getKeystore, log: logging.Get().WithGroup("lightning"), synced: false, @@ -64,7 +80,8 @@ func NewLightning(config *config.Config, } } -// Activate first creates a mnemonic from the keystore entropy then connects to instance. +// Activate first creates a mnemonic from the keystore entropy, persists it, and connects to the +// instance. func (lightning *Lightning) Activate() error { if lightning.Account() != nil { return errp.New("Lightning accounts already configured") @@ -91,13 +108,25 @@ func (lightning *Lightning) Activate() error { return errp.New("Error generating mnemonic") } + accountCode := types.Code(strings.Join([]string{"v0-", hex.EncodeToString(fingerprint), "-ln-0"}, "")) + sealedMnemonic, err := lightning.sealMnemonic(string(accountCode), entropyMnemonic) + if err != nil { + lightning.log.WithError(err).Warn("Error configuring Lightning secure storage") + return errp.New("Could not configure Lightning secure storage on this device") + } + lightningAccount := config.LightningAccountConfig{ - Mnemonic: entropyMnemonic, + Mnemonic: sealedMnemonic, RootFingerprint: fingerprint, - Code: types.Code(strings.Join([]string{"v0-", hex.EncodeToString(fingerprint), "-ln-0"}, "")), + Code: accountCode, Number: 0, } if err = lightning.SetAccount(&lightningAccount); err != nil { + if lightning.environment.CanEncryptLightningMnemonic() { + if deleteErr := lightning.environment.DeleteLightningEncryptionKey(string(accountCode)); deleteErr != nil { + lightning.log.WithError(deleteErr).Warn("Error deleting lightning encryption key after activation failure") + } + } return err } @@ -149,6 +178,12 @@ func (lightning *Lightning) Deactivate() error { return err } + if lightning.environment.CanEncryptLightningMnemonic() { + if err := lightning.environment.DeleteLightningEncryptionKey(string(account.Code)); err != nil { + lightning.log.WithError(err).Warn("Error deleting lightning encryption key") + } + } + return nil } @@ -172,7 +207,6 @@ func (lightning *Lightning) Balance() (*accounts.Balance, error) { // before returning the balance EnsureSynced: &ensureSynced, }) - if err != nil { return nil, err } @@ -201,9 +235,15 @@ func (lightning *Lightning) connect(_ bool) error { return err } + mnemonic, err := lightning.unsealMnemonic(account) + if err != nil { + lightning.log.WithError(err).Warn("Error unlocking Lightning mnemonic") + return errp.New("Error unlocking Lightning mnemonic from the device") + } + // Construct the seed using mnemonic words or entropy bytes var seed breez_sdk_spark.Seed = breez_sdk_spark.SeedMnemonic{ - Mnemonic: account.Mnemonic, + Mnemonic: mnemonic, Passphrase: nil, } @@ -219,7 +259,9 @@ func (lightning *Lightning) connect(_ bool) error { config.PrivateEnabledDefault = true // Set the maximum fee to the fastest network recommended fee at the time of claim // with a leeway of 1 sats/vbyte - networkRecommendedInterface := breez_sdk_spark.MaxFee(breez_sdk_spark.MaxFeeNetworkRecommended{LeewaySatPerVbyte: 1}) + networkRecommendedInterface := breez_sdk_spark.MaxFee( + breez_sdk_spark.MaxFeeNetworkRecommended{LeewaySatPerVbyte: 1}, + ) config.MaxDepositClaimFee = &networkRecommendedInterface connectRequest := breez_sdk_spark.ConnectRequest{ @@ -252,6 +294,96 @@ func (lightning *Lightning) connect(_ bool) error { return nil } +func (lightning *Lightning) sealMnemonic(accountCode string, mnemonic string) (string, error) { + if !lightning.environment.CanEncryptLightningMnemonic() { + return mnemonic, nil + } + + encryptionKey := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, encryptionKey); err != nil { + return "", err + } + + sealedMnemonic, err := encryptMnemonic(mnemonic, encryptionKey) + if err != nil { + return "", err + } + + if err := lightning.environment.StoreLightningEncryptionKey( + accountCode, + base64.StdEncoding.EncodeToString(encryptionKey), + ); err != nil { + return "", err + } + + return sealedMnemonic, nil +} + +func (lightning *Lightning) unsealMnemonic(account *config.LightningAccountConfig) (string, error) { + if !lightning.environment.CanEncryptLightningMnemonic() { + return account.Mnemonic, nil + } + + encryptionKeyBase64, err := lightning.environment.LoadLightningEncryptionKey(string(account.Code)) + if err != nil { + return "", err + } + + encryptionKey, err := base64.StdEncoding.DecodeString(encryptionKeyBase64) + if err != nil { + return "", err + } + + mnemonic, err := decryptMnemonic(account.Mnemonic, encryptionKey) + if err != nil { + return "", err + } + + return mnemonic, nil +} + +func encryptMnemonic(mnemonic string, encryptionKey []byte) (string, error) { + block, err := aes.NewCipher(encryptionKey) + if err != nil { + return "", err + } + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return "", err + } + ciphertext := gcm.Seal(nil, nonce, []byte(mnemonic), nil) + return base64.StdEncoding.EncodeToString(append(nonce, ciphertext...)), nil +} + +func decryptMnemonic(sealedMnemonic string, encryptionKey []byte) (string, error) { + rawCiphertext, err := base64.StdEncoding.DecodeString(sealedMnemonic) + if err != nil { + return "", err + } + block, err := aes.NewCipher(encryptionKey) + if err != nil { + return "", err + } + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + if len(rawCiphertext) < gcm.NonceSize() { + return "", errp.New("ciphertext too short") + } + nonce := rawCiphertext[:gcm.NonceSize()] + ciphertext := rawCiphertext[gcm.NonceSize():] + plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + return "", err + } + return string(plaintext), nil +} + func (lightning *Lightning) getBreezApiKey() (*string, error) { _, breezApiKey, err := util.HTTPGet(lightning.httpClient, breezApiKeyUrl, "", int64(4096)) if err != nil { diff --git a/backend/lightning/lightning_test.go b/backend/lightning/lightning_test.go index b58081579c..afeab411ae 100644 --- a/backend/lightning/lightning_test.go +++ b/backend/lightning/lightning_test.go @@ -12,7 +12,47 @@ import ( "github.com/stretchr/testify/require" ) -func newTestLightning(t *testing.T) *Lightning { +type testEnvironment struct { + canEncrypt bool + keys map[string]string + storeErr error + loadErr error + deleteErr error + loadCalls int +} + +func (e *testEnvironment) CanEncryptLightningMnemonic() bool { + return e.canEncrypt +} + +func (e *testEnvironment) StoreLightningEncryptionKey(accountCode string, encryptionKey string) error { + if e.storeErr != nil { + return e.storeErr + } + if e.keys == nil { + e.keys = map[string]string{} + } + e.keys[accountCode] = encryptionKey + return nil +} + +func (e *testEnvironment) LoadLightningEncryptionKey(accountCode string) (string, error) { + e.loadCalls++ + if e.loadErr != nil { + return "", e.loadErr + } + return e.keys[accountCode], nil +} + +func (e *testEnvironment) DeleteLightningEncryptionKey(accountCode string) error { + if e.deleteErr != nil { + return e.deleteErr + } + delete(e.keys, accountCode) + return nil +} + +func newTestLightning(t *testing.T, environment environment) *Lightning { t.Helper() appConfigFilename := test.TstTempFile("appConfig") @@ -22,9 +62,14 @@ func newTestLightning(t *testing.T) *Lightning { cfg, err := config.NewConfig(appConfigFilename, accountsConfigFilename, lightningConfigFilename) require.NoError(t, err) + if environment == nil { + environment = &testEnvironment{} + } + return NewLightning( cfg, test.TstTempDir("lightning-cache"), + environment, func() keystore.Keystore { return nil }, &http.Client{}, nil, @@ -33,7 +78,7 @@ func newTestLightning(t *testing.T) *Lightning { } func TestAccount(t *testing.T) { - lightning := newTestLightning(t) + lightning := newTestLightning(t, nil) require.Nil(t, lightning.Account()) require.NoError(t, lightning.backendConfig.ModifyLightningConfig(func(cfg *config.LightningConfig) error { @@ -50,7 +95,7 @@ func TestAccount(t *testing.T) { } func TestSetAccount(t *testing.T) { - lightning := newTestLightning(t) + lightning := newTestLightning(t, nil) account := &config.LightningAccountConfig{ Mnemonic: "test mnemonic", @@ -73,3 +118,28 @@ func TestSetAccount(t *testing.T) { require.Nil(t, lightning.Account()) require.Empty(t, lightning.backendConfig.LightningConfig().Accounts) } + +func TestSealAndUnsealMnemonicEncrypted(t *testing.T) { + env := &testEnvironment{canEncrypt: true} + lightning := newTestLightning(t, env) + + sealedMnemonic, err := lightning.sealMnemonic("v0-deadbeef-ln-0", "test mnemonic") + require.NoError(t, err) + require.NotEqual(t, "test mnemonic", sealedMnemonic) + + mnemonic, err := lightning.unsealMnemonic(&config.LightningAccountConfig{ + Code: "v0-deadbeef-ln-0", + Mnemonic: sealedMnemonic, + }) + require.NoError(t, err) + require.Equal(t, "test mnemonic", mnemonic) + require.Equal(t, 1, env.loadCalls) + + mnemonic, err = lightning.unsealMnemonic(&config.LightningAccountConfig{ + Code: "v0-deadbeef-ln-0", + Mnemonic: sealedMnemonic, + }) + require.NoError(t, err) + require.Equal(t, "test mnemonic", mnemonic) + require.Equal(t, 2, env.loadCalls) +} diff --git a/backend/mobileserver/mobileserver.go b/backend/mobileserver/mobileserver.go index 4d70086166..756cff0524 100644 --- a/backend/mobileserver/mobileserver.go +++ b/backend/mobileserver/mobileserver.go @@ -74,6 +74,10 @@ type GoEnvironmentInterface interface { DetectDarkTheme() bool Auth() OnAuthSettingChanged(bool) + CanEncryptLightningMnemonic() bool + StoreLightningEncryptionKey(string, string) error + LoadLightningEncryptionKey(string) (string, error) + DeleteLightningEncryptionKey(string) error BluetoothConnect(string) } @@ -185,15 +189,19 @@ func Serve(dataDir string, testnet bool, environment GoEnvironmentInterface, goA } return []usb.DeviceInfo{deviceInfo{i}} }, - SystemOpenFunc: environment.SystemOpen, - UsingMobileDataFunc: environment.UsingMobileData, - NativeLocaleFunc: environment.NativeLocale, - GetSaveFilenameFunc: environment.GetSaveFilename, - SetDarkThemeFunc: environment.SetDarkTheme, - DetectDarkThemeFunc: environment.DetectDarkTheme, - AuthFunc: environment.Auth, - OnAuthSettingChangedFunc: environment.OnAuthSettingChanged, - BluetoothConnectFunc: environment.BluetoothConnect, + SystemOpenFunc: environment.SystemOpen, + UsingMobileDataFunc: environment.UsingMobileData, + NativeLocaleFunc: environment.NativeLocale, + GetSaveFilenameFunc: environment.GetSaveFilename, + SetDarkThemeFunc: environment.SetDarkTheme, + DetectDarkThemeFunc: environment.DetectDarkTheme, + AuthFunc: environment.Auth, + OnAuthSettingChangedFunc: environment.OnAuthSettingChanged, + CanEncryptLightningMnemonicFunc: environment.CanEncryptLightningMnemonic, + StoreLightningEncryptionKeyFunc: environment.StoreLightningEncryptionKey, + LoadLightningEncryptionKeyFunc: environment.LoadLightningEncryptionKey, + DeleteLightningEncryptionKeyFunc: environment.DeleteLightningEncryptionKey, + BluetoothConnectFunc: environment.BluetoothConnect, }, ) } diff --git a/cmd/servewallet/main.go b/cmd/servewallet/main.go index c4e9cbaf5d..3c8b860cef 100644 --- a/cmd/servewallet/main.go +++ b/cmd/servewallet/main.go @@ -92,6 +92,26 @@ func (webdevEnvironment) Auth() { func (webdevEnvironment) OnAuthSettingChanged(enabled bool) { } +// CanEncryptLightningMnemonic implements backend.Environment. +func (webdevEnvironment) CanEncryptLightningMnemonic() bool { + return false +} + +// StoreLightningEncryptionKey implements backend.Environment. +func (webdevEnvironment) StoreLightningEncryptionKey(accountCode string, encryptionKey string) error { + return nil +} + +// LoadLightningEncryptionKey implements backend.Environment. +func (webdevEnvironment) LoadLightningEncryptionKey(accountCode string) (string, error) { + return "", nil +} + +// DeleteLightningEncryptionKey implements backend.Environment. +func (webdevEnvironment) DeleteLightningEncryptionKey(accountCode string) error { + return nil +} + // BluetoothConnect implements backend.Environment. func (webdevEnvironment) BluetoothConnect(identifier string) { } diff --git a/frontends/android/BitBoxApp/app/src/main/AndroidManifest.xml b/frontends/android/BitBoxApp/app/src/main/AndroidManifest.xml index dfc1c8ad71..b11278c035 100644 --- a/frontends/android/BitBoxApp/app/src/main/AndroidManifest.xml +++ b/frontends/android/BitBoxApp/app/src/main/AndroidManifest.xml @@ -30,6 +30,8 @@ + + + + diff --git a/frontends/android/BitBoxApp/app/src/main/res/xml/data_extraction_rules.xml b/frontends/android/BitBoxApp/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000000..ec489d4e2c --- /dev/null +++ b/frontends/android/BitBoxApp/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift b/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift index 965aea4f91..10650008a1 100644 --- a/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift +++ b/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift @@ -91,6 +91,20 @@ class GoEnvironment: NSObject, MobileserverGoEnvironmentInterfaceProtocol, UIDoc // TODO: hide app window contents in app switcher, maybe always not just when auth is on. } + func canEncryptLightningMnemonic() -> Bool { + false + } + + func storeLightningEncryptionKey(_ accountCode: String?, p1 encryptionKey: String?) throws { + } + + func loadLightningEncryptionKey(_ accountCode: String?, error: NSErrorPointer) -> String { + "" + } + + func deleteLightningEncryptionKey(_ accountCode: String?) throws { + } + func bluetoothConnect(_ identifier: String?) { guard let identifier = identifier else { return diff --git a/frontends/qt/server/server.go b/frontends/qt/server/server.go index 1913e69d6e..a0cd771267 100644 --- a/frontends/qt/server/server.go +++ b/frontends/qt/server/server.go @@ -196,8 +196,12 @@ func serve( log.Info("Qt auth") authResult(mobileserver.AuthResultOk) }, - OnAuthSettingChangedFunc: func(bool) {}, - BluetoothConnectFunc: func(string) {}, + OnAuthSettingChangedFunc: func(bool) {}, + CanEncryptLightningMnemonicFunc: func() bool { return false }, + StoreLightningEncryptionKeyFunc: func(string, string) error { return nil }, + LoadLightningEncryptionKeyFunc: func(string) (string, error) { return "", nil }, + DeleteLightningEncryptionKeyFunc: func(string) error { return nil }, + BluetoothConnectFunc: func(string) {}, }, ) }