Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
gruve-p committed Nov 9, 2023
2 parents 9364f26 + 1be3cc0 commit 636a3a7
Show file tree
Hide file tree
Showing 40 changed files with 480 additions and 186 deletions.
25 changes: 1 addition & 24 deletions App.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ import loc from './loc';
import { BlueDefaultTheme, BlueDarkTheme } from './components/themes';
import InitRoot from './Navigation';
import BlueClipboard from './blue_modules/clipboard';
import { isDesktop } from './blue_modules/environment';
import { BlueStorageContext } from './blue_modules/storage-context';
import WatchConnectivity from './WatchConnectivity';
import DeviceQuickActions from './class/quick-actions';
import Notifications from './blue_modules/notifications';
import Biometric from './class/biometrics';
import WidgetCommunication from './blue_modules/WidgetCommunication';
import changeNavigationBarColor from 'react-native-navigation-bar-color';
import ActionSheet from './screen/ActionSheet';
import HandoffComponent from './components/handoff';
import Privacy from './blue_modules/Privacy';
Expand Down Expand Up @@ -119,27 +117,6 @@ const App = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletsInitialized]);

useEffect(() => {
return () => {
Linking.removeEventListener('url', handleOpenURL);
AppState.removeEventListener('change', handleAppStateChange);
eventEmitter?.removeAllListeners('onNotificationReceived');
eventEmitter?.removeAllListeners('openSettings');
eventEmitter?.removeAllListeners('onUserActivityOpen');
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
if (colorScheme) {
if (colorScheme === 'light') {
changeNavigationBarColor(BlueDefaultTheme.colors.background, true, true);
} else {
changeNavigationBarColor(BlueDarkTheme.colors.buttonBackgroundColor, false, true);
}
}
}, [colorScheme]);

const addListeners = () => {
Linking.addEventListener('url', handleOpenURL);
AppState.addEventListener('change', handleAppStateChange);
Expand Down Expand Up @@ -387,8 +364,8 @@ const App = () => {
<InitRoot />
<Notifications onProcessNotifications={processPushNotifications} />
</NavigationContainer>
{walletsInitialized && !isDesktop && <WatchConnectivity />}
</View>
<WatchConnectivity />
<DeviceQuickActions />
<Biometric />
<WidgetCommunication />
Expand Down
7 changes: 1 addition & 6 deletions BlueComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -558,12 +558,7 @@ export const BlueHeaderDefaultMain = props => {
>
{props.leftText}
</Text>
<PlusIcon
accessibilityRole="button"
accessibilityLabel={loc.wallets.add_title}
onPress={props.onNewWalletPress}
Component={TouchableOpacity}
/>
<PlusIcon accessibilityRole="button" accessibilityLabel={loc.wallets.add_title} onPress={props.onNewWalletPress} />
</View>
);
};
Expand Down
9 changes: 8 additions & 1 deletion Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import WalletAddresses from './screen/wallets/addresses';
import ReorderWallets from './screen/wallets/reorderWallets';
import SelectWallet from './screen/wallets/selectWallet';
import ProvideEntropy from './screen/wallets/provideEntropy';
import GenerateWord from './screen/wallets/generateWord';

import TransactionDetails from './screen/transactions/details';
import TransactionStatus from './screen/transactions/transactionStatus';
Expand Down Expand Up @@ -145,6 +146,7 @@ const WalletsRoot = () => {
/>
<WalletsStack.Screen name="Broadcast" component={Broadcast} options={Broadcast.navigationOptions(theme)} />
<WalletsStack.Screen name="IsItMyAddress" component={IsItMyAddress} options={IsItMyAddress.navigationOptions(theme)} />
<WalletsStack.Screen name="GenerateWord" component={GenerateWord} options={GenerateWord.navigationOptions(theme)} />
<WalletsStack.Screen name="LnurlPay" component={LnurlPay} options={LnurlPay.navigationOptions(theme)} />
<WalletsStack.Screen name="LnurlPaySuccess" component={LnurlPaySuccess} options={LnurlPaySuccess.navigationOptions(theme)} />
<WalletsStack.Screen name="LnurlAuth" component={LnurlAuth} options={LnurlAuth.navigationOptions(theme)} />
Expand Down Expand Up @@ -214,7 +216,12 @@ const SendDetailsRoot = () => {

return (
<SendDetailsStack.Navigator screenOptions={{ headerHideShadow: true }}>
<SendDetailsStack.Screen name="SendDetails" component={SendDetails} options={SendDetails.navigationOptions(theme)} />
<SendDetailsStack.Screen
name="SendDetails"
component={SendDetails}
options={SendDetails.navigationOptions(theme)}
initialParams={SendDetails.initialParams}
/>
<SendDetailsStack.Screen name="Confirm" component={Confirm} options={Confirm.navigationOptions(theme)} />
<SendDetailsStack.Screen
name="PsbtWithHardwareWallet"
Expand Down
39 changes: 26 additions & 13 deletions WatchConnectivity.ios.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useContext, useEffect, useRef } from 'react';
import React, { useContext, useEffect, useRef } from 'react';
import {
updateApplicationContext,
watchEvents,
useReachability,
useInstalled,
usePaired,
transferCurrentComplicationUserInfo,
transferUserInfo,
} from 'react-native-watch-connectivity';
import { Chain } from './models/bitcoinUnits';
import loc, { formatBalance, transactionTimeToReadable } from './loc';
Expand All @@ -18,14 +18,13 @@ function WatchConnectivity() {
const { walletsInitialized, wallets, fetchWalletTransactions, saveToDisk, txMetadata, preferredFiatCurrency } =
useContext(BlueStorageContext);
const isReachable = useReachability();
const isPaired = usePaired();
const isInstalled = useInstalled(); // true | false
const messagesListenerActive = useRef(false);
const lastPreferredCurrency = useRef(FiatUnit.USD.endPointKey);

useEffect(() => {
let messagesListener = () => {};
if (isPaired && isInstalled && isReachable && walletsInitialized && messagesListenerActive.current === false) {
if (isInstalled && isReachable && walletsInitialized && messagesListenerActive.current === false) {
messagesListener = watchEvents.addListener('message', handleMessages);
messagesListenerActive.current = true;
} else {
Expand All @@ -37,14 +36,25 @@ function WatchConnectivity() {
messagesListenerActive.current = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletsInitialized, isPaired, isReachable, isInstalled]);
}, [walletsInitialized, isReachable, isInstalled]);

useEffect(() => {
if (isPaired && isInstalled && isReachable && walletsInitialized) {
sendWalletsToWatch();
console.log(`Apple Watch: isInstalled: ${isInstalled}, isReachable: ${isReachable}, walletsInitialized: ${walletsInitialized}`);
if (isInstalled && walletsInitialized) {
constructWalletsToSendToWatch().then(walletsToProcess => {
if (walletsToProcess) {
if (isReachable) {
transferUserInfo(walletsToProcess);
console.log('Apple Watch: sent info to watch transferUserInfo');
} else {
updateApplicationContext(walletsToProcess);
console.log('Apple Watch: sent info to watch context');
}
}
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletsInitialized, wallets, isPaired, isReachable, isInstalled]);
}, [walletsInitialized, wallets, isReachable, isInstalled]);

useEffect(() => {
updateApplicationContext({ isWalletsInitialized: walletsInitialized, randomID: Math.floor(Math.random() * 11) });
Expand Down Expand Up @@ -78,8 +88,11 @@ function WatchConnectivity() {
reply({});
});
} else if (message.message === 'sendApplicationContext') {
sendWalletsToWatch();
reply({});
constructWalletsToSendToWatch().then(walletsToProcess => {
if (walletsToProcess) {
updateApplicationContext(walletsToProcess);
}
});
} else if (message.message === 'fetchTransactions') {
fetchWalletTransactions()
.then(() => saveToDisk())
Expand Down Expand Up @@ -116,7 +129,7 @@ function WatchConnectivity() {
}
};

const sendWalletsToWatch = async () => {
const constructWalletsToSendToWatch = async () => {
if (!Array.isArray(wallets)) {
console.log('No Wallets set to sync with Watch app. Exiting...');
return;
Expand Down Expand Up @@ -218,10 +231,10 @@ function WatchConnectivity() {
}
walletsToProcess.push(walletInformation);
}
updateApplicationContext({ wallets: walletsToProcess, randomID: Math.floor(Math.random() * 11) });
return { wallets: walletsToProcess, randomID: Math.floor(Math.random() * 11) };
};

return null;
return <></>;
}

export default WatchConnectivity;
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ buildscript {

// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
kotlin_version = '1.9.10'
kotlin_version = '1.9.20'
kotlinVersion = '1.8.0'

}
Expand Down
5 changes: 3 additions & 2 deletions blue_modules/BlueElectrum.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet, TaprootWallet } fro
import DefaultPreference from 'react-native-default-preference';
import loc from '../loc';
import WidgetCommunication from './WidgetCommunication';
import { isTorDaemonDisabled } from './environment';
import { isTorCapable, isTorDaemonDisabled } from './environment';
import alert from '../components/Alert';
const bitcoin = require('groestlcoinjs-lib');
const ElectrumClient = require('electrum-client');
const reverse = require('buffer-reverse');
const BigNumber = require('bignumber.js');
const torrific = require('./torrific');
const torrific = isTorCapable ? require('./torrific') : require('../scripts/maccatalystpatches/torrific.js');

const Realm = require('realm');

const ELECTRUM_HOST = 'electrum_host';
Expand Down
79 changes: 79 additions & 0 deletions blue_modules/checksumWords.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import * as bip39 from 'bip39';
import createHash from 'create-hash';

// partial (11 or 23 word) seed phrase
export function generateChecksumWords(stringSeedPhrase) {
const seedPhrase = stringSeedPhrase.toLowerCase().trim().split(' ');

if ((seedPhrase.length + 1) % 3 > 0) {
return false; // Partial mnemonic size must be multiple of three words, less one.
}

const wordList = bip39.wordlists[bip39.getDefaultWordlist()];

const concatLenBits = seedPhrase.length * 11;
const concatBits = new Array(concatLenBits);
let wordindex = 0;
for (let i = 0; i < seedPhrase.length; i++) {
const word = seedPhrase[i];
const ndx = wordList.indexOf(word.toLowerCase());
if (ndx === -1) return false;
// Set the next 11 bits to the value of the index.
for (let ii = 0; ii < 11; ++ii) {
concatBits[wordindex * 11 + ii] = (ndx & (1 << (10 - ii))) !== 0; // eslint-disable-line no-bitwise
}
++wordindex;
}

const checksumLengthBits = (concatLenBits + 11) / 33;
const entropyLengthBits = concatLenBits + 11 - checksumLengthBits;
const varyingLengthBits = entropyLengthBits - concatLenBits;
const numPermutations = 2 ** varyingLengthBits;

const bitPermutations = new Array(numPermutations);

for (let i = 0; i < numPermutations; i++) {
if (bitPermutations[i] === undefined || bitPermutations[i] === null) bitPermutations[i] = new Array(varyingLengthBits);
for (let j = 0; j < varyingLengthBits; j++) {
bitPermutations[i][j] = ((i >> j) & 1) === 1; // eslint-disable-line no-bitwise
}
}

const possibleWords = [];
for (let i = 0; i < bitPermutations.length; i++) {
const bitPermutation = bitPermutations[i];
const entropyBits = new Array(concatLenBits + varyingLengthBits);
entropyBits.splice(0, 0, ...concatBits);
entropyBits.splice(concatBits.length, 0, ...bitPermutation.slice(0, varyingLengthBits));

const entropy = new Array(entropyLengthBits / 8);
for (let ii = 0; ii < entropy.length; ++ii) {
for (let jj = 0; jj < 8; ++jj) {
if (entropyBits[ii * 8 + jj]) {
entropy[ii] |= 1 << (7 - jj); // eslint-disable-line no-bitwise
}
}
}

const hash = createHash('sha256').update(Buffer.from(entropy)).digest();

const hashBits = new Array(hash.length * 8);
for (let iq = 0; iq < hash.length; ++iq) for (let jq = 0; jq < 8; ++jq) hashBits[iq * 8 + jq] = (hash[iq] & (1 << (7 - jq))) !== 0; // eslint-disable-line no-bitwise

const wordBits = new Array(11);
wordBits.splice(0, 0, ...bitPermutation.slice(0, varyingLengthBits));
wordBits.splice(varyingLengthBits, 0, ...hashBits.slice(0, checksumLengthBits));

let index = 0;
for (let j = 0; j < 11; ++j) {
index <<= 1; // eslint-disable-line no-bitwise
if (wordBits[j]) {
index |= 0x1; // eslint-disable-line no-bitwise
}
}

possibleWords.push(wordList[index]);
}

return possibleWords;
}
1 change: 1 addition & 0 deletions blue_modules/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const getIsTorCapable = (): boolean => {
} else if (isDesktop) {
capable = false;
}
console.log('getIsTorCapable', capable);
return capable;
};

Expand Down
5 changes: 3 additions & 2 deletions class/lnurl.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { bech32 } from 'bech32';
import bolt11 from 'bolt11grs';
import { isTorDaemonDisabled } from '../blue_modules/environment';
import { isTorCapable, isTorDaemonDisabled } from '../blue_modules/environment';
import { parse } from 'url'; // eslint-disable-line n/no-deprecated-api
import { createHmac } from 'crypto';
import secp256k1 from 'secp256k1';
const CryptoJS = require('crypto-js');
const createHash = require('create-hash');
const torrific = require('../blue_modules/torrific');
const torrific = isTorCapable ? require('../blue_modules/torrific') : require('../scripts/maccatalystpatches/torrific.js');

const ONION_REGEX = /^(http:\/\/[^/:@]+\.onion(?::\d{1,5})?)(\/.*)?$/; // regex for onion URL

/**
Expand Down
Loading

0 comments on commit 636a3a7

Please sign in to comment.