From d54147b838d78c0985e439d5af739bd2c7ef9c61 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Wed, 17 Jan 2024 10:29:57 +0000 Subject: [PATCH] Use secure storage for overriding nsec --- android/app/capacitor.build.gradle | 1 + android/capacitor.settings.gradle | 3 ++ ios/App/Podfile | 1 + package.json | 1 + pnpm-lock.yaml | 11 ++++++ src/logic/mutinyWalletSetup.ts | 16 +++++++- src/routes/settings/SyncNostrContacts.tsx | 48 +++++++++++++++++++++-- 7 files changed, 76 insertions(+), 5 deletions(-) diff --git a/android/app/capacitor.build.gradle b/android/app/capacitor.build.gradle index c909025a..f68271e8 100644 --- a/android/app/capacitor.build.gradle +++ b/android/app/capacitor.build.gradle @@ -18,6 +18,7 @@ dependencies { implementation project(':capacitor-share') implementation project(':capacitor-status-bar') implementation project(':capacitor-toast') + implementation project(':capacitor-secure-storage-plugin') } diff --git a/android/capacitor.settings.gradle b/android/capacitor.settings.gradle index 8a2fdb13..e770f7af 100644 --- a/android/capacitor.settings.gradle +++ b/android/capacitor.settings.gradle @@ -28,3 +28,6 @@ project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@c include ':capacitor-toast' project(':capacitor-toast').projectDir = new File('../node_modules/.pnpm/@capacitor+toast@5.0.6_@capacitor+core@5.5.1/node_modules/@capacitor/toast/android') + +include ':capacitor-secure-storage-plugin' +project(':capacitor-secure-storage-plugin').projectDir = new File('../node_modules/.pnpm/capacitor-secure-storage-plugin@0.9.0_@capacitor+core@5.5.1/node_modules/capacitor-secure-storage-plugin/android') diff --git a/ios/App/Podfile b/ios/App/Podfile index b866717b..99f2ff5c 100644 --- a/ios/App/Podfile +++ b/ios/App/Podfile @@ -20,6 +20,7 @@ def capacitor_pods pod 'CapacitorShare', :path => '../../node_modules/.pnpm/@capacitor+share@5.0.6_@capacitor+core@5.5.1/node_modules/@capacitor/share' pod 'CapacitorStatusBar', :path => '../../node_modules/.pnpm/@capacitor+status-bar@5.0.6_@capacitor+core@5.5.1/node_modules/@capacitor/status-bar' pod 'CapacitorToast', :path => '../../node_modules/.pnpm/@capacitor+toast@5.0.6_@capacitor+core@5.5.1/node_modules/@capacitor/toast' + pod 'CapacitorSecureStoragePlugin', :path => '../../node_modules/.pnpm/capacitor-secure-storage-plugin@0.9.0_@capacitor+core@5.5.1/node_modules/capacitor-secure-storage-plugin' end target 'App' do diff --git a/package.json b/package.json index b5c1c96c..f83a724f 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "@solid-primitives/upload": "^0.0.111", "@solidjs/meta": "^0.29.1", "@solidjs/router": "^0.9.0", + "capacitor-secure-storage-plugin": "^0.9.0", "i18next": "^22.5.1", "i18next-browser-languagedetector": "^7.1.0", "qr-scanner": "^1.4.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18ba86b4..59775269 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,6 +68,9 @@ importers: '@solidjs/router': specifier: ^0.9.0 version: 0.9.0(solid-js@1.8.5) + capacitor-secure-storage-plugin: + specifier: ^0.9.0 + version: 0.9.0(@capacitor/core@5.5.1) i18next: specifier: ^22.5.1 version: 22.5.1 @@ -6320,6 +6323,14 @@ packages: /caniuse-lite@1.0.30001559: resolution: {integrity: sha512-cPiMKZgqgkg5LY3/ntGeLFUpi6tzddBNS58A4tnTgQw1zON7u2sZMU7SzOeVH4tj20++9ggL+V6FDOFMTaFFYA==} + /capacitor-secure-storage-plugin@0.9.0(@capacitor/core@5.5.1): + resolution: {integrity: sha512-P5fiC94opcLHu41vceo9weXH+20g0SPYKkeAx+qm9eKNcVFqpcuI4dqwivXlGXYNMDygyjSQuAaFwZ4gW0Y91Q==} + peerDependencies: + '@capacitor/core': ^5.0.0 + dependencies: + '@capacitor/core': 5.5.1 + dev: false + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} diff --git a/src/logic/mutinyWalletSetup.ts b/src/logic/mutinyWalletSetup.ts index 7ba1ba8c..c29039b0 100644 --- a/src/logic/mutinyWalletSetup.ts +++ b/src/logic/mutinyWalletSetup.ts @@ -1,6 +1,8 @@ /* @refresh reload */ +import { Capacitor } from "@capacitor/core"; import initMutinyWallet, { MutinyWallet } from "@mutinywallet/mutiny-wasm"; +import { SecureStoragePlugin } from "capacitor-secure-storage-plugin"; export type Network = "bitcoin" | "testnet" | "regtest" | "signet"; @@ -249,6 +251,17 @@ export async function setupMutinyWallet( scorer } = settings; + let nsec; + // get nsec from secure storage + if (Capacitor.isNativePlatform()) { + try { + const value = await SecureStoragePlugin.get({ key: "nsec" }); + nsec = value.value; + } catch (e) { + console.log("No nsec stored"); + } + } + console.log("Initializing Mutiny Manager"); console.log("Using network", network); console.log("Using proxy", proxy); @@ -290,7 +303,8 @@ export async function setupMutinyWallet( // Safe mode safeMode || undefined, // Skip hodl invoices? (defaults to true, so if shouldZapHodl is true that's when we pass false) - shouldZapHodl ? false : undefined + shouldZapHodl ? false : undefined, + nsec ); sessionStorage.setItem("MUTINY_WALLET_INITIALIZED", Date.now().toString()); diff --git a/src/routes/settings/SyncNostrContacts.tsx b/src/routes/settings/SyncNostrContacts.tsx index c5847f02..43470fed 100644 --- a/src/routes/settings/SyncNostrContacts.tsx +++ b/src/routes/settings/SyncNostrContacts.tsx @@ -1,5 +1,8 @@ +import { Capacitor } from "@capacitor/core"; import { createForm, required, SubmitHandler } from "@modular-forms/solid"; -import { createSignal, Match, Show, Switch } from "solid-js"; +import { MutinyWallet } from "@mutinywallet/mutiny-wasm"; +import { SecureStoragePlugin } from "capacitor-secure-storage-plugin"; +import { createResource, createSignal, Match, Show, Switch } from "solid-js"; import { BackPop, @@ -31,6 +34,8 @@ function SyncContactsForm() { const [state, actions] = useMegaStore(); const [error, setError] = createSignal(); + const allowNsec = Capacitor.isNativePlatform(); + const [feedbackForm, { Form, Field }] = createForm({ initialValues: { npub: "" @@ -41,7 +46,26 @@ function SyncContactsForm() { f: NostrContactsForm ) => { try { - const npub = f.npub.trim(); + const string = f.npub.trim(); + let npub = string; + + // if it is an nsec, save it into secure storage + if (string.startsWith("nsec")) { + if (!allowNsec) { + throw new Error( + "nsec not allowed in web version, please install the app" + ); + } + + // set in storage + SecureStoragePlugin.set({ key: "nsec", value: string }).then( + (success) => console.log(success) + ); + + // set npub and continue + npub = await MutinyWallet.nsec_to_npub(string); + } + if (!PRIMAL_API) throw new Error("PRIMAL_API not set"); await state.mutiny_wallet?.sync_nostr_contacts(PRIMAL_API, npub); actions.saveNpub(npub); @@ -68,7 +92,7 @@ function SyncContactsForm() { value={field.value} error={field.error} label={i18n.t("settings.nostr_contacts.npub_label")} - placeholder="npub..." + placeholder={allowNsec ? "npub/nsec..." : "npub..."} /> )} @@ -97,10 +121,26 @@ export function SyncNostrContacts() { const [loading, setLoading] = createSignal(false); const [error, setError] = createSignal(); - function clearNpub() { + async function clearNpub() { actions.saveNpub(""); + if (Capacitor.isNativePlatform()) { + await SecureStoragePlugin.remove({ key: "nsec" }); + } } + const [hasNsec] = createResource(async () => { + if (Capacitor.isNativePlatform()) { + try { + await SecureStoragePlugin.get({ key: "nsec" }); + return true; + } catch (_e) { + return false; + } + } else { + return false; + } + }); + async function resync() { setError(undefined); setLoading(true);