FIX: LNDhub URI invalid after BlueWallet update #7087

This commit is contained in:
Marcos Rodriguez Velez 2024-09-18 21:30:34 -04:00
parent dd08d54b01
commit b5c6c10447
7 changed files with 114 additions and 41 deletions

View File

@ -9,6 +9,7 @@ import Realm from 'realm';
import { LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet, TaprootWallet } from '../class';
import presentAlert from '../components/Alert';
import loc from '../loc';
import { GROUP_IO_BLUEWALLET } from './currency';
const ElectrumClient = require('electrum-client');
const net = require('net');
@ -200,7 +201,7 @@ export async function connectMain(): Promise<void> {
usingPeer = savedPeer;
}
await DefaultPreference.setName('group.io.bluewallet.bluewallet');
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
try {
if (usingPeer.host.endsWith('onion')) {
const randomPeer = getCurrentPeer();

View File

@ -24,6 +24,7 @@ import { SegwitP2SHWallet } from './wallets/segwit-p2sh-wallet';
import { SLIP39LegacyP2PKHWallet, SLIP39SegwitBech32Wallet, SLIP39SegwitP2SHWallet } from './wallets/slip39-wallets';
import { ExtendedTransaction, Transaction, TWallet } from './wallets/types';
import { WatchOnlyWallet } from './wallets/watch-only-wallet';
import { getLNDHub } from '../helpers/lndHub';
let usedBucketNum: boolean | number = false;
let savingInProgress = 0; // its both a flag and a counter of attempts to write to disk
@ -437,7 +438,7 @@ export class BlueApp {
unserializedWallet = LightningCustodianWallet.fromJson(key) as unknown as LightningCustodianWallet;
let lndhub: false | any = false;
try {
lndhub = await AsyncStorage.getItem(BlueApp.LNDHUB);
lndhub = await getLNDHub();
} catch (error) {
console.warn(error);
}

View File

@ -579,14 +579,17 @@ export class LightningCustodianWallet extends LegacyWallet {
}
}
static async isValidNodeAddress(address: string) {
const response = await fetch((address?.endsWith('/') ? address.slice(0, -1) : address) + '/getinfo', {
static async isValidNodeAddress(address: string): Promise<boolean> {
const normalizedAddress = new URL('/getinfo', address.replace(/([^:]\/)\/+/g, '$1'));
const response = await fetch(normalizedAddress.toString(), {
method: 'GET',
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json',
},
});
const json = await response.json();
if (!json) {
throw new Error('API failure: ' + response.statusText);
@ -595,6 +598,7 @@ export class LightningCustodianWallet extends LegacyWallet {
if (json.code && json.code !== 1) {
throw new Error('API error: ' + json.message + ' (code ' + json.code + ')');
}
return true;
}

49
helpers/lndHub.ts Normal file
View File

@ -0,0 +1,49 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import DefaultPreference from 'react-native-default-preference';
import { BlueApp } from '../class';
import { GROUP_IO_BLUEWALLET } from '..//blue_modules/currency';
// Function to get the value from DefaultPreference first, then fallback to AsyncStorage
// as DefaultPreference uses truly native storage.
// If found in AsyncStorage, migrate it to DefaultPreference and remove it from AsyncStorage.
export const getLNDHub = async (): Promise<string | undefined> => {
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
let value = await DefaultPreference.get(BlueApp.LNDHUB);
// If not found, check AsyncStorage and migrate it to DefaultPreference
if (!value) {
value = await AsyncStorage.getItem(BlueApp.LNDHUB);
if (value) {
await DefaultPreference.set(BlueApp.LNDHUB, value);
await AsyncStorage.removeItem(BlueApp.LNDHUB);
console.log('Migrated LNDHub value from AsyncStorage to DefaultPreference');
}
}
return value ?? undefined;
} catch (error) {
console.log('Error getting LNDHub preference:', error);
return undefined;
}
};
export const setLNDHub = async (value: string): Promise<void> => {
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.set(BlueApp.LNDHUB, value);
} catch (error) {
console.log('Error setting LNDHub preference:', error);
}
};
export const clearLNDHub = async (): Promise<void> => {
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
await DefaultPreference.clear(BlueApp.LNDHUB);
await AsyncStorage.removeItem(BlueApp.LNDHUB);
} catch (error) {
console.log('Error clearing LNDHub preference:', error);
}
};

View File

@ -12,7 +12,7 @@ const About = lazy(() => import('../screen/settings/About'));
const DefaultView = lazy(() => import('../screen/settings/DefaultView'));
const ElectrumSettings = lazy(() => import('../screen/settings/electrumSettings'));
const EncryptStorage = lazy(() => import('../screen/settings/EncryptStorage'));
const LightningSettings = lazy(() => import('../screen/settings/lightningSettings'));
const LightningSettings = lazy(() => import('../screen/settings/LightningSettings'));
const NotificationSettings = lazy(() => import('../screen/settings/notificationSettings'));
const SelfTest = lazy(() => import('../screen/settings/SelfTest'));
const ReleaseNotes = lazy(() => import('../screen/settings/ReleaseNotes'));

View File

@ -1,18 +1,19 @@
import React, { useCallback, useEffect, useState } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { RouteProp, useRoute } from '@react-navigation/native';
import { Alert, I18nManager, Linking, ScrollView, StyleSheet, TextInput, View } from 'react-native';
import { Button as ButtonRNElements } from '@rneui/themed';
import DefaultPreference from 'react-native-default-preference';
import { BlueButtonLink, BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
import { BlueApp } from '../../class';
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet';
import presentAlert from '../../components/Alert';
import presentAlert, { AlertType } from '../../components/Alert';
import { Button } from '../../components/Button';
import { useTheme } from '../../components/themes';
import { scanQrHelper } from '../../helpers/scan-qr';
import loc from '../../loc';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { GROUP_IO_BLUEWALLET } from '../../blue_modules/currency';
import { clearLNDHub, getLNDHub, setLNDHub } from '../../helpers/lndHub';
const styles = StyleSheet.create({
uri: {
@ -61,11 +62,20 @@ const LightningSettings: React.FC = () => {
});
useEffect(() => {
AsyncStorage.getItem(BlueApp.LNDHUB)
.then(value => setURI(value ?? undefined))
.then(() => setIsLoading(false))
.catch(() => setIsLoading(false));
const fetchURI = async () => {
try {
// Try fetching from DefaultPreference first as DefaultPreference uses truly native storage
const value = await getLNDHub();
setURI(value ?? undefined);
} catch (error) {
console.log(error);
}
};
const initialize = async () => {
setIsLoading(true);
await fetchURI().finally(() => {
setIsLoading(false);
if (params?.url) {
Alert.alert(
loc.formatString(loc.settings.set_lndhub_as_default, { url: params.url }) as string,
@ -83,6 +93,11 @@ const LightningSettings: React.FC = () => {
{ cancelable: false },
);
}
});
};
// Call the initialize function
initialize();
}, [params?.url]);
const setLndhubURI = (value: string) => {
@ -91,21 +106,24 @@ const LightningSettings: React.FC = () => {
setURI(typeof setLndHubUrl === 'string' ? setLndHubUrl.trim() : value.trim());
};
const save = useCallback(async () => {
setIsLoading(true);
try {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
if (URI) {
await LightningCustodianWallet.isValidNodeAddress(URI);
// validating only if its not empty. empty means use default
}
if (URI) {
await AsyncStorage.setItem(BlueApp.LNDHUB, URI);
const normalizedURI = new URL(URI.replace(/([^:]\/)\/+/g, '$1')).toString();
await LightningCustodianWallet.isValidNodeAddress(normalizedURI);
await setLNDHub(normalizedURI);
} else {
await AsyncStorage.removeItem(BlueApp.LNDHUB);
await clearLNDHub();
}
presentAlert({ message: loc.settings.lightning_saved });
presentAlert({ message: loc.settings.lightning_saved, type: AlertType.Toast });
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
} catch (error) {
triggerHapticFeedback(HapticFeedbackTypes.NotificationError);
presentAlert({ message: loc.settings.lightning_error_lndhub_uri });
console.log(error);
}

View File

@ -1,4 +1,3 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation } from '@react-navigation/native';
import React, { useCallback, useEffect, useMemo, useReducer } from 'react';
import {
@ -18,7 +17,7 @@ import {
import A from '../../blue_modules/analytics';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueButtonLink, BlueFormLabel, BlueSpacing20, BlueSpacing40, BlueText } from '../../BlueComponents';
import { BlueApp, HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet, SegwitP2SHWallet } from '../../class';
import { HDSegwitBech32Wallet, HDSegwitP2SHWallet, LightningCustodianWallet, SegwitP2SHWallet } from '../../class';
import presentAlert from '../../components/Alert';
import Button from '../../components/Button';
import { useTheme } from '../../components/themes';
@ -30,6 +29,7 @@ import ToolTipMenu from '../../components/TooltipMenu';
import { Icon } from '@rneui/themed';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
import { Action } from '../../components/types';
import { getLNDHub } from '../../helpers/lndHub';
enum ButtonSelected {
// @ts-ignore: Return later to update
@ -261,7 +261,7 @@ const WalletsAdd: React.FC = () => {
}, [HeaderRight, colorScheme, colors.foregroundColor, navigateToEntropy, setOptions, toolTipActions]);
useEffect(() => {
AsyncStorage.getItem(BlueApp.LNDHUB)
getLNDHub()
.then(url => (url ? setWalletBaseURI(url) : setWalletBaseURI('')))
.catch(() => setWalletBaseURI(''))
.finally(() => setIsLoading(false));