Security News
Node.js EOL Versions CVE Dubbed the "Worst CVE of the Year" by Security Experts
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
@photon-sdk/photon-lib
Advanced tools
A high level library for building bitcoin wallets with react native
A high level library for building bitcoin wallets with react native.
Provide an easy-to-use high level api for the following:
Please see the threat model doc for a discussion about attack vectors and mitigation strategies.
In your react-native app...
Make sure to install all peer dependencies:
npm install --save @photon-sdk/photon-lib react-native-randombytes react-native-keychain @photon-sdk/react-native-icloudstore @react-native-async-storage/async-storage @photon-sdk/react-native-tcp @react-native-google-signin/google-signin @robinbobin/react-native-google-drive-api-wrapper node-libs-react-native react-native-device-info
npx pod-install
In your target's "capabilities" tab in Xcode, make sure that iCloud is switched on as well as make sure that the "Key-value storage" option is checked.
Follow the usage instructions for node-libs-react-native.
An example app using photon-lib can be found here photon-sdk/photon-app.
This PR shows what the diff should look like when installing photon-lib to your react-native app.
First we'll need to tell the key backup module which key server to use. See photon-sdk/photon-keyserver for how to deploy a key server instance for your app.
import { KeyBackup } from '@photon-sdk/photon-lib';
KeyBackup.init({
keyServerURI: 'http://localhost:3000' // your key server instance
});
The encrypted backup is stored on the user's cloud storage account. On Android the user is required to grant access to an app specific Google Drive folder with an OAuth dialog. For iOS apps this step can be ignored as iCloud does not require extra authentication.
await KeyBackup.authenticate({
clientId: '<FROM DEVELOPER CONSOLE>' // see the Google Drive API docs
});
Now let's do an encrypted backup of a user's wallet to their iCloud account. The encryption key will be stored on your app's key server. A random Key ID
(stored automatically on the user's iCloud) and a user chosen PIN
is used for authentication with the key server.
import { HDSegwitBech32Wallet, KeyBackup } from '@photon-sdk/photon-lib';
const wallet = new HDSegwitBech32Wallet();
await wallet.generate(); // generate a new seed phrase
const mnemonic = await wallet.getSecret(); // the seed phrase to backup
const data = { mnemonic }; // backup payload (any attributes possible)
const pin = '1234'; // PIN for auth to key server
await KeyBackup.createBackup({ data, pin }); // create encrypted cloud backup
Now let's restore the user's wallet on their new device. This will download their encrypted mnemonic from iCloud and decrypt it using the encryption key from the key server. The random Key ID
(stored on the user's iCloud) and the PIN
that was set during wallet backup will be used to authenticate with the key server. N.B. encryption key download is locked for 7 days after 10 failed authentication attempts to mitigate brute forcing of the PIN.
import { HDSegwitBech32Wallet, KeyBackup, WalletStore } from '@photon-sdk/photon-lib';
const exists = await KeyBackup.checkForExistingBackup();
if (!exists) return;
const pin = '1234'; // PIN for auth to key server
const data = await KeyBackup.restoreBackup({ pin }); // fetch and decrypt user's seed
const wallet = new HDSegwitBech32Wallet();
wallet.setSecret(data.mnemonic); // restore from the seed
const store = new WalletStore();
store.wallets.push(wallet);
await store.saveToDisk(); // store securely in device keychain
Users can change the authentication PIN simply by calling the following api. A PIN must be at least 4 digits, but can also be a complex passphrase up to 256 chars in length.
import { KeyBackup } from '@photon-sdk/photon-lib';
const pin = '1234';
const newPin = 'complex passphrases are also possible';
await KeyBackup.changePin({ pin, newPin });
In order to allow for wallet recovery in case the user forgets their PIN, a recovery phone number can be set. A 30 day time delay is enforced for PIN recovery to mitigate SIM swap attacks. The phone number is stored in plaintext only on the user's iCloud. A hash of the phone number is stored on the key server for authentication (hashed with scrypt and a random salt).
import { KeyBackup } from '@photon-sdk/photon-lib';
const userId = '+4917512345678'; // the user's number for 2FA
const pin = '1234';
await KeyBackup.registerPhone({ userId, pin }); // sends code via SMS
const code = '000000'; // received via SMS
await KeyBackup.verifyPhone({ userId, code }); // verify phone number
In order to allow for wallet recovery in case the user forgets their PIN, a recovery email address can be set. A 30 day time delay is enforced for PIN recovery to mitigate SIM swap attacks. The email address is stored in plaintext only on the user's iCloud. A hash of the email address is stored on the key server for authentication (hashed with scrypt and a random salt).
import { KeyBackup } from '@photon-sdk/photon-lib';
const userId = 'jon@example.com'; // the user's number for 2FA
const pin = '1234';
await KeyBackup.registerEmail({ userId, pin }); // sends code via Email
const code = '000000'; // received via Email
await KeyBackup.verifyEmail({ userId, code }); // verify phone number
In case the user forgets their PIN, apps should encourage users to set a recovery phone number or email address during sign up. This can be used later to reset the PIN with a 30 day time delay.
import { KeyBackup } from '@photon-sdk/photon-lib';
const userId = await KeyBackup.getEmail() // get registered email address
await KeyBackup.initPinReset({ userId }); // start time delay in key server
const code = '123456'; // received via SMS or Email
const newPin = '5678'; // let user chose new pin
const delay = await KeyBackup.verifyPinReset({ userId, code, newPin });
if (delay) {
// display delay in the UI and tell user to wait (30 days by default)
return
}
// if delay is null the time lock is over and pin reset can be confirmed ...
await KeyBackup.initPinReset({ userId }); // call again after 30 day delay
const code = '654321'; // received via SMS or Email
await KeyBackup.verifyPinReset({ userId, code, newPin });
const pin = '5678'; // use the new pin for recovery
const data = await KeyBackup.restoreBackup({ pin }); // fetch and decrypt user's seed
First we'll need to init the electrum client by specifying the host and port of our full node.
import { ElectrumClient } from '@photon-sdk/photon-lib';
const options = {
host: 'blockstream.info',
ssl: '700'
};
await ElectrumClient.connectMain(options); // connect to your full node
await ElectrumClient.waitTillConnected();
Now we'll generate a new wallet key, store it securely in the device keychain and fetch transactions and balances using the electrum client.
import { HDSegwitBech32Wallet, WalletStore } from '@photon-sdk/photon-lib';
const wallet = new HDSegwitBech32Wallet();
await wallet.generate(); // or use restored (see above)
const store = new WalletStore();
store.wallets.push(wallet);
await store.saveToDisk(); // store securely in device keychain
await store.fetchWalletBalances(); // get wallet balances from electrum
await store.fetchWalletTransactions(); // get wallet transactions from electrum
const balance = store.getBalance(); // the wallet balance to display in the ui
const address = await wallet.getAddressAsync(); // a new address to receive bitcoin
Finally we'll fetch the wallets utxos, create a new transaction, and broadcast it using the electrum client.
import { HDSegwitBech32Wallet, WalletStore } from '@photon-sdk/photon-lib';
const wallet = new HDSegwitBech32Wallet();
await wallet.generate(); // or use restored (see above)
await wallet.fetchUtxo(); // fetch UTXOs
const utxo = wallet.getUtxo(); // set UTXO as input
const target = [{ // set output address and value in sats
value: 1000,
address: 'some-address'
}];
const feeRate = 1; // set fee rate in sat/vbyte
const changeTo = await wallet.getAddressAsync(); // get change address
const newTx = wallet.createTransaction(utxo, target, feeRate, changeTo);
await wallet.broadcastTx(newTx.tx.toHex()); // broadcast tx to the network
In this example we'll create a 2-of-2 multisig wallet. Cosigners can be added as either xpubs or mnemonics. Once created, the wallet can be interacted with using the same apis as above.
import { MultisigHDWallet, WalletStore } from '@photon-sdk/photon-lib';
const path = "m/48'/0'/0'/2'";
const key1_mnemonic = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
const key2_fp = '05C0D4E1';
const key2_zpub = 'Zpub755JaEN81qADr1Hq22Q6AbiRutDnCMdWghxUrpxkPB5JhdcAzWzQGMiSS58oxEjTqZkxBJ1q6TwvQ1EkiNEsrD18aeVnuJgEDjg1S3ETtd6';
const wallet = new MultisigHDWallet();
wallet.addCosigner(key1_mnemonic);
wallet.addCosigner(key2_zpub, key2_fp);
wallet.setDerivationPath(path);
wallet.setM(2);
const newTx = wallet.createTransaction(utxo, target, feeRate, changeTo); // see above for how to specify args
const signedTx = wallet.cosignPsbt(newTx.psbt); // cosign the psbt (must be done by both cosigners)
await wallet.broadcastTx(signedTx.tx.toHex()); // broadcast tx to the network
Clone the git repo and then:
npm install && npm test
FAQs
A high level library for building bitcoin wallets with react native
The npm package @photon-sdk/photon-lib receives a total of 40 weekly downloads. As such, @photon-sdk/photon-lib popularity was classified as not popular.
We found that @photon-sdk/photon-lib demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Critics call the Node.js EOL CVE a misuse of the system, sparking debate over CVE standards and the growing noise in vulnerability databases.
Security News
cURL and Go security teams are publicly rejecting CVSS as flawed for assessing vulnerabilities and are calling for more accurate, context-aware approaches.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.