Skip to content

Commit

Permalink
Migrate LNC data
Browse files Browse the repository at this point in the history
  • Loading branch information
kaloudis committed Dec 31, 2024
1 parent e931a3b commit daf3cab
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 61 deletions.
50 changes: 22 additions & 28 deletions backends/LNC/credentialStore.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import EncryptedStorage from 'react-native-encrypted-storage';
import Storage from '../../storage';
import { CredentialStore } from '../../zeus_modules/@lightninglabs/lnc-rn';
import hashjs from 'hash.js';

const STORAGE_KEY = 'lnc-rn';
const LNC_STORAGE_KEY = 'lnc-rn';

const hash = (stringToHash: string) =>
hashjs.sha256().update(stringToHash).digest('hex');

/**
* A wrapper around `EncryptedStorage` used to store sensitive data required
* A wrapper around `Storage` used to store sensitive data required
* by LNC to reconnect after the initial pairing process has been completed.
*/
export default class LncCredentialStore implements CredentialStore {
// the data to store in EncryptedStorage
// the data to store in Storage
private persisted = {
serverHost: '',
localKey: '',
Expand Down Expand Up @@ -44,28 +44,22 @@ export default class LncCredentialStore implements CredentialStore {

private async _migrateServerHost() {
try {
const baseKey = `${STORAGE_KEY}:${hash(this._pairingPhrase)}`;
const baseKey = `${LNC_STORAGE_KEY}:${hash(this._pairingPhrase)}`;
const hostKey = `${baseKey}:host`;
const hasNewFormat = await EncryptedStorage.getItem(hostKey);
const hasNewFormat = await Storage.getItem(hostKey);

// Only migrate if new format doesn't exist yet
if (!hasNewFormat) {
const oldData = await EncryptedStorage.getItem(baseKey);
const oldData = await Storage.getItem(baseKey);

if (oldData) {
const parsed = JSON.parse(oldData);
if (parsed.serverHost) {
await EncryptedStorage.setItem(
hostKey,
parsed.serverHost
);
await Storage.setItem(hostKey, parsed.serverHost);

// Remove serverHost from old format
delete parsed.serverHost;
await EncryptedStorage.setItem(
baseKey,
JSON.stringify(parsed)
);
await Storage.setItem(baseKey, parsed);
}
}
}
Expand Down Expand Up @@ -136,9 +130,9 @@ export default class LncCredentialStore implements CredentialStore {

/** Clears any persisted data in the store */
clear() {
const baseKey = `${STORAGE_KEY}:${hash(this._pairingPhrase)}`;
EncryptedStorage.removeItem(baseKey);
EncryptedStorage.removeItem(`${baseKey}:host`);
const baseKey = `${LNC_STORAGE_KEY}:${hash(this._pairingPhrase)}`;
Storage.removeItem(baseKey);
Storage.removeItem(`${baseKey}:host`);
this.persisted = {
serverHost: this.persisted.serverHost,
localKey: '',
Expand All @@ -150,15 +144,15 @@ export default class LncCredentialStore implements CredentialStore {
this._pairingPhrase = '';
}

/** Loads persisted data from EncryptedStorage */
/** Loads persisted data from Storage */
async load(pairingPhrase?: string) {
// only load if pairingPhrase is set
if (!pairingPhrase) return;
try {
const baseKey = `${STORAGE_KEY}:${hash(pairingPhrase)}`;
const baseKey = `${LNC_STORAGE_KEY}:${hash(pairingPhrase)}`;
const hostKey = `${baseKey}:host`;
const json = await EncryptedStorage.getItem(baseKey);
const serverHost = await EncryptedStorage.getItem(hostKey);
const json = await Storage.getItem(baseKey);
const serverHost = await Storage.getItem(hostKey);
if (json) {
this.persisted = JSON.parse(json);
if (serverHost) {
Expand All @@ -179,18 +173,18 @@ export default class LncCredentialStore implements CredentialStore {
//

private _saveServerHost() {
const hostKey = `${STORAGE_KEY}:${hash(this._pairingPhrase)}:host`;
EncryptedStorage.setItem(hostKey, this.persisted.serverHost);
const hostKey = `${LNC_STORAGE_KEY}:${hash(this._pairingPhrase)}:host`;
Storage.setItem(hostKey, this.persisted.serverHost);
}

/** Saves persisted data to EncryptedStorage */
/** Saves persisted data to Storage */
private _save() {
// only save if localKey and remoteKey is set
if (!this._localKey) return;
if (!this._remoteKey) return;
const baseKey = `${STORAGE_KEY}:${hash(this._pairingPhrase)}`;
EncryptedStorage.setItem(baseKey, JSON.stringify(this.persisted));
const baseKey = `${LNC_STORAGE_KEY}:${hash(this._pairingPhrase)}`;
Storage.setItem(baseKey, this.persisted);
}
}

export { STORAGE_KEY, hash };
export { LNC_STORAGE_KEY, hash };
13 changes: 9 additions & 4 deletions ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ PODS:
- fmt (= 9.1.0)
- glog
- RCT-Folly/Default (= 2024.01.01.00)
- RCT-Folly/Default (2024.01.01.00):
- boost
- DoubleConversion
- fmt (= 9.1.0)
- glog
- RCT-Folly/Fabric (2024.01.01.00):
- boost
- DoubleConversion
Expand Down Expand Up @@ -1628,14 +1633,14 @@ SPEC CHECKSUMS:
boost: d3f49c53809116a5d38da093a8aa78bf551aed09
BVLinearGradient: 7815a70ab485b7b155186dd0cc836363e0288cad
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: f16ae600a246532c4020132d54af21d0ddb2a385
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
FBLazyVector: 4bc164e5b5e6cfc288d2b5ff28643ea15fa1a589
fmt: 10c6e61f4be25dc963c36bd73fc7b1705fe975be
glog: 08b301085f15bcbb6ff8632a8ebaf239aae04e6a
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f
hermes-engine: 01d3e052018c2a13937aca1860fbedbccd4a41b7
lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8
lottie-react-native: 5d89c05930d4180a1e39b1757d46e6c0eec90255
RCT-Folly: 84578c8756030547307e4572ab1947de1685c599
RCT-Folly: 5dc73daec3476616d19e8a53f0156176f7b55461
RCTDeprecation: b03c35057846b685b3ccadc9bfe43e349989cdb2
RCTRequired: 194626909cfa8d39ca6663138c417bc6c431648c
RCTTypeSafety: 552aff5b8e8341660594db00e53ac889682bc120
Expand Down
8 changes: 0 additions & 8 deletions ios/zeus.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1493,7 +1493,6 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-zeus-zeusTests/Pods-zeus-zeusTests-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo/RNDeviceInfoPrivacyInfo.bundle",
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
Expand All @@ -1514,11 +1513,9 @@
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/SwiftProtobuf/SwiftProtobuf.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNDeviceInfoPrivacyInfo.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
Expand All @@ -1539,7 +1536,6 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SwiftProtobuf.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down Expand Up @@ -1570,7 +1566,6 @@
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-zeus/Pods-zeus-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNDeviceInfo/RNDeviceInfoPrivacyInfo.bundle",
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
Expand All @@ -1591,11 +1586,9 @@
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/SwiftProtobuf/SwiftProtobuf.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNDeviceInfoPrivacyInfo.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
Expand All @@ -1616,7 +1609,6 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SwiftProtobuf.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
Expand Down
5 changes: 5 additions & 0 deletions storage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ class Storage {
);
return response;
};

removeItem = async (key: string) => {
const response = await Keychain.resetInternetCredentials(key);
return response;
};
}

const storage = new Storage();
Expand Down
20 changes: 9 additions & 11 deletions stores/SettingsStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Storage from '../storage';
import LoginRequest from '../models/LoginRequest';

const LEGACY_STORAGE_KEY = 'zeus-settings';
export const MODERN_STORAGE_KEY = 'zeus-settings-v2';
export const STORAGE_KEY = 'zeus-settings-v2';

export const LEGACY_CURRENCY_CODES_KEY = 'currency-codes';
export const CURRENCY_CODES_KEY = 'zeus-currency-codes';
Expand Down Expand Up @@ -1394,9 +1394,7 @@ export default class SettingsStore {
public async getSettings(silentUpdate: boolean = false) {
if (!silentUpdate) this.loading = true;
try {
const modernSettings: any = await Storage.getItem(
MODERN_STORAGE_KEY
);
const modernSettings: any = await Storage.getItem(STORAGE_KEY);

if (modernSettings) {
console.log('attempting to load modern settings');
Expand All @@ -1420,13 +1418,13 @@ export default class SettingsStore {

await MigrationsUtils.storageMigrationV2(newSettings);
} else {
console.log('No settings stored');
console.log('No legacy settings stored');
}
}

const node: any =
this.settings.nodes?.length &&
this.settings.nodes[this.settings.selectedNode || 0];
this.settings?.nodes?.length &&
this.settings?.nodes[this.settings.selectedNode || 0];
if (node) {
this.host = node.host;
this.port = node.port;
Expand Down Expand Up @@ -1461,9 +1459,9 @@ export default class SettingsStore {
}

@action
public async setSettings(settings: string) {
public async setSettings(settings: any) {
this.loading = true;
await EncryptedStorage.setItem(LEGACY_STORAGE_KEY, settings);
await Storage.setItem(STORAGE_KEY, settings);
this.loading = false;
return settings;
}
Expand All @@ -1476,7 +1474,7 @@ export default class SettingsStore {
...newSetting
};

await this.setSettings(JSON.stringify(newSettings));
await this.setSettings(newSettings);
// ensure we get the enhanced settings set
const settings = await this.getSettings(true);
return settings;
Expand Down Expand Up @@ -1650,7 +1648,7 @@ export default class SettingsStore {
public checkBiometricsStatus = async () => {
const biometryType = await getSupportedBiometryType();
if (this.settings.supportedBiometryType !== biometryType) {
this.updateSettings({
await this.updateSettings({
supportedBiometryType: biometryType
});
}
Expand Down
2 changes: 1 addition & 1 deletion utils/MigrationUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jest.mock('../stores/SettingsStore', () => ({
'wss://nostr.lnproxy.org'
],
DEFAULT_SLIDE_TO_PAY_THRESHOLD: 10000,
MODERN_STORAGE_KEY: 'zeus-settings-v2',
STORAGE_KEY: 'zeus-settings-v2',
LEGACY_CURRENCY_CODES_KEY: 'currency-codes',
CURRENCY_CODES_KEY: 'zeus-currency-codes',
PosEnabled: {
Expand Down
44 changes: 39 additions & 5 deletions utils/MigrationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
DEFAULT_NOSTR_RELAYS_2023,
PosEnabled,
DEFAULT_SLIDE_TO_PAY_THRESHOLD,
MODERN_STORAGE_KEY,
STORAGE_KEY,
LEGACY_CURRENCY_CODES_KEY,
CURRENCY_CODES_KEY
} from '../stores/SettingsStore';
Expand Down Expand Up @@ -61,6 +61,8 @@ import {

import { LEGACY_LSPS1_ORDERS_KEY, LSPS1_ORDERS_KEY } from '../stores/LSPStore';

import { LNC_STORAGE_KEY, hash } from '../backends/LNC/credentialStore';

import EncryptedStorage from 'react-native-encrypted-storage';
import Storage from '../storage';

Expand Down Expand Up @@ -273,10 +275,7 @@ class MigrationsUtils {
public async storageMigrationV2(settings: any) {
// Settings migration
console.log('Attemping settings migration');
const writeSuccess = await Storage.setItem(
MODERN_STORAGE_KEY,
settings
);
const writeSuccess = await Storage.setItem(STORAGE_KEY, settings);
console.log('Settings migration status', writeSuccess);

// Contacts migration
Expand Down Expand Up @@ -536,6 +535,41 @@ class MigrationsUtils {
error
);
}

// LNC migrations
try {
settings?.nodes.forEach(async (node: any) => {
if (node.implementation === 'lightning-node-connect') {
const baseKey = `${LNC_STORAGE_KEY}:${hash(
node.pairingPhrase
)}`;
const hostKey = `${baseKey}:host`;

const baseKeyData = await EncryptedStorage.getItem(baseKey);

console.log('Attemping LNC base key migration', baseKey);
const writeSuccess1 = await Storage.setItem(
baseKey,
baseKeyData
);
console.log('LNC base key migration status', writeSuccess1);

const hostKeyData = await EncryptedStorage.getItem(hostKey);

console.log('Attemping LNC host key migration', baseKey);
const writeSuccess2 = await Storage.setItem(
hostKey,
hostKeyData
);
console.log('LNC host key migration status', writeSuccess2);
}
});
} catch (error) {
console.error(
'Error loading LNC data from encrypted storage',
error
);
}
}
}

Expand Down
9 changes: 5 additions & 4 deletions views/Settings/WalletConfiguration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,21 @@ import {
} from 'react-native';
import Clipboard from '@react-native-clipboard/clipboard';
import { inject, observer } from 'mobx-react';
import EncryptedStorage from 'react-native-encrypted-storage';
import cloneDeep from 'lodash/cloneDeep';
import differenceBy from 'lodash/differenceBy';
import { Route } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';

import { hash, STORAGE_KEY } from '../../backends/LNC/credentialStore';
import { hash, LNC_STORAGE_KEY } from '../../backends/LNC/credentialStore';

import AddressUtils, { CUSTODIAL_LNDHUBS } from '../../utils/AddressUtils';
import ConnectionFormatUtils from '../../utils/ConnectionFormatUtils';
import { localeString } from '../../utils/LocaleUtils';
import BackendUtils from '../../utils/BackendUtils';
import { themeColor } from '../../utils/ThemeUtils';

import Storage from '../../storage';

import Button from '../../components/Button';
import CollapsedQR from '../../components/CollapsedQR';
import DropdownSetting from '../../components/DropdownSetting';
Expand Down Expand Up @@ -279,8 +280,8 @@ export default class WalletConfiguration extends React.Component<

const { implementation, pairingPhrase } = this.state;
if (implementation === 'lightning-node-connect') {
const key = `${STORAGE_KEY}:${hash(pairingPhrase)}`;
const json: any = await EncryptedStorage.getItem(key);
const key = `${LNC_STORAGE_KEY}:${hash(pairingPhrase)}`;
const json: any = await Storage.getItem(key);
const parsed = JSON.parse(json);
if (parsed) {
if (parsed.localKey && parsed.remoteKey) {
Expand Down

0 comments on commit daf3cab

Please sign in to comment.