From 31f8d2f48d1d0cd9cc715f2353c36b77ac0da5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hampus=20Sj=C3=B6berg?= Date: Thu, 15 Feb 2024 20:38:22 +0400 Subject: [PATCH] Replace react-native-securerandom as a dependency --- .../java/com/blixtwallet/LndMobileTools.java | 9 + ios/LndMobile/LndMobileTools.m | 5 + ios/LndMobile/LndMobileTools.swift | 19 ++ mocks/lndmobile/index.ts | 133 ++++++++----- src/lndmobile/LndMobile.d.ts | 1 + src/lndmobile/fake/index.ts | 176 +++++++++++------- src/lndmobile/index.ts | 16 +- src/state/BlixtLsp.ts | 96 +++++++--- src/state/LndMobileInjection.ts | 7 +- src/state/LndMobileInjectionFake.ts | 6 + src/state/index.ts | 7 +- src/windows/InitProcess/DEV_Commands.tsx | 11 +- src/windows/Keysend/Experiment.tsx | 2 +- src/windows/Keysend/Test.tsx | 2 +- .../LightningBox/LightningBoxRegistration.tsx | 2 +- 15 files changed, 345 insertions(+), 147 deletions(-) diff --git a/android/app/src/main/java/com/blixtwallet/LndMobileTools.java b/android/app/src/main/java/com/blixtwallet/LndMobileTools.java index 0679f0c7c..114818830 100644 --- a/android/app/src/main/java/com/blixtwallet/LndMobileTools.java +++ b/android/app/src/main/java/com/blixtwallet/LndMobileTools.java @@ -33,6 +33,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; +import java.security.SecureRandom; import java.util.Arrays; import java.io.UnsupportedEncodingException; @@ -756,6 +757,14 @@ public void getInternalFiles(Promise promise) { } } + @ReactMethod + public void generateSecureRandomAsBase64(int length, Promise promise) { + SecureRandom secureRandom = new SecureRandom(); + byte[] buffer = new byte[length]; + secureRandom.nextBytes(buffer); + promise.resolve(Base64.encodeToString(buffer, Base64.NO_WRAP)); + } + private void checkWriteExternalStoragePermission(@NonNull RequestWriteExternalStoragePermissionCallback successCallback, @NonNull Runnable failCallback, @NonNull Runnable failPermissionCheckcallback) { diff --git a/ios/LndMobile/LndMobileTools.m b/ios/LndMobile/LndMobileTools.m index 7c6987b13..f15a21190 100644 --- a/ios/LndMobile/LndMobileTools.m +++ b/ios/LndMobile/LndMobileTools.m @@ -139,4 +139,9 @@ @interface RCT_EXTERN_MODULE(LndMobileTools, RCTEventEmitter) rejecter: (RCTPromiseRejectBlock)reject ) +RCT_EXTERN_METHOD( + generateSecureRandomAsBase64: (NSInteger)length + resolver: (RCTPromiseResolveBlock)resolve + rejecter: (RCTPromiseRejectBlock)reject +) @end diff --git a/ios/LndMobile/LndMobileTools.swift b/ios/LndMobile/LndMobileTools.swift index 94a5a72bf..36574b74a 100644 --- a/ios/LndMobile/LndMobileTools.swift +++ b/ios/LndMobile/LndMobileTools.swift @@ -702,4 +702,23 @@ autopilot.heuristic=preferential:0.05 } resolve(filesMap) } + + @objc(generateSecureRandomAsBase64:resolver:rejecter:) + func generateSecureRandomAsBase64(length: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) { + var bytes = Data(count: length) + let result = bytes.withUnsafeMutableBytes { mutableBytes -> Int32 in + if let baseAddress = mutableBytes.baseAddress { + return SecRandomCopyBytes(kSecRandomDefault, length, baseAddress) + } else { + return errSecParam + } + } + + if result == errSecSuccess { + resolve(bytes.base64EncodedString()) + } else { + let error = NSError(domain: "LndMobileTools", code: Int(result), userInfo: nil) + reject("randombytes_error", "Error generating random bytes", error) + } + } } diff --git a/mocks/lndmobile/index.ts b/mocks/lndmobile/index.ts index d4ff9a502..edf30f6ce 100644 --- a/mocks/lndmobile/index.ts +++ b/mocks/lndmobile/index.ts @@ -33,16 +33,25 @@ export const writeConfigFile = jest.fn(async () => { return "File written:"; }); -export const subscribeStateEmitter = (data: Uint8Array) => DeviceEventEmitter.emit("SubscribeState", { data: base64.fromByteArray(data) }); +export const subscribeStateEmitter = (data: Uint8Array) => + DeviceEventEmitter.emit("SubscribeState", { data: base64.fromByteArray(data) }); export const subscribeState = async () => { setTimeout(async () => { subscribeStateEmitter( lnrpc.SubscribeStateResponse.encode({ state: lnrpc.WalletState.LOCKED, - }).finish() + }).finish(), ); - }, 10) -} + }, 10); +}; + +export const generateSecureRandomAsBase64 = jest.fn(async (length: number) => { + return "c2F0b3NoaQ=="; +}); + +export const generateSecureRandom = jest.fn(async (length: number) => { + return new Uint8Array([0, 1, 2, 3]); +}); export const decodeState = (data: string): lnrpc.SubscribeStateResponse => { return decodeStreamResult({ @@ -84,10 +93,12 @@ export const startLnd = jest.fn(async (): Promise => { export const getInfoResponse = lnrpc.GetInfoResponse.create({ uris: [], - chains: [{ - chain: "bitcoin", - network: "testnet", - }], + chains: [ + { + chain: "bitcoin", + network: "testnet", + }, + ], identityPubkey: "02b5380da0919e32b13c1a21c1c85000eed0ba9a9309fc6849d72230d43088ae1d", alias: "02b5380da0919e32b13c", numPeers: 3, @@ -100,13 +111,18 @@ export const getInfoResponse = lnrpc.GetInfoResponse.create({ version: "0.7.1-beta commit=v0.7.1-beta-rc1-10-g3760f29f5e758b2865b756604333ca22cf23e90b", features: {}, }); -export const getInfo = jest.fn() +export const getInfo = jest + .fn() .mockImplementationOnce(async () => getInfoResponse) - .mockImplementation(async () => ({ ...getInfoResponse, syncedToChain: true, syncedToGraph: true })); + .mockImplementation(async () => ({ + ...getInfoResponse, + syncedToChain: true, + syncedToGraph: true, + })); export const sendPaymentSync = async (paymentRequest: string): Promise => { const response = lnrpc.SendResponse.create({ - paymentHash: new Uint8Array([1,2,3,4]), + paymentHash: new Uint8Array([1, 2, 3, 4]), paymentRoute: { totalAmt: Long.fromNumber(1000), totalAmtMsat: Long.fromNumber(1000000), @@ -121,8 +137,8 @@ export const sendPaymentSync = async (paymentRequest: string): Promise => { await timeout(600); - const paymentHash = new Uint8Array([0,1,2,3]); - const paymentPreimage = new Uint8Array([0,1,2,3]); + const paymentHash = new Uint8Array([0, 1, 2, 3]); + const paymentPreimage = new Uint8Array([0, 1, 2, 3]); const response = lnrpc.Payment.create({ paymentHash: bytesToHexString(paymentHash), @@ -131,25 +147,33 @@ export const sendPaymentV2Sync = async (paymentRequest: string): Promise => { +export const addInvoice = async ( + amount: number, + memo: string, + expiry: number = 3600, +): Promise => { try { const unixTimestamp = Math.floor(Date.now() / 1000); const encoded = payReq.encode({ @@ -157,13 +181,16 @@ export const addInvoice = async (amount: number, memo: string, expiry: number = satoshis: amount, timestamp: unixTimestamp, timeExpireDate: expiry, - tags: [{ - tagName: "payment_hash", - data: "0001020304050607080900010203040506070809000102030405060708090102", - }, { - tagName: "description", - data: memo, - }], + tags: [ + { + tagName: "payment_hash", + data: "0001020304050607080900010203040506070809000102030405060708090102", + }, + { + tagName: "description", + data: memo, + }, + ], }); const privateKeyHex = "e126f68f7eafcc8b74f54d269fe206be715000f94dac067d1c04a8ca3b2db734"; @@ -188,7 +215,7 @@ export const addInvoice = async (amount: number, memo: string, expiry: number = value: Long.fromNumber(signed!.satoshis!), amtPaidMsat: Long.fromNumber(signed!.satoshis!).mul(1000), amtPaidSat: Long.fromNumber(signed!.satoshis!), - cltvExpiry: cltvExpiry && (Long.fromNumber(cltvExpiry.data as number)), + cltvExpiry: cltvExpiry && Long.fromNumber(cltvExpiry.data as number), creationDate: Long.fromNumber(signed!.timestamp!), expiry: Long.fromNumber(expiry), rPreimage: new Uint8Array([1, 2, 3, 4]), // TODO @@ -207,9 +234,19 @@ export const addInvoice = async (amount: number, memo: string, expiry: number = } }; -export const addInvoiceBlixtLsp = ({amount, memo, expiry = 600, servicePubkey, chanId, cltvExpiryDelta, feeBaseMsat, feeProportionalMillionths, preimage}: IAddInvoiceBlixtLspArgs) => { +export const addInvoiceBlixtLsp = ({ + amount, + memo, + expiry = 600, + servicePubkey, + chanId, + cltvExpiryDelta, + feeBaseMsat, + feeProportionalMillionths, + preimage, +}: IAddInvoiceBlixtLspArgs) => { return addInvoice(amount, memo, expiry); -} +}; // // export const lookupInvoice = async (rHash: string): Promise => { @@ -224,12 +261,16 @@ export const addInvoiceBlixtLsp = ({amount, memo, expiry = 600, servicePubkey, c // return response; // }; -export const queryRoutes = async (pubKey: string, amount?: Long, routeHints?: lnrpc.IRouteHint[]): Promise => { +export const queryRoutes = async ( + pubKey: string, + amount?: Long, + routeHints?: lnrpc.IRouteHint[], +): Promise => { return lnrpc.QueryRoutesResponse.create({ routes: [], successProb: 0.5, }); -} +}; // TODO test export const decodePayReq = async (bolt11: string): Promise => { @@ -250,30 +291,30 @@ export const decodePayReq = async (bolt11: string): Promise => { /** * @throws */ - export const getRecoveryInfo = async (): Promise => { +export const getRecoveryInfo = async (): Promise => { const response = lnrpc.GetRecoveryInfoResponse.create({ progress: 1, recoveryFinished: false, recoveryMode: false, - }) + }); return response; }; /** * @throws */ - export const listUnspent = async (): Promise => { +export const listUnspent = async (): Promise => { const response = lnrpc.ListUnspentResponse.create({ - utxos: [] - }) + utxos: [], + }); return response; }; /** * @throws */ - export const resetMissionControl = async (): Promise => { - const response = routerrpc.ResetMissionControlResponse.create({}) +export const resetMissionControl = async (): Promise => { + const response = routerrpc.ResetMissionControlResponse.create({}); return response; }; diff --git a/src/lndmobile/LndMobile.d.ts b/src/lndmobile/LndMobile.d.ts index 89c5a0588..c335799ce 100644 --- a/src/lndmobile/LndMobile.d.ts +++ b/src/lndmobile/LndMobile.d.ts @@ -39,6 +39,7 @@ export interface ILndMobile { export interface ILndMobileTools { writeConfig(data: string): Promise; writeConfigFile(): Promise; + generateSecureRandomAsBase64(length: number): Promise; killLnd(): Promise; log(level: "v" | "d" | "i" | "w" | "e", tag: string, msg: string): void; saveLogs(): Promise; diff --git a/src/lndmobile/fake/index.ts b/src/lndmobile/fake/index.ts index c5dfcf018..d22866205 100644 --- a/src/lndmobile/fake/index.ts +++ b/src/lndmobile/fake/index.ts @@ -1,5 +1,4 @@ import { NativeModules, DeviceEventEmitter } from "react-native"; -import { generateSecureRandom } from "react-native-securerandom"; import { lnrpc, routerrpc, invoicesrpc } from "../../../proto/lightning"; import Long from "long"; import sha from "sha.js"; @@ -51,15 +50,24 @@ export const writeConfigFile = async () => { return "File written:"; }; -export const subscribeStateEmitter = (data: Uint8Array) => DeviceEventEmitter.emit("SubscribeState", { data: base64.fromByteArray(data) }); +export const subscribeStateEmitter = (data: Uint8Array) => + DeviceEventEmitter.emit("SubscribeState", { data: base64.fromByteArray(data) }); export const subscribeState = async () => { subscribeStateEmitter( lnrpc.SubscribeStateResponse.encode({ state: lnrpc.WalletState.LOCKED, - }).finish() + }).finish(), ); return "subscribing"; -} +}; + +export const generateSecureRandomAsBase64 = async (length: number) => { + return "c2F0b3NoaQ=="; +}; + +export const generateSecureRandom = async (length: number) => { + return new Uint8Array([0, 1, 2, 3]); +}; export const decodeState = (data: string): lnrpc.SubscribeStateResponse => { return decodeStreamResult({ @@ -118,7 +126,10 @@ export const checkICloudEnabled = async (): Promise => { /** * @throws */ -export const connectPeer = async (pubkey: string, host: string): Promise => { +export const connectPeer = async ( + pubkey: string, + host: string, +): Promise => { const response = lnrpc.ConnectPeerResponse.create({}); return response; }; @@ -162,13 +173,12 @@ export const getNetworkInfo = async (): Promise => { // TODO(hsjoberg): lots of missing API funcs - export const subscribeCustomMessages = async () => { return "subscribing"; -} +}; export const decodeCustomMessage = (data: string): lnrpc.CustomMessage => { - console.error("fake decodeCustomMessage not implemented"); + console.error("fake decodeCustomMessage not implemented"); }; /** @@ -179,10 +189,12 @@ export const getInfo = async (): Promise => { if (getInfoCount++ < 1) { const response = lnrpc.GetInfoResponse.create({ uris: [], - chains: [{ - chain: "bitcoin", - network: "testnet", - }], + chains: [ + { + chain: "bitcoin", + network: "testnet", + }, + ], identityPubkey: "02b5380da0919e32b13c1a21c1c85000eed0ba9a9309fc6849d72230d43088ae1d", alias: "02b5380da0919e32b13c", numPeers: 3, @@ -199,10 +211,12 @@ export const getInfo = async (): Promise => { } const response = lnrpc.GetInfoResponse.create({ uris: [], - chains: [{ - chain: "bitcoin", - network: "testnet", - }], + chains: [ + { + chain: "bitcoin", + network: "testnet", + }, + ], identityPubkey: "02b5380da0919e32b13c1a21c1c85000eed0ba9a9309fc6849d72230d43088ae1d", alias: "02b5380da0919e32b13c", numPeers: 3, @@ -225,7 +239,11 @@ export const getInfo = async (): Promise => { * @params name TLV record for sender name * */ -export const sendPaymentSync = async (paymentRequest: string, amount?: Long, tlvRecordName?: string | null): Promise => { +export const sendPaymentSync = async ( + paymentRequest: string, + amount?: Long, + tlvRecordName?: string | null, +): Promise => { await timeout(600); const paymentHash = await generateSecureRandom(32); @@ -245,8 +263,11 @@ export const sendPaymentSync = async (paymentRequest: string, amount?: Long, tlv return response; }; - -export const sendPaymentV2Sync = async (paymentRequest: string, amount?: Long, tlvRecordName?: string | null): Promise => { +export const sendPaymentV2Sync = async ( + paymentRequest: string, + amount?: Long, + tlvRecordName?: string | null, +): Promise => { await timeout(600); const paymentHash = await generateSecureRandom(32); @@ -259,20 +280,24 @@ export const sendPaymentV2Sync = async (paymentRequest: string, amount?: Long, t status: lnrpc.Payment.PaymentStatus.SUCCEEDED, fee: Long.fromValue(1), feeMsat: Long.fromValue(1000), - htlcs: [{ - route: { - hops: [{ - chanId: Long.fromValue(1), - chanCapacity: Long.fromValue(10000), - amtToForward: Long.fromValue(100), - amtToForwardMsat: Long.fromValue(100000), - fee: Long.fromValue(1), - feeMsat: Long.fromValue(1000), - expiry: 3600, - pubKey: "abc", - }], + htlcs: [ + { + route: { + hops: [ + { + chanId: Long.fromValue(1), + chanCapacity: Long.fromValue(10000), + amtToForward: Long.fromValue(100), + amtToForwardMsat: Long.fromValue(100000), + fee: Long.fromValue(1), + feeMsat: Long.fromValue(1000), + expiry: 3600, + pubKey: "abc", + }, + ], + }, }, - }], + ], }); return response; }; @@ -286,11 +311,14 @@ export const decodeSendPaymentV2Result = (data: string): lnrpc.Payment => { // }); }; - /** * @throws */ -export const sendKeysendPaymentSync = async (destinationPubKey: Uint8Array, sat: Long, preImage: Uint8Array): Promise => { +export const sendKeysendPaymentSync = async ( + destinationPubKey: Uint8Array, + sat: Long, + preImage: Uint8Array, +): Promise => { console.error("fake sendKeysendPaymentSync not implemented"); // const response = await sendCommand({ // request: lnrpc.SendRequest, @@ -314,7 +342,11 @@ export const sendKeysendPaymentSync = async (destinationPubKey: Uint8Array, sat: /** * @throws */ -export const addInvoice = async (amount: number, memo: string, expiry: number = 3600): Promise => { +export const addInvoice = async ( + amount: number, + memo: string, + expiry: number = 3600, +): Promise => { try { const paymentHash = await generateSecureRandom(32); const paymentPreimage = await generateSecureRandom(32); @@ -337,7 +369,8 @@ export const addInvoice = async (amount: number, memo: string, expiry: number = // const signed = payReq.sign(encoded, privateKeyHex); const response = lnrpc.AddInvoiceResponse.create({ - paymentRequest: "lnbc1p0nqccppp5p5kgsr0sfc787n6xzpwv63k05k05lzzck90peefr37nxvktp06rqdq0fpsk6ur4wvazqgqcqzpgxqrrssrzjqtdqwyatrvfwavqlyy55ffp4qalnnudhvlh9cf9srnd5kzunw7mxkzwxg5qq0ksqqqqqqyugqqqqhwqpyqsp53sukk23w33nyvg5efjrl5k8dkjlcqrwjn25jeeca80t599fg7n9s9qy9qsq70vcpv4zpgp465w0n373yxqrcla8n07teznwwu4srv4gvhrmhaeqh4zuerl370ms7dxu5wulqcafaf2u6egeay0vuma94yrwud2n6esq7wq4t9", + paymentRequest: + "lnbc1p0nqccppp5p5kgsr0sfc787n6xzpwv63k05k05lzzck90peefr37nxvktp06rqdq0fpsk6ur4wvazqgqcqzpgxqrrssrzjqtdqwyatrvfwavqlyy55ffp4qalnnudhvlh9cf9srnd5kzunw7mxkzwxg5qq0ksqqqqqqyugqqqqhwqpyqsp53sukk23w33nyvg5efjrl5k8dkjlcqrwjn25jeeca80t599fg7n9s9qy9qsq70vcpv4zpgp465w0n373yxqrcla8n07teznwwu4srv4gvhrmhaeqh4zuerl370ms7dxu5wulqcafaf2u6egeay0vuma94yrwud2n6esq7wq4t9", addIndex: Long.fromNumber(0), rHash: paymentHash, }); @@ -346,7 +379,8 @@ export const addInvoice = async (amount: number, memo: string, expiry: number = // const description = signed!.tags.find((tag) => tag.tagName === "d"); // const cltvExpiry = signed!.tags.find((tag) => tag.tagName === "min_final_cltv_expiry"); const invoice = lnrpc.Invoice.create({ - paymentRequest: "lnbc1p0nqccppp5p5kgsr0sfc787n6xzpwv63k05k05lzzck90peefr37nxvktp06rqdq0fpsk6ur4wvazqgqcqzpgxqrrssrzjqtdqwyatrvfwavqlyy55ffp4qalnnudhvlh9cf9srnd5kzunw7mxkzwxg5qq0ksqqqqqqyugqqqqhwqpyqsp53sukk23w33nyvg5efjrl5k8dkjlcqrwjn25jeeca80t599fg7n9s9qy9qsq70vcpv4zpgp465w0n373yxqrcla8n07teznwwu4srv4gvhrmhaeqh4zuerl370ms7dxu5wulqcafaf2u6egeay0vuma94yrwud2n6esq7wq4t9", + paymentRequest: + "lnbc1p0nqccppp5p5kgsr0sfc787n6xzpwv63k05k05lzzck90peefr37nxvktp06rqdq0fpsk6ur4wvazqgqcqzpgxqrrssrzjqtdqwyatrvfwavqlyy55ffp4qalnnudhvlh9cf9srnd5kzunw7mxkzwxg5qq0ksqqqqqqyugqqqqhwqpyqsp53sukk23w33nyvg5efjrl5k8dkjlcqrwjn25jeeca80t599fg7n9s9qy9qsq70vcpv4zpgp465w0n373yxqrcla8n07teznwwu4srv4gvhrmhaeqh4zuerl370ms7dxu5wulqcafaf2u6egeay0vuma94yrwud2n6esq7wq4t9", private: false, memo, addIndex: Long.fromNumber(0), // TODO @@ -365,7 +399,7 @@ export const addInvoice = async (amount: number, memo: string, expiry: number = DeviceEventEmitter.emit("SubscribeInvoices", { data: base64.fromByteArray(lnrpc.Invoice.encode(invoice).finish()), }); - }, 600); + }, 600); return response; } catch (e) { @@ -373,14 +407,26 @@ export const addInvoice = async (amount: number, memo: string, expiry: number = throw e; } }; -export const addInvoiceBlixtLsp = ({amount, memo, expiry = 600, servicePubkey, chanId, cltvExpiryDelta, feeBaseMsat, feeProportionalMillionths, preimage}: IAddInvoiceBlixtLspArgs) => { +export const addInvoiceBlixtLsp = ({ + amount, + memo, + expiry = 600, + servicePubkey, + chanId, + cltvExpiryDelta, + feeBaseMsat, + feeProportionalMillionths, + preimage, +}: IAddInvoiceBlixtLspArgs) => { return addInvoice(amount, memo, expiry); -} +}; -export const cancelInvoice = async (paymentHash: string): Promise => { +export const cancelInvoice = async ( + paymentHash: string, +): Promise => { const response = invoicesrpc.CancelInvoiceResp.create({}); return response; -} +}; /** * @throws @@ -391,7 +437,8 @@ export const lookupInvoice = async (rHash: string): Promise => { const invoice = lnrpc.Invoice.create({ creationDate: Long.fromValue(unixTimestamp), expiry: Long.fromValue(3600), - paymentRequest: "lnbc1p0nqccppp5p5kgsr0sfc787n6xzpwv63k05k05lzzck90peefr37nxvktp06rqdq0fpsk6ur4wvazqgqcqzpgxqrrssrzjqtdqwyatrvfwavqlyy55ffp4qalnnudhvlh9cf9srnd5kzunw7mxkzwxg5qq0ksqqqqqqyugqqqqhwqpyqsp53sukk23w33nyvg5efjrl5k8dkjlcqrwjn25jeeca80t599fg7n9s9qy9qsq70vcpv4zpgp465w0n373yxqrcla8n07teznwwu4srv4gvhrmhaeqh4zuerl370ms7dxu5wulqcafaf2u6egeay0vuma94yrwud2n6esq7wq4t9", + paymentRequest: + "lnbc1p0nqccppp5p5kgsr0sfc787n6xzpwv63k05k05lzzck90peefr37nxvktp06rqdq0fpsk6ur4wvazqgqcqzpgxqrrssrzjqtdqwyatrvfwavqlyy55ffp4qalnnudhvlh9cf9srnd5kzunw7mxkzwxg5qq0ksqqqqqqyugqqqqhwqpyqsp53sukk23w33nyvg5efjrl5k8dkjlcqrwjn25jeeca80t599fg7n9s9qy9qsq70vcpv4zpgp465w0n373yxqrcla8n07teznwwu4srv4gvhrmhaeqh4zuerl370ms7dxu5wulqcafaf2u6egeay0vuma94yrwud2n6esq7wq4t9", private: false, // memo, addIndex: Long.fromNumber(0), // TODO @@ -427,24 +474,25 @@ export const lookupInvoice = async (rHash: string): Promise => { export const listPeers = async (): Promise => { console.error("fake listPeers not implemented"); const listPeers = lnrpc.ListPeersResponse.create({ - peers: [{ - address: "123.456.78.90", - bytesRecv: Long.fromValue(10), - bytesSent: Long.fromValue(10), - errors: [], - features: {}, - inbound: false, - pingTime: Long.fromValue(50), - pubKey: "abcdef123456", - satRecv: Long.fromValue(100), - satSent: Long.fromValue(100), - syncType: lnrpc.Peer.SyncType.PASSIVE_SYNC, - }] + peers: [ + { + address: "123.456.78.90", + bytesRecv: Long.fromValue(10), + bytesSent: Long.fromValue(10), + errors: [], + features: {}, + inbound: false, + pingTime: Long.fromValue(50), + pubKey: "abcdef123456", + satRecv: Long.fromValue(100), + satSent: Long.fromValue(100), + syncType: lnrpc.Peer.SyncType.PASSIVE_SYNC, + }, + ], }); return listPeers; }; - /** * @throws */ @@ -484,30 +532,30 @@ export const decodePayReq = async (bolt11: string): Promise => { /** * @throws */ - export const getRecoveryInfo = async (): Promise => { +export const getRecoveryInfo = async (): Promise => { const response = lnrpc.GetRecoveryInfoResponse.create({ progress: 1, recoveryFinished: false, recoveryMode: false, - }) + }); return response; }; /** * @throws */ - export const listUnspent = async (): Promise => { +export const listUnspent = async (): Promise => { const response = lnrpc.ListUnspentResponse.create({ - utxos: [] - }) + utxos: [], + }); return response; }; /** * @throws */ - export const resetMissionControl = async (): Promise => { - const response = routerrpc.ResetMissionControlResponse.create({}) +export const resetMissionControl = async (): Promise => { + const response = routerrpc.ResetMissionControlResponse.create({}); return response; }; diff --git a/src/lndmobile/index.ts b/src/lndmobile/index.ts index 7c0f9da26..5d755ebf9 100644 --- a/src/lndmobile/index.ts +++ b/src/lndmobile/index.ts @@ -1,8 +1,9 @@ import { TLV_KEYSEND, TLV_RECORD_NAME, TLV_WHATSAT_MESSAGE } from "../utils/constants"; import { decodeStreamResult, sendCommand, sendStreamCommand } from "./utils"; -import { devrpc, invoicesrpc, lnrpc, routerrpc } from "../../proto/lightning"; +import { invoicesrpc, lnrpc, routerrpc } from "../../proto/lightning"; import { getChanInfo, listPrivateChannels } from "./channel"; import { hexToUint8Array, stringToUint8Array, unicodeStringToUint8Array } from "../utils"; +import { toByteArray as base64ToByteArray } from "base64-js"; import { LndMobileEventEmitter } from "../utils/event-listener"; import Long from "long"; @@ -60,6 +61,19 @@ export const subscribeState = async () => { return response; }; +/** + * @throws + * @return string + */ +export const generateSecureRandomAsBase64 = async (length: number) => { + return await LndMobileTools.generateSecureRandomAsBase64(length); +}; + +export const generateSecureRandom = async (length: number) => { + const randomBase64 = await generateSecureRandomAsBase64(length); + return base64ToByteArray(randomBase64); +}; + export const decodeState = (data: string): lnrpc.SubscribeStateResponse => { return decodeStreamResult({ response: lnrpc.SubscribeStateResponse, diff --git a/src/state/BlixtLsp.ts b/src/state/BlixtLsp.ts index 7d816310b..67acda879 100644 --- a/src/state/BlixtLsp.ts +++ b/src/state/BlixtLsp.ts @@ -1,14 +1,11 @@ -import { NativeModules } from "react-native"; import { Action, action, computed, Computed, Thunk, thunk } from "easy-peasy"; -import { generateSecureRandom } from "react-native-securerandom"; +import { generateSecureRandom } from "../lndmobile/index"; import { IStoreInjections } from "./store"; import { bytesToHexString, stringToUint8Array, timeout } from "../utils"; import { IStoreModel } from "./index"; import { LndMobileEventEmitter } from "../utils/event-listener"; import { checkLndStreamErrorResponse } from "../utils/lndmobile"; -import * as base64 from "base64-js"; -import { PLATFORM } from "../utils/constants"; import logger from "./../utils/log"; const log = logger("BlixtLsp"); @@ -68,13 +65,48 @@ export interface IOnDemandChannelUnknownRequestResponse extends IErrorResponse { export interface IOndemandChannel { checkOndemandChannelService: Thunk; - connectToService: Thunk>; - addInvoice: Thunk; - - serviceStatus: Thunk>; - checkStatus: Thunk>; - register: Thunk>; - claim: Thunk>; + connectToService: Thunk< + IOndemandChannel, + undefined, + IStoreInjections, + IStoreModel, + Promise + >; + addInvoice: Thunk< + IOndemandChannel, + { sat: number; description: string; preimage?: Uint8Array }, + IStoreInjections, + IStoreModel + >; + + serviceStatus: Thunk< + IOndemandChannel, + void, + IStoreInjections, + IStoreModel, + Promise + >; + checkStatus: Thunk< + IOndemandChannel, + void, + IStoreInjections, + IStoreModel, + Promise + >; + register: Thunk< + IOndemandChannel, + { preimage: Uint8Array; amount: number }, + IStoreInjections, + IStoreModel, + Promise + >; + claim: Thunk< + IOndemandChannel, + void, + IStoreInjections, + IStoreModel, + Promise + >; registerInvoicePreimage: Uint8Array | null; setRegisterInvoicePreimage: Action; @@ -90,7 +122,7 @@ export interface IBlixtLsp { // On-demand Channels ondemandChannel: IOndemandChannel; -}; +} export const blixtLsp: IBlixtLsp = { initialize: thunk(async (actions, _, { getState, getStoreState, getStoreActions }) => { @@ -149,20 +181,24 @@ export const blixtLsp: IBlixtLsp = { log.i("checkStatus"); const dunderServer = getStoreState().settings.dunderServer; - const signMessageResult = await injections.lndMobile.wallet.signMessageNodePubkey(stringToUint8Array("CHECKSTATUS")); + const signMessageResult = await injections.lndMobile.wallet.signMessageNodePubkey( + stringToUint8Array("CHECKSTATUS"), + ); const request = JSON.stringify({ pubkey: getStoreState().lightning.nodeInfo?.identityPubkey, signature: signMessageResult.signature, }); - return (await fetch(`${dunderServer}/ondemand-channel/check-status`, { - body: request, - method: "POST", - })).json(); + return ( + await fetch(`${dunderServer}/ondemand-channel/check-status`, { + body: request, + method: "POST", + }) + ).json(); }), - connectToService: thunk((async (actions, _, { getStoreActions }) => { + connectToService: thunk(async (actions, _, { getStoreActions }) => { const result = await actions.serviceStatus(); log.d("serviceStatus", [result]); @@ -182,9 +218,9 @@ export const blixtLsp: IBlixtLsp = { } } return connectToPeer; - })), + }), - addInvoice: thunk((async (actions, { sat, description, preimage }, { getStoreActions }) => { + addInvoice: thunk(async (actions, { sat, description, preimage }, { getStoreActions }) => { if (!preimage) { preimage = await generateSecureRandom(32); } @@ -206,12 +242,14 @@ export const blixtLsp: IBlixtLsp = { }); console.log(invoice); return invoice; - })), + }), register: thunk(async (actions, { preimage, amount }, { getStoreState, injections }) => { log.i("register"); const dunderServer = getStoreState().settings.dunderServer; - const signMessageResult = await injections.lndMobile.wallet.signMessageNodePubkey(stringToUint8Array("REGISTER")); + const signMessageResult = await injections.lndMobile.wallet.signMessageNodePubkey( + stringToUint8Array("REGISTER"), + ); // const getInfoResponse = await injections.lndMobile.index.getInfo(); const request: IOnDemandChannelRegisterRequest = { pubkey: getStoreState().lightning.nodeInfo?.identityPubkey!, @@ -237,17 +275,21 @@ export const blixtLsp: IBlixtLsp = { log.i("claim"); const dunderServer = getStoreState().settings.dunderServer; - const signMessageResult = await injections.lndMobile.wallet.signMessageNodePubkey(stringToUint8Array("CLAIM")); + const signMessageResult = await injections.lndMobile.wallet.signMessageNodePubkey( + stringToUint8Array("CLAIM"), + ); const request = JSON.stringify({ pubkey: getStoreState().lightning.nodeInfo?.identityPubkey, signature: signMessageResult.signature, }); - return (await fetch(`${dunderServer}/ondemand-channel/claim`, { - body: request, - method: "POST", - })).json(); + return ( + await fetch(`${dunderServer}/ondemand-channel/claim`, { + body: request, + method: "POST", + }) + ).json(); }), setRegisterInvoicePreimage: action((store, payload) => { diff --git a/src/state/LndMobileInjection.ts b/src/state/LndMobileInjection.ts index 9eecf5038..f5dd586d3 100644 --- a/src/state/LndMobileInjection.ts +++ b/src/state/LndMobileInjection.ts @@ -34,6 +34,8 @@ import { trackPaymentV2Sync, writeConfig, writeConfigFile, + generateSecureRandomAsBase64, + generateSecureRandom, subscribeCustomMessages, decodeCustomMessage, sendCustomMessage, @@ -85,7 +87,6 @@ import { import { modifyStatus, queryScores, setScores, status } from "../lndmobile/autopilot"; import { WorkInfo } from "../lndmobile/LndMobile"; -import { checkScheduledGossipSyncWorkStatus } from "../lndmobile/scheduled-gossip-sync"; import { checkScheduledSyncWorkStatus } from "../lndmobile/scheduled-sync"; // TODO(hsjoberg): This could be its own injection "LndMobileScheduledSync" export interface ILndMobileInjections { @@ -93,6 +94,8 @@ export interface ILndMobileInjections { initialize: () => Promise<{ data: string } | number>; writeConfig: (config: string) => Promise; writeConfigFile: () => Promise; + generateSecureRandomAsBase64: (length: number) => Promise; + generateSecureRandom: (length: number) => Promise; subscribeState: () => Promise; decodeState: (data: string) => lnrpc.SubscribeStateResponse; checkStatus: () => Promise; @@ -241,6 +244,8 @@ export default { initialize, writeConfig, writeConfigFile, + generateSecureRandomAsBase64, + generateSecureRandom, checkStatus, subscribeState, decodeState, diff --git a/src/state/LndMobileInjectionFake.ts b/src/state/LndMobileInjectionFake.ts index 44b21e0e7..2d7e1e8d3 100644 --- a/src/state/LndMobileInjectionFake.ts +++ b/src/state/LndMobileInjectionFake.ts @@ -31,6 +31,8 @@ import { subscribeState, writeConfig, writeConfigFile, + generateSecureRandomAsBase64, + generateSecureRandom, } from "../lndmobile/fake/index"; import { WorkInfo, checkScheduledSyncWorkStatus } from "../lndmobile/fake/scheduled-sync"; // TODO(hsjoberg): This could be its own injection "LndMobileScheduledSync" import { @@ -78,6 +80,8 @@ export interface ILndMobileInjections { initialize: () => Promise<{ data: string } | number>; writeConfig: (config: string) => Promise; writeConfigFile: () => Promise; + generateSecureRandomAsBase64: (length: number) => Promise; + generateSecureRandom: (length: number) => Promise; subscribeState: () => Promise; decodeState: (data: string) => lnrpc.SubscribeStateResponse; checkStatus: () => Promise; @@ -212,6 +216,8 @@ export default { initialize, writeConfig, writeConfigFile, + generateSecureRandomAsBase64, + generateSecureRandom, subscribeState, decodeState, checkStatus, diff --git a/src/state/index.ts b/src/state/index.ts index e91cfa4ff..3fbab3623 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -72,7 +72,6 @@ import SetupBlixtDemo from "../utils/setup-demo"; import { appMigration } from "../migration/app-migration"; import { checkLndStreamErrorResponse } from "../utils/lndmobile"; import { clearTransactions } from "../storage/database/transaction"; -import { generateSecureRandom } from "react-native-securerandom"; import { lnrpc } from "../../proto/lightning"; import logger from "./../utils/log"; import { toast } from "../utils"; @@ -115,7 +114,7 @@ export interface IStoreModel { generateSeed: Thunk; writeConfig: Thunk; unlockWallet: Thunk; - createWallet: Thunk; + createWallet: Thunk; changeOnboardingState: Thunk; db?: SQLiteDatabase; @@ -641,13 +640,13 @@ routerrpc.estimator=${lndPathfindingAlgorithm} createWallet: thunk(async (actions, payload, { injections, getState, dispatch }) => { const initWallet = injections.lndMobile.wallet.initWallet; + const generateSecureRandomAsBase64 = injections.lndMobile.index.generateSecureRandomAsBase64; const seed = getState().walletSeed; if (!seed) { return; } - let random = await generateSecureRandom(32); + const randomBase64 = await generateSecureRandomAsBase64(32); - const randomBase64 = base64.fromByteArray(random); await setItem(StorageItem.walletPassword, randomBase64); await setWalletPassword(randomBase64); diff --git a/src/windows/InitProcess/DEV_Commands.tsx b/src/windows/InitProcess/DEV_Commands.tsx index 8e9875b4a..3ed63670f 100644 --- a/src/windows/InitProcess/DEV_Commands.tsx +++ b/src/windows/InitProcess/DEV_Commands.tsx @@ -29,6 +29,7 @@ import { checkStatus, connectPeer, decodePayReq, + generateSecureRandomAsBase64, getInfo, getNetworkInfo, getNodeInfo, @@ -67,7 +68,7 @@ import { RootStackParamList } from "../../Main"; import { StackNavigationProp } from "@react-navigation/stack"; import { abandonChannel } from "../../lndmobile/channel"; import { blixtTheme } from "../../native-base-theme/variables/commonColor"; -import { generateSecureRandom } from "react-native-securerandom"; +import { generateSecureRandom } from "../../lndmobile/index"; import { localNotification } from "../../utils/push-notification"; import { sendCommand } from "../../lndmobile/utils"; @@ -306,6 +307,14 @@ export default function DEV_Commands({ navigation, continueCallback }: IProps) { > generateSecureRandom +