diff --git a/class/deeplink-schema-match.js b/class/deeplink-schema-match.js index 74130e26b..b96e47793 100644 --- a/class/deeplink-schema-match.js +++ b/class/deeplink-schema-match.js @@ -181,7 +181,6 @@ class DeeplinkSchemaMatch { ]); } else { const urlObject = url.parse(event.url, true); // eslint-disable-line node/no-deprecated-api - console.log('parsed', event.url, 'into', urlObject); (async () => { if (urlObject.protocol === 'bluewallet:' || urlObject.protocol === 'lapp:' || urlObject.protocol === 'blue:') { switch (urlObject.host) { @@ -244,12 +243,56 @@ class DeeplinkSchemaMatch { ]); break; } + case 'setelectrumserver': + completionHandler([ + 'ElectrumSettings', + { + server: DeeplinkSchemaMatch.getServerFromSetElectrumServerAction(event.url), + }, + ]); + break; + case 'setlndhuburl': + completionHandler([ + 'LightningSettings', + { + url: DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction(event.url), + }, + ]); + break; } } })(); } } + /** + * Extracts server from a deeplink like `bluewallet:setelectrumserver?server=electrum1.bluewallet.io%3A443%3As` + * returns FALSE if none found + * + * @param url {string} + * @return {string|boolean} + */ + static getServerFromSetElectrumServerAction(url) { + if (!url.startsWith('bluewallet:setelectrumserver') && !url.startsWith('setelectrumserver')) return false; + const splt = url.split('server='); + if (splt[1]) return decodeURIComponent(splt[1]); + return false; + } + + /** + * Extracts url from a deeplink like `bluewallet:setlndhuburl?url=https%3A%2F%2Flndhub.herokuapp.com` + * returns FALSE if none found + * + * @param url {string} + * @return {string|boolean} + */ + static getUrlFromSetLndhubUrlAction(url) { + if (!url.startsWith('bluewallet:setlndhuburl') && !url.startsWith('setlndhuburl')) return false; + const splt = url.split('url='); + if (splt[1]) return decodeURIComponent(splt[1]); + return false; + } + static isTXNFile(filePath) { return ( (filePath.toLowerCase().startsWith('file:') || filePath.toLowerCase().startsWith('content:')) && diff --git a/loc/en.json b/loc/en.json index ac56aef8d..3c75d1780 100644 --- a/loc/en.json +++ b/loc/en.json @@ -248,6 +248,8 @@ "electrum_port": "TCP port, usually {example}", "electrum_port_ssl": "SSL port, usually {example}", "electrum_saved": "Your changes have been saved successfully. Restart may be required for changes to take effect.", + "set_electrum_server_as_default": "Set {server} as default electrum server?", + "set_lndhub_as_default": "Set {url} as default LNDHub server?", "electrum_settings": "Electrum Settings", "electrum_settings_explain": "Set to blank to use default", "electrum_status": "Status", diff --git a/screen/settings/electrumSettings.js b/screen/settings/electrumSettings.js index 0ec8f3d11..178a388c6 100644 --- a/screen/settings/electrumSettings.js +++ b/screen/settings/electrumSettings.js @@ -1,6 +1,6 @@ /* global alert */ import React, { Component } from 'react'; -import { View, TextInput, StyleSheet } from 'react-native'; +import { Alert, View, TextInput, StyleSheet } from 'react-native'; import { AppStorage } from '../../class'; import AsyncStorage from '@react-native-community/async-storage'; import { ScrollView } from 'react-native-gesture-handler'; @@ -19,14 +19,17 @@ import PropTypes from 'prop-types'; import loc from '../../loc'; import DefaultPreference from 'react-native-default-preference'; import RNWidgetCenter from 'react-native-widget-center'; +import DeeplinkSchemaMatch from '../../class/deeplink-schema-match'; const BlueElectrum = require('../../blue_modules/BlueElectrum'); export default class ElectrumSettings extends Component { constructor(props) { super(props); + const server = props?.route?.params?.server; this.state = { isLoading: true, config: {}, + server, }; } @@ -56,6 +59,24 @@ export default class ElectrumSettings extends Component { config: await BlueElectrum.getConfig(), inverval, }); + + if (this.state.server) { + Alert.alert( + loc.formatString(loc.settings.set_electrum_server_as_default, { server: this.state.server }), + '', + [ + { + text: loc._.ok, + onPress: () => { + this.onBarScanned(this.state.server); + }, + style: 'default', + }, + { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, + ], + { cancelable: false }, + ); + } } checkServer = async () => { @@ -115,6 +136,10 @@ export default class ElectrumSettings extends Component { }; onBarScanned = value => { + if (DeeplinkSchemaMatch.getServerFromSetElectrumServerAction(value)) { + // in case user scans a QR with a deeplink like `bluewallet:setelectrumserver?server=electrum1.bluewallet.io%3A443%3As` + value = DeeplinkSchemaMatch.getServerFromSetElectrumServerAction(value); + } var [host, port, type] = value.split(':'); this.setState({ host: host }); type === 's' ? this.setState({ sslPort: port }) : this.setState({ port: port }); @@ -216,6 +241,9 @@ ElectrumSettings.propTypes = { }), route: PropTypes.shape({ name: PropTypes.string, + params: PropTypes.shape({ + server: PropTypes.string, + }), }), }; diff --git a/screen/settings/lightningSettings.js b/screen/settings/lightningSettings.js index 25b94986e..59fb6eb63 100644 --- a/screen/settings/lightningSettings.js +++ b/screen/settings/lightningSettings.js @@ -1,6 +1,6 @@ /* global alert */ import React, { useState, useEffect, useCallback } from 'react'; -import { View, TextInput, Linking, StyleSheet } from 'react-native'; +import { View, TextInput, Linking, StyleSheet, Alert } from 'react-native'; import { Button } from 'react-native-elements'; import { useTheme, useNavigation, useRoute } from '@react-navigation/native'; import { AppStorage } from '../../class'; @@ -18,6 +18,7 @@ import { import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet'; import loc from '../../loc'; import { BlueCurrentTheme } from '../../components/themes'; +import DeeplinkSchemaMatch from '../../class/deeplink-schema-match'; const styles = StyleSheet.create({ root: { @@ -48,6 +49,7 @@ const styles = StyleSheet.create({ }); const LightningSettings = () => { + const params = useRoute().params; const [isLoading, setIsLoading] = useState(true); const [URI, setURI] = useState(); const { colors } = useTheme(); @@ -59,9 +61,31 @@ const LightningSettings = () => { .then(setURI) .then(() => setIsLoading(false)) .catch(() => setIsLoading(false)); - }, []); + + if (params?.url) { + Alert.alert( + loc.formatString(loc.settings.set_lndhub_as_default, { url: params?.url }), + '', + [ + { + text: loc._.ok, + onPress: () => { + setLndhubURI(params?.url); + }, + style: 'default', + }, + { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, + ], + { cancelable: false }, + ); + } + }, [params?.url]); const setLndhubURI = value => { + if (DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction(value)) { + // in case user scans a QR with a deeplink like `bluewallet:setlndhuburl?url=https%3A%2F%2Flndhub.herokuapp.com` + value = DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction(value); + } setURI(value.trim()); }; diff --git a/tests/unit/deeplink-schema-match.test.js b/tests/unit/deeplink-schema-match.test.js index d30979c80..6451d783e 100644 --- a/tests/unit/deeplink-schema-match.test.js +++ b/tests/unit/deeplink-schema-match.test.js @@ -165,6 +165,28 @@ describe('unit - DeepLinkSchemaMatch', function () { }, ], }, + { + argument: { + url: 'bluewallet:setelectrumserver?server=electrum1.bluewallet.io%3A443%3As', + }, + expected: [ + 'ElectrumSettings', + { + server: 'electrum1.bluewallet.io:443:s', + }, + ], + }, + { + argument: { + url: 'bluewallet:setlndhuburl?url=https%3A%2F%2Flndhub.herokuapp.com', + }, + expected: [ + 'LightningSettings', + { + url: 'https://lndhub.herokuapp.com', + }, + ], + }, { argument: { url: @@ -291,4 +313,39 @@ describe('unit - DeepLinkSchemaMatch', function () { assert.ok(DeeplinkSchemaMatch.isPossiblyPSBTFile('content://com.android.externalstorage.documents/document/081D-1403%3Atxhex.psbt')); assert.ok(DeeplinkSchemaMatch.isPossiblyPSBTFile('file://com.android.externalstorage.documents/document/081D-1403%3Atxhex.psbt')); }); + + it('can work with some deeplink actions', () => { + assert.strictEqual(DeeplinkSchemaMatch.getServerFromSetElectrumServerAction('sgasdgasdgasd'), false); + assert.strictEqual( + DeeplinkSchemaMatch.getServerFromSetElectrumServerAction('bluewallet:setelectrumserver?server=electrum1.bluewallet.io%3A443%3As'), + 'electrum1.bluewallet.io:443:s', + ); + assert.strictEqual( + DeeplinkSchemaMatch.getServerFromSetElectrumServerAction('setelectrumserver?server=electrum1.bluewallet.io%3A443%3As'), + 'electrum1.bluewallet.io:443:s', + ); + assert.strictEqual( + DeeplinkSchemaMatch.getServerFromSetElectrumServerAction('ololo:setelectrumserver?server=electrum1.bluewallet.io%3A443%3As'), + false, + ); + assert.strictEqual( + DeeplinkSchemaMatch.getServerFromSetElectrumServerAction('setTrololo?server=electrum1.bluewallet.io%3A443%3As'), + false, + ); + + assert.strictEqual( + DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction('bluewallet:setlndhuburl?url=https%3A%2F%2Flndhub.herokuapp.com'), + 'https://lndhub.herokuapp.com', + ); + assert.strictEqual( + DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction('bluewallet:setlndhuburl?url=https%3A%2F%2Flndhub.herokuapp.com%3A443'), + 'https://lndhub.herokuapp.com:443', + ); + assert.strictEqual( + DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction('setlndhuburl?url=https%3A%2F%2Flndhub.herokuapp.com%3A443'), + 'https://lndhub.herokuapp.com:443', + ); + assert.strictEqual(DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction('gsom?url=https%3A%2F%2Flndhub.herokuapp.com%3A443'), false); + assert.strictEqual(DeeplinkSchemaMatch.getUrlFromSetLndhubUrlAction('sdfhserhsthsd'), false); + }); });