ADD: Toggle for disabling Tor daemon

This commit is contained in:
Marcos Rodriguez Vélez 2021-09-21 23:55:14 -04:00
parent 748c6e4397
commit 78380405aa
11 changed files with 100 additions and 58 deletions

View File

@ -4,7 +4,6 @@ import { Alert } from 'react-native';
import { LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet } from '../class';
import DefaultPreference from 'react-native-default-preference';
import loc from '../loc';
import { isTorCapable } from './environment';
import WidgetCommunication from './WidgetCommunication';
const bitcoin = require('bitcoinjs-lib');
const ElectrumClient = require('electrum-client');
@ -18,6 +17,7 @@ const ELECTRUM_TCP_PORT = 'electrum_tcp_port';
const ELECTRUM_SSL_PORT = 'electrum_ssl_port';
const ELECTRUM_SERVER_HISTORY = 'electrum_server_history';
const ELECTRUM_CONNECTION_DISABLED = 'electrum_disabled';
const IS_TOR_DAEMON_DISABLED = 'is_tor_daemon_disabled';
let _realm;
async function _getRealm() {
@ -90,10 +90,30 @@ async function isDisabled() {
return !!isDisabled;
}
async function isTorDaemonDisabled() {
let isTorDaemonDisabled;
try {
const savedValue = await AsyncStorage.getItem(IS_TOR_DAEMON_DISABLED);
if (savedValue === null) {
isTorDaemonDisabled = false;
} else {
isTorDaemonDisabled = savedValue;
}
} catch {
isTorDaemonDisabled = true;
}
return !!isTorDaemonDisabled;
}
async function setDisabled(disabled = true) {
return AsyncStorage.setItem(ELECTRUM_CONNECTION_DISABLED, disabled ? '1' : '');
}
async function setIsTorDaemonDisabled(disabled = true) {
return AsyncStorage.setItem(IS_TOR_DAEMON_DISABLED, disabled ? '1' : '');
}
async function connectMain() {
if (await isDisabled()) {
console.log('Electrum connection disabled by user. Skipping connectMain call');
@ -127,7 +147,7 @@ async function connectMain() {
try {
console.log('begin connection:', JSON.stringify(usingPeer));
mainClient = new ElectrumClient(
usingPeer.host.endsWith('.onion') && isTorCapable ? torrific : global.net,
usingPeer.host.endsWith('.onion') && !(await isTorDaemonDisabled()) ? torrific : global.net,
global.tls,
usingPeer.ssl || usingPeer.tcp,
usingPeer.host,
@ -854,8 +874,9 @@ module.exports.calculateBlockTime = function (height) {
* @returns {Promise<boolean>} Whether provided host:port is a valid electrum server
*/
module.exports.testConnection = async function (host, tcpPort, sslPort) {
const isTorDisabled = await isTorDaemonDisabled();
const client = new ElectrumClient(
host.endsWith('.onion') && isTorCapable ? torrific : global.net,
host.endsWith('.onion') && !isTorDisabled ? torrific : global.net,
global.tls,
sslPort || tcpPort,
host,
@ -867,7 +888,7 @@ module.exports.testConnection = async function (host, tcpPort, sslPort) {
try {
const rez = await Promise.race([
new Promise(resolve => {
timeoutId = setTimeout(() => resolve('timeout'), host.endsWith('.onion') && isTorCapable ? 21000 : 5000);
timeoutId = setTimeout(() => resolve('timeout'), host.endsWith('.onion') && !isTorDisabled ? 21000 : 5000);
}),
client.connect(),
]);
@ -899,6 +920,8 @@ module.exports.setBatchingEnabled = () => {
module.exports.connectMain = connectMain;
module.exports.isDisabled = isDisabled;
module.exports.setDisabled = setDisabled;
module.exports.isTorDaemonDisabled = isTorDaemonDisabled;
module.exports.setIsTorDaemonDisabled = setIsTorDaemonDisabled;
module.exports.hardcodedPeers = hardcodedPeers;
module.exports.getRandomHardcodedPeer = getRandomHardcodedPeer;
module.exports.ELECTRUM_HOST = ELECTRUM_HOST;

View File

@ -23,11 +23,17 @@ export const BlueStorageProvider = ({ children }) => {
const getLanguageAsyncStorage = useAsyncStorage(loc.LANG).getItem;
const [isHandOffUseEnabled, setIsHandOffUseEnabled] = useState(false);
const [isElectrumDisabled, setIsElectrumDisabled] = useState(true);
const [isTorDaemonDisabled, setIsTorDaemonDisabled] = useState(false);
useEffect(() => {
BlueElectrum.isDisabled().then(setIsElectrumDisabled);
BlueElectrum.isTorDaemonDisabled().then(setIsTorDaemonDisabled);
}, []);
useEffect(() => {
BlueElectrum.setIsTorDaemonDisabled(isTorDaemonDisabled);
}, [isTorDaemonDisabled]);
const setIsHandOffUseEnabledAsyncStorage = value => {
setIsHandOffUseEnabled(value);
return BlueApp.setIsHandoffEnabled(value);
@ -234,6 +240,8 @@ export const BlueStorageProvider = ({ children }) => {
isDoNotTrackEnabled,
isElectrumDisabled,
setIsElectrumDisabled,
isTorDaemonDisabled,
setIsTorDaemonDisabled,
}}
>
{children}

View File

@ -2,8 +2,8 @@ import { LegacyWallet } from './legacy-wallet';
import Frisbee from 'frisbee';
import bolt11 from 'bolt11';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import { isTorCapable } from '../../blue_modules/environment';
const torrific = require('../../blue_modules/torrific');
const BlueElectrum = require('../../blue_modules/BlueElectrum');
export class LightningCustodianWallet extends LegacyWallet {
static type = 'lightningCustodianWallet';
@ -72,12 +72,13 @@ export class LightningCustodianWallet extends LegacyWallet {
this._api = new Frisbee({
baseURI: this.baseURI,
});
if (isTorCapable && this.baseURI && this.baseURI?.indexOf('.onion') !== -1) {
this._api = new torrific.Torsbee({
baseURI: this.baseURI,
});
}
BlueElectrum.isTorDaemonDisabled().then(isDisabled => {
if (!isDisabled && this.baseURI && this.baseURI?.indexOf('.onion') !== -1) {
this._api = new torrific.Torsbee({
baseURI: this.baseURI,
});
}
});
}
accessTokenExpired() {

View File

@ -267,13 +267,13 @@ PODS:
- React-jsinspector (0.64.2)
- react-native-blue-crypto (1.0.0):
- React
- react-native-camera (4.2.0):
- react-native-camera (4.2.1):
- React-Core
- react-native-camera/RCT (= 4.2.0)
- react-native-camera/RN (= 4.2.0)
- react-native-camera/RCT (4.2.0):
- react-native-camera/RCT (= 4.2.1)
- react-native-camera/RN (= 4.2.1)
- react-native-camera/RCT (4.2.1):
- React-Core
- react-native-camera/RN (4.2.0):
- react-native-camera/RN (4.2.1):
- React-Core
- react-native-document-picker (3.5.4):
- React
@ -281,7 +281,7 @@ PODS:
- React
- react-native-idle-timer (2.1.6):
- React-Core
- react-native-image-picker (4.0.6):
- react-native-image-picker (4.1.1):
- React-Core
- react-native-ios-context-menu (1.3.0):
- React-Core
@ -431,7 +431,7 @@ PODS:
- React-RCTImage
- RNSecureKeyStore (1.0.0):
- React
- RNShare (7.1.0):
- RNShare (7.1.1):
- React-Core
- RNSVG (12.1.1):
- React
@ -739,11 +739,11 @@ SPEC CHECKSUMS:
React-jsiexecutor: 80c46bd381fd06e418e0d4f53672dc1d1945c4c3
React-jsinspector: cc614ec18a9ca96fd275100c16d74d62ee11f0ae
react-native-blue-crypto: 23f1558ad3d38d7a2edb7e2f6ed1bc520ed93e56
react-native-camera: 384df93277a5ccdc800ca9f86daac7107598365e
react-native-camera: 210a872c84d3aa0982a9223047ef9e743ed694fa
react-native-document-picker: c5752781fbc0c126c627c1549b037c139444a4cf
react-native-fingerprint-scanner: c68136ca57e3704d7bdf5faa554ea535ce15b1d0
react-native-idle-timer: 97b8283237d45146a7a5c25bdebe9e1e85f3687b
react-native-image-picker: 7bda3c7297c3ea16f4f504ad6174aa7e548192ef
react-native-image-picker: 7c37cd600a9b7338ced8609cc3ad108ebe6c444f
react-native-ios-context-menu: c787c9a764525d07dff9bd75a191f67de7176e9f
react-native-randombytes: 5fc412efe7b5c55b9002c0004d75fe5fabcaa507
react-native-safe-area-context: 5cf05f49df9d17261e40e518481f2e334c6cd4b5
@ -783,7 +783,7 @@ SPEC CHECKSUMS:
RNReanimated: 241c586663f44f19a53883c63375fdd041253960
RNScreens: 0591543e343c7444ea1756b6265d81a4295922c9
RNSecureKeyStore: f1ad870e53806453039f650720d2845c678d89c8
RNShare: 072f63d19c2b90da3742adac614396d805e7ae22
RNShare: a22398d8d02336133e28bf8b6e0b47b31abade41
RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f
RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4
RNWatch: 99637948ec9b5c9ec5a41920642594ad5ba07e80

View File

@ -5,6 +5,7 @@
"continue": "Continue",
"enter_password": "Enter password",
"never": "Never",
"disabled": "Disabled",
"of": "{number} of {total}",
"ok": "OK",
"storage_is_encrypted": "Your storage is encrypted. Password is required to decrypt it.",

12
package-lock.json generated
View File

@ -19673,9 +19673,9 @@
"from": "git+https://github.com/BlueWallet/react-native-blue-crypto.git#fbc2e6beded0b7f61e0986ce98cca1230f84bc1c"
},
"react-native-camera": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-4.2.0.tgz",
"integrity": "sha512-AhBEtkCLXENrjQke42FwiZL3CStugLaxXsJIqx7xYDnSEHnSwM9/dFen6BdNVoh9LiPgAw6X3CjOvvJNoGchhQ==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/react-native-camera/-/react-native-camera-4.2.1.tgz",
"integrity": "sha512-+Vkql24PFYQfsPRznJCvPwJQfyzCnjlcww/iZ4Ej80bgivKjL9eU0IMQIXp4yi6XCrKi4voWXxIDPMupQZKeIQ==",
"requires": {
"prop-types": "^15.6.2"
}
@ -19979,9 +19979,9 @@
"from": "git+https://github.com/BlueWallet/react-native-secure-key-store.git#63ab38c9d382a819844a086a69cc204c46aa93f9"
},
"react-native-share": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-7.1.0.tgz",
"integrity": "sha512-LSnAz2OeuLrR2MS+PLUR3JN67eCkvu9Eh89j6FD2tah0BwJ5U/Vl31CcwJPV17+X6bLftzUxECPHZ9TtEr7Guw=="
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-7.1.1.tgz",
"integrity": "sha512-pdIr+OUmCP5+t0HHSTy5opbBle+dE7Qw98U8ixSaIGoeQbkyP7vnCDpngxQoOHJ4IdcrbGgSAx+m0OAvvACzXg=="
},
"react-native-size-matters": {
"version": "0.3.1",

View File

@ -28,12 +28,11 @@ import loc, { formatBalanceWithoutSuffix, formatBalancePlain } from '../../loc';
import Lnurl from '../../class/lnurl';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import Notifications from '../../blue_modules/notifications';
import { isTorCapable } from '../../blue_modules/environment';
const currency = require('../../blue_modules/currency');
const torrific = require('../../blue_modules/torrific');
const LNDCreateInvoice = () => {
const { wallets, saveToDisk, setSelectedWallet } = useContext(BlueStorageContext);
const { wallets, saveToDisk, setSelectedWallet, isTorDaemonDisabled } = useContext(BlueStorageContext);
const { walletID, uri } = useRoute().params;
const wallet = useRef(wallets.find(item => item.getID() === walletID) || wallets.find(item => item.chain === Chain.OFFCHAIN));
const { name } = useRoute();
@ -177,7 +176,7 @@ const LNDCreateInvoice = () => {
const callbackUrl = callback + (callback.indexOf('?') !== -1 ? '&' : '?') + 'k1=' + k1 + '&pr=' + invoiceRequest;
let reply;
if (isTorCapable && callbackUrl.includes('.onion')) {
if (!isTorDaemonDisabled && callbackUrl.includes('.onion')) {
const api = new torrific.Torsbee();
const torResponse = await api.get(callbackUrl);
reply = torResponse.body;
@ -228,7 +227,7 @@ const LNDCreateInvoice = () => {
// calling the url
let reply;
try {
if (isTorCapable && url.includes('.onion')) {
if (!isTorDaemonDisabled && url.includes('.onion')) {
const api = new torrific.Torsbee();
const torResponse = await api.get(url);
reply = torResponse.body;

View File

@ -15,7 +15,6 @@ import loc, { formatBalance, formatBalanceWithoutSuffix } from '../../loc';
import Notifications from '../../blue_modules/notifications';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import { Psbt } from 'bitcoinjs-lib';
import { isTorCapable } from '../../blue_modules/environment';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
const currency = require('../../blue_modules/currency');
const BlueElectrum = require('../../blue_modules/BlueElectrum');
@ -24,7 +23,7 @@ const bitcoin = require('bitcoinjs-lib');
const torrific = require('../../blue_modules/torrific');
const Confirm = () => {
const { wallets, fetchAndSaveWalletTransactions, isElectrumDisabled } = useContext(BlueStorageContext);
const { wallets, fetchAndSaveWalletTransactions, isElectrumDisabled, isTorDaemonDisabled } = useContext(BlueStorageContext);
const [isBiometricUseCapableAndEnabled, setIsBiometricUseCapableAndEnabled] = useState(false);
const { params } = useRoute();
const { recipients = [], walletID, fee, memo, tx, satoshiPerByte, psbt } = params;
@ -121,7 +120,7 @@ const Confirm = () => {
const payJoinWallet = new PayjoinTransaction(psbt, txHex => broadcast(txHex), wallet);
const paymentScript = getPaymentScript();
let payjoinClient;
if (isTorCapable && payjoinUrl.includes('.onion')) {
if (!isTorDaemonDisabled && payjoinUrl.includes('.onion')) {
console.warn('trying TOR....');
// working through TOR - crafting custom requester that will handle TOR http request
const customPayjoinRequester = {

View File

@ -162,10 +162,6 @@ export default class ElectrumSettings extends Component {
const sslPort = this.state.sslPort ? this.state.sslPort : '';
const serverHistory = this.state.serverHistory || [];
if (host.endsWith('.onion') && !isTorCapable) {
return alert(loc.settings.tor_unsupported);
}
this.setState({ isLoading: true }, async () => {
try {
if (!host && !port && !sslPort) {

View File

@ -96,10 +96,6 @@ const LightningSettings: React.FC & { navigationOptions: NavigationOptionsGetter
setIsLoading(true);
try {
if (URI) {
if (URI.endsWith('.onion') && !isTorCapable) {
setIsLoading(false);
return alert(loc.settings.tor_unsupported);
}
await LightningCustodianWallet.isValidNodeAddress(URI);
// validating only if its not empty. empty means use default
}

View File

@ -1,10 +1,11 @@
/* global alert */
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useContext } from 'react';
import { View, StyleSheet } from 'react-native';
import navigationStyle from '../../components/navigationStyle';
import { BlueButton, BlueCard, BlueLoading, BlueSpacing20, BlueText, SafeBlueArea } from '../../BlueComponents';
import { BlueButton, BlueCard, BlueListItem, BlueLoading, BlueSpacing20, BlueText, SafeBlueArea } from '../../BlueComponents';
import loc from '../../loc';
import { BlueStorageContext } from '../../blue_modules/storage-context';
const torrific = require('../../blue_modules/torrific');
@ -20,6 +21,7 @@ const styles = StyleSheet.create({
const TorSettings = () => {
const [isLoading, setIsLoading] = useState(false);
const [daemonStatus, setDaemonStatus] = useState('');
const { isTorDaemonDisabled, setIsTorDaemonDisabled } = useContext(BlueStorageContext);
const updateStatus = async () => {
const status = await torrific.getDaemonStatus();
@ -38,7 +40,7 @@ const TorSettings = () => {
try {
setIsLoading(true);
await torrific.testSocket();
alert('OK');
alert(loc._.ok);
} catch (error) {
alert(error.message);
} finally {
@ -50,7 +52,7 @@ const TorSettings = () => {
try {
setIsLoading(true);
await torrific.testHttp();
alert('OK');
alert(loc._.ok);
} catch (error) {
alert(error.message);
} finally {
@ -60,12 +62,19 @@ const TorSettings = () => {
useEffect(() => {
const interval = setInterval(updateStatus, 1000);
return () => {
clearInterval(interval);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (isTorDaemonDisabled) {
stopIfRunning();
}
}, [isTorDaemonDisabled]);
if (isLoading) {
return (
<View style={[styles.root]}>
@ -76,18 +85,28 @@ const TorSettings = () => {
return (
<SafeBlueArea>
<BlueCard>
<BlueText>Daemon Status: {daemonStatus}</BlueText>
</BlueCard>
<BlueCard>
<BlueButton title="start" onPress={startIfNotStarted} />
<BlueSpacing20 />
<BlueButton title="stop" onPress={stopIfRunning} />
<BlueSpacing20 />
<BlueButton title="test socket" onPress={testSocket} />
<BlueSpacing20 />
<BlueButton title="test http" onPress={testHttp} />
</BlueCard>
<BlueListItem
hideChevron
title={loc._.disabled}
Component={View}
switch={{ onValueChange: setIsTorDaemonDisabled, value: isTorDaemonDisabled }}
/>
{!isTorDaemonDisabled && (
<>
<BlueCard>
<BlueText>Daemon Status: {daemonStatus}</BlueText>
</BlueCard>
<BlueCard>
<BlueButton title={loc.send.dynamic_start} onPress={startIfNotStarted} />
<BlueSpacing20 />
<BlueButton title={loc.send.dynamic_stop} onPress={stopIfRunning} />
<BlueSpacing20 />
<BlueButton title="Test Socket" onPress={testSocket} />
<BlueSpacing20 />
<BlueButton title="Test HTTP" onPress={testHttp} />
</BlueCard>
</>
)}
</SafeBlueArea>
);
};