Merge pull request #2822 from BlueWallet/fix-2817

ADD: main view SCAN button can now import watch-only wallets (closes …
This commit is contained in:
GLaDOS 2021-03-21 07:51:22 +00:00 committed by GitHub
commit d337d4ecc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 122 additions and 51 deletions

View File

@ -1,4 +1,4 @@
import { AppStorage, LightningCustodianWallet } from './';
import { AppStorage, LightningCustodianWallet, WatchOnlyWallet } from './';
import AsyncStorage from '@react-native-async-storage/async-storage';
import RNFS from 'react-native-fs';
import url from 'url';
@ -178,6 +178,17 @@ class DeeplinkSchemaMatch {
params: Azteco.getParamsFromUrl(event.url),
},
]);
} else if (new WatchOnlyWallet().setSecret(event.url).init().valid()) {
completionHandler([
'AddWalletRoot',
{
screen: 'ImportWallet',
params: {
triggerImport: true,
label: event.url,
},
},
]);
} else {
const urlObject = url.parse(event.url, true); // eslint-disable-line node/no-deprecated-api
(async () => {

View File

@ -56,13 +56,15 @@ export class WatchOnlyWallet extends LegacyWallet {
* this method creates appropriate HD wallet class, depending on whether we have xpub, ypub or zpub
* as a property of `this`, and in case such property exists - it recreates it and copies data from old one.
* this is needed after serialization/save/load/deserialization procedure.
*
* @return {WatchOnlyWallet} this
*/
init() {
let hdWalletInstance;
if (this.secret.startsWith('xpub')) hdWalletInstance = new HDLegacyP2PKHWallet();
else if (this.secret.startsWith('ypub')) hdWalletInstance = new HDSegwitP2SHWallet();
else if (this.secret.startsWith('zpub')) hdWalletInstance = new HDSegwitBech32Wallet();
else return;
else return this;
hdWalletInstance._xpub = this.secret;
if (this._hdWalletInstance) {
// now, porting all properties from old object to new one
@ -75,6 +77,8 @@ export class WatchOnlyWallet extends LegacyWallet {
delete hdWalletInstance._node0;
}
this._hdWalletInstance = hdWalletInstance;
return this;
}
prepareForSerialization() {

View File

@ -4,13 +4,14 @@
*
* @param navigateFunc {function}
* @param currentScreenName {string}
* @param showFileImportButton {boolean}
*
* @return {Promise<string>}
*/
module.exports = function (navigateFunc, currentScreenName) {
module.exports = function scanQrHelper(navigateFunc, currentScreenName, showFileImportButton = true) {
return new Promise(resolve => {
const params = {};
params.showFileImportButton = true;
params.showFileImportButton = !!showFileImportButton;
params.onBarScanned = function (data) {
setTimeout(() => resolve(data.data || data), 1);

View File

@ -315,17 +315,9 @@ const ScanQRCode = () => {
testID="scanQrBackdoorOkButton"
onPress={() => {
setBackdoorVisible(false);
let data;
try {
data = JSON.parse(backdoorText);
// this might be a json string (for convenience - in case there are "\n" in there)
} catch (_) {
data = backdoorText;
} finally {
setBackdoorText('');
}
setBackdoorText('');
if (data) onBarCodeRead({ data });
if (backdoorText) onBarCodeRead({ data: backdoorText });
}}
/>
</View>

View File

@ -23,6 +23,7 @@ const WalletsImport = () => {
const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState(false);
const route = useRoute();
const label = (route.params && route.params.label) || '';
const triggerImport = (route.params && route.params.triggerImport) || false;
const [importText, setImportText] = useState(label);
const navigation = useNavigation();
const { colors } = useTheme();
@ -50,6 +51,11 @@ const WalletsImport = () => {
};
}, []);
useEffect(() => {
if (triggerImport) importButtonPressed();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const importButtonPressed = () => {
if (importText.trim().length === 0) {
return;

View File

@ -31,6 +31,7 @@ import { isCatalyst, isMacCatalina, isTablet } from '../../blue_modules/environm
import BlueClipboard from '../../blue_modules/clipboard';
import navigationStyle from '../../components/navigationStyle';
const scanqrHelper = require('../../helpers/scan-qr');
const A = require('../../blue_modules/analytics');
const fs = require('../../blue_modules/fs');
const WalletsListSections = { CAROUSEL: 'CAROUSEL', LOCALTRADER: 'LOCALTRADER', TRANSACTIONS: 'TRANSACTIONS' };
@ -343,18 +344,12 @@ const WalletsList = () => {
if (isMacCatalina) {
fs.showActionSheet({ anchor: walletActionButtonsRef.current }).then(onBarScanned);
} else {
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
params: {
launchedBy: routeName,
onBarScanned,
showFileImportButton: false,
},
});
scanqrHelper(navigate, routeName, false).then(onBarScanned);
}
};
const onBarScanned = value => {
if (!value) return;
DeeplinkSchemaMatch.navigationRouteFor({ url: value }, completionValue => {
ReactNativeHapticFeedback.trigger('impactLight', { ignoreAndroidSystemSettings: false });
navigate(...completionValue);
@ -381,14 +376,7 @@ const WalletsList = () => {
if (buttonIndex === 1) {
fs.showImagePickerAndReadImage().then(onBarScanned);
} else if (buttonIndex === 2) {
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
params: {
launchedBy: routeName,
onBarScanned,
showFileImportButton: false,
},
});
scanqrHelper(navigate, routeName, false).then(onBarScanned);
} else if (buttonIndex === 3) {
copyFromClipboard();
}
@ -408,15 +396,7 @@ const WalletsList = () => {
},
{
text: loc.wallets.list_long_scan,
onPress: () =>
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
params: {
launchedBy: routeName,
onBarScanned,
showFileImportButton: false,
},
}),
onPress: () => scanqrHelper(navigate, routeName, false).then(onBarScanned),
},
];
if (!isClipboardEmpty) {

View File

@ -202,6 +202,81 @@ describe('unit - DeepLinkSchemaMatch', function () {
},
],
},
{
argument: {
url: require('fs').readFileSync('./tests/unit/fixtures/skeleton-cobo.txt', 'ascii'),
},
expected: [
'AddWalletRoot',
{
screen: 'ImportWallet',
params: {
triggerImport: true,
label: require('fs').readFileSync('./tests/unit/fixtures/skeleton-cobo.txt', 'ascii'),
},
},
],
},
{
argument: {
url: require('fs').readFileSync('./tests/unit/fixtures/skeleton-coldcard.txt', 'ascii'),
},
expected: [
'AddWalletRoot',
{
screen: 'ImportWallet',
params: {
triggerImport: true,
label: require('fs').readFileSync('./tests/unit/fixtures/skeleton-coldcard.txt', 'ascii'),
},
},
],
},
{
argument: {
url: require('fs').readFileSync('./tests/unit/fixtures/skeleton-electrum.txt', 'ascii'),
},
expected: [
'AddWalletRoot',
{
screen: 'ImportWallet',
params: {
triggerImport: true,
label: require('fs').readFileSync('./tests/unit/fixtures/skeleton-electrum.txt', 'ascii'),
},
},
],
},
{
argument: {
url: require('fs').readFileSync('./tests/unit/fixtures/skeleton-walletdescriptor.txt', 'ascii'),
},
expected: [
'AddWalletRoot',
{
screen: 'ImportWallet',
params: {
triggerImport: true,
label: require('fs').readFileSync('./tests/unit/fixtures/skeleton-walletdescriptor.txt', 'ascii'),
},
},
],
},
{
argument: {
url: 'zpub6rFDtF1nuXZ9PUL4XzKURh3vJBW6Kj6TUrYL4qPtFNtDXtcTVfiqjQDyrZNwjwzt5HS14qdqo3Co2282Lv3Re6Y5wFZxAVuMEpeygnnDwfx',
},
expected: [
'AddWalletRoot',
{
screen: 'ImportWallet',
params: {
triggerImport: true,
label: 'zpub6rFDtF1nuXZ9PUL4XzKURh3vJBW6Kj6TUrYL4qPtFNtDXtcTVfiqjQDyrZNwjwzt5HS14qdqo3Co2282Lv3Re6Y5wFZxAVuMEpeygnnDwfx',
},
},
],
},
];
const asyncNavigationRouteFor = async function (event) {

View File

@ -0,0 +1 @@
{"ExtPubKey":"zpub6rcabYFcdr41zyUNRWRyHYs2Sm86E5XV8RjjRzTFYsiCngteeZnkwaF2xuhjmM6kpHjuNpFW42BMhzPmFwXt48e1FhddMB7xidZzN4SF24K","MasterFingerprint":"5271c071","CoboVaultFirmwareVersion":"1.2.4(BTC-Only)"}

View File

@ -0,0 +1 @@
{"keystore": {"ckcc_xpub": "xpub661MyMwAqRbcGmUDQVKxmhEESB5xTk8hbsdTSV3Pmhm3HE9Fj3s45R9Y8LwyaQWjXXPytZjuhTKSyCBPeNrB1VVWQq1HCvjbEZ27k44oNmg", "xpub": "zpub6rFDtF1nuXZ9PUL4XzKURh3vJBW6Kj6TUrYL4qPtFNtDXtcTVfiqjQDyrZNwjwzt5HS14qdqo3Co2282Lv3Re6Y5wFZxAVuMEpeygnnDwfx", "label": "Coldcard Import 168DD603", "ckcc_xfp": 64392470, "type": "hardware", "hw_type": "coldcard", "derivation": "m/84'/0'/0'"}, "wallet_type": "standard", "use_encryption": false, "seed_version": 17}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
[8cce63f8/84h/0h/0h]zpub6s2RJ9qAEBW8Abhojs6LyDzF7gttcDr6EsR3Umu2aptZBb45e734rGtt4KqsCMmNyR1EEzUU2ugdVYez2VywQvAbBjUSKn8ho4Zk2c5otkk

File diff suppressed because one or more lines are too long