mirror of
https://github.com/aljazceru/mutiny-web.git
synced 2025-12-19 07:14:22 +01:00
encrypt / decrypt
This commit is contained in:
@@ -6,7 +6,7 @@ import { A } from "solid-start";
|
||||
import { OnboardWarning } from "~/components/OnboardWarning";
|
||||
import { CombinedActivity } from "./Activity";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { Match, Show, Switch, createMemo } from "solid-js";
|
||||
import { Match, Show, Switch } from "solid-js";
|
||||
import { ExternalLink } from "./layout/ExternalLink";
|
||||
import { BetaWarningModal } from "~/components/BetaWarningModal";
|
||||
import settings from "~/assets/icons/settings.svg";
|
||||
@@ -14,6 +14,7 @@ import pixelLogo from "~/assets/mutiny-pixel-logo.png";
|
||||
import plusLogo from "~/assets/mutiny-plus-logo.png";
|
||||
import { PendingNwc } from "./PendingNwc";
|
||||
import { useI18n } from "~/i18n/context";
|
||||
import { DecryptDialog } from "./DecryptDialog";
|
||||
|
||||
export default function App() {
|
||||
const [state, _actions] = useMegaStore();
|
||||
@@ -96,6 +97,7 @@ export default function App() {
|
||||
</span>
|
||||
</p>
|
||||
</DefaultMain>
|
||||
<DecryptDialog />
|
||||
<BetaWarningModal />
|
||||
<NavBar activeTab="home" />
|
||||
</SafeArea>
|
||||
|
||||
74
src/components/DecryptDialog.tsx
Normal file
74
src/components/DecryptDialog.tsx
Normal file
@@ -0,0 +1,74 @@
|
||||
import { Show, createSignal } from "solid-js";
|
||||
import { Button, SimpleDialog } from "~/components/layout";
|
||||
import { TextField } from "~/components/layout/TextField";
|
||||
import { InfoBox } from "~/components/InfoBox";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import eify from "~/utils/eify";
|
||||
import { A } from "solid-start";
|
||||
|
||||
export function DecryptDialog() {
|
||||
const [state, actions] = useMegaStore();
|
||||
|
||||
const [password, setPassword] = createSignal("");
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
const [error, setError] = createSignal("");
|
||||
|
||||
async function decrypt(e: Event) {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
try {
|
||||
await actions.setupMutinyWallet(undefined, password());
|
||||
|
||||
// If we get this far and the state stills wants a password that means the password was wrong
|
||||
if (state.needs_password) {
|
||||
throw new Error("wrong");
|
||||
}
|
||||
} catch (e) {
|
||||
const err = eify(e);
|
||||
console.error(e);
|
||||
if (err.message === "wrong") {
|
||||
setError("Invalid password");
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function noop() {
|
||||
// noop
|
||||
}
|
||||
|
||||
return (
|
||||
<SimpleDialog
|
||||
title="Enter your password"
|
||||
// Only show the dialog if we need a password and there's no setup error
|
||||
open={state.needs_password && !state.setup_error}
|
||||
>
|
||||
<form onSubmit={decrypt}>
|
||||
<div class="flex flex-col gap-4">
|
||||
<TextField
|
||||
name="password"
|
||||
type="password"
|
||||
ref={noop}
|
||||
value={password()}
|
||||
onInput={(e) => setPassword(e.currentTarget.value)}
|
||||
error={""}
|
||||
onBlur={noop}
|
||||
onChange={noop}
|
||||
/>
|
||||
<Show when={error()}>
|
||||
<InfoBox accent="red">{error()}</InfoBox>
|
||||
</Show>
|
||||
<Button intent="blue" loading={loading()} onClick={decrypt}>
|
||||
Decrypt Wallet
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<A class="self-end text-m-grey-400" href="/settings/restore">
|
||||
Forgot Password?
|
||||
</A>
|
||||
</SimpleDialog>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +1,64 @@
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { Button, InnerCard, NiceP, VStack } from "~/components/layout";
|
||||
import { createSignal } from "solid-js";
|
||||
import {
|
||||
Button,
|
||||
InnerCard,
|
||||
NiceP,
|
||||
SimpleDialog,
|
||||
VStack
|
||||
} from "~/components/layout";
|
||||
import { Show, createSignal } from "solid-js";
|
||||
import eify from "~/utils/eify";
|
||||
import { showToast } from "./Toaster";
|
||||
import { downloadTextFile } from "~/utils/download";
|
||||
import { createFileUploader } from "@solid-primitives/upload";
|
||||
import { ConfirmDialog } from "./Dialog";
|
||||
import initMutinyWallet, { MutinyWallet } from "@mutinywallet/mutiny-wasm";
|
||||
import { InfoBox } from "./InfoBox";
|
||||
import { TextField } from "./layout/TextField";
|
||||
|
||||
export function ImportExport(props: { emergency?: boolean }) {
|
||||
const [state, _] = useMegaStore();
|
||||
|
||||
const [error, setError] = createSignal<Error>();
|
||||
const [exportDecrypt, setExportDecrypt] = createSignal(false);
|
||||
const [password, setPassword] = createSignal("");
|
||||
|
||||
async function handleSave() {
|
||||
try {
|
||||
setError(undefined);
|
||||
const json = await MutinyWallet.export_json();
|
||||
downloadTextFile(json || "", "mutiny-state.json");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
const err = eify(e);
|
||||
if (err.message === "Incorrect password entered.") {
|
||||
setExportDecrypt(true);
|
||||
} else {
|
||||
setError(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function savePassword(e: Event) {
|
||||
e.preventDefault();
|
||||
try {
|
||||
setError(undefined);
|
||||
if (!password()) {
|
||||
throw new Error("Password is required");
|
||||
}
|
||||
const json = await MutinyWallet.export_json(password());
|
||||
downloadTextFile(json || "", "mutiny-state.json");
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setError(eify(e));
|
||||
} finally {
|
||||
setExportDecrypt(false);
|
||||
setPassword("");
|
||||
}
|
||||
}
|
||||
|
||||
function noop() {
|
||||
// noop
|
||||
}
|
||||
|
||||
const { files, selectFiles } = createFileUploader();
|
||||
@@ -23,6 +68,7 @@ export function ImportExport(props: { emergency?: boolean }) {
|
||||
const fileReader = new FileReader();
|
||||
|
||||
try {
|
||||
setError(undefined);
|
||||
const file: File = files()[0].file;
|
||||
|
||||
const text = await new Promise<string | null>((resolve, reject) => {
|
||||
@@ -45,6 +91,7 @@ export function ImportExport(props: { emergency?: boolean }) {
|
||||
await state.mutiny_wallet.stop();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setError(eify(e));
|
||||
}
|
||||
} else {
|
||||
// If there's no mutiny wallet loaded we need to initialize WASM
|
||||
@@ -96,6 +143,9 @@ export function ImportExport(props: { emergency?: boolean }) {
|
||||
to make sure you don't create conflicts.
|
||||
</NiceP>
|
||||
<div />
|
||||
<Show when={error()}>
|
||||
<InfoBox accent="red">{error()?.message}</InfoBox>
|
||||
</Show>
|
||||
<VStack>
|
||||
<Button onClick={handleSave}>Save State As File</Button>
|
||||
<Button onClick={uploadFile}>Import State From File</Button>
|
||||
@@ -109,6 +159,32 @@ export function ImportExport(props: { emergency?: boolean }) {
|
||||
>
|
||||
Do you want to replace your state with {files()[0].name}?
|
||||
</ConfirmDialog>
|
||||
{/* TODO: this is pretty redundant with the DecryptDialog, could make a shared component */}
|
||||
<SimpleDialog
|
||||
title="Enter your password to decrypt"
|
||||
open={exportDecrypt()}
|
||||
>
|
||||
<form onSubmit={savePassword}>
|
||||
<div class="flex flex-col gap-4">
|
||||
<TextField
|
||||
name="password"
|
||||
type="password"
|
||||
ref={noop}
|
||||
value={password()}
|
||||
onInput={(e) => setPassword(e.currentTarget.value)}
|
||||
error={""}
|
||||
onBlur={noop}
|
||||
onChange={noop}
|
||||
/>
|
||||
<Show when={error()}>
|
||||
<InfoBox accent="red">{error()?.message}</InfoBox>
|
||||
</Show>
|
||||
<Button intent="blue" onClick={savePassword}>
|
||||
Decrypt Wallet
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</SimpleDialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,9 @@ export function TextField(props: TextFieldProps) {
|
||||
class="w-full p-2 rounded-lg bg-white/10 placeholder-neutral-400"
|
||||
/>
|
||||
</Show>
|
||||
<KTextField.ErrorMessage>{props.error}</KTextField.ErrorMessage>
|
||||
<KTextField.ErrorMessage class="text-m-red">
|
||||
{props.error}
|
||||
</KTextField.ErrorMessage>
|
||||
<Show when={props.caption}>
|
||||
<TinyText>{props.caption}</TinyText>
|
||||
</Show>
|
||||
|
||||
@@ -18,6 +18,7 @@ import { generateGradient } from "~/utils/gradientHash";
|
||||
import close from "~/assets/icons/close.svg";
|
||||
import { A } from "solid-start";
|
||||
import down from "~/assets/icons/down.svg";
|
||||
import { DecryptDialog } from "../DecryptDialog";
|
||||
|
||||
export { Button, ButtonLink, Linkify };
|
||||
|
||||
@@ -110,7 +111,6 @@ export const Collapser: ParentComponent<{
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const SafeArea: ParentComponent = (props) => {
|
||||
return (
|
||||
<div class="h-[100dvh] safe-left safe-right">
|
||||
@@ -161,6 +161,7 @@ export const MutinyWalletGuard: ParentComponent = (props) => {
|
||||
<Show when={state.mutiny_wallet && !state.wallet_loading}>
|
||||
{props.children}
|
||||
</Show>
|
||||
<DecryptDialog />
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
@@ -318,7 +319,7 @@ export function ModalCloseButton() {
|
||||
);
|
||||
}
|
||||
|
||||
export const SIMPLE_OVERLAY = "fixed inset-0 z-50 bg-black/70 backdrop-blur-md";
|
||||
export const SIMPLE_OVERLAY = "fixed inset-0 z-50 bg-black/20 backdrop-blur-md";
|
||||
export const SIMPLE_DIALOG_POSITIONER =
|
||||
"fixed inset-0 z-50 flex items-center justify-center";
|
||||
export const SIMPLE_DIALOG_CONTENT =
|
||||
@@ -327,10 +328,13 @@ export const SIMPLE_DIALOG_CONTENT =
|
||||
export const SimpleDialog: ParentComponent<{
|
||||
title: string;
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
setOpen?: (open: boolean) => void;
|
||||
}> = (props) => {
|
||||
return (
|
||||
<Dialog.Root open={props.open} onOpenChange={props.setOpen}>
|
||||
<Dialog.Root
|
||||
open={props.open}
|
||||
onOpenChange={props.setOpen && props.setOpen}
|
||||
>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay class={SIMPLE_OVERLAY} />
|
||||
<div class={SIMPLE_DIALOG_POSITIONER}>
|
||||
@@ -339,9 +343,11 @@ export const SimpleDialog: ParentComponent<{
|
||||
<Dialog.Title>
|
||||
<SmallHeader>{props.title}</SmallHeader>
|
||||
</Dialog.Title>
|
||||
<Show when={props.setOpen}>
|
||||
<Dialog.CloseButton>
|
||||
<ModalCloseButton />
|
||||
</Dialog.CloseButton>
|
||||
</Show>
|
||||
</div>
|
||||
<Dialog.Description class="flex flex-col gap-4">
|
||||
{props.children}
|
||||
|
||||
@@ -106,7 +106,8 @@ export async function checkForWasm() {
|
||||
}
|
||||
|
||||
export async function setupMutinyWallet(
|
||||
settings?: MutinyWalletSettingStrings
|
||||
settings?: MutinyWalletSettingStrings,
|
||||
password?: string
|
||||
): Promise<MutinyWallet> {
|
||||
// Ultimate defense against getting multiple instances of the wallet running.
|
||||
// If we detect that the wallet has already been initialized in this session, we'll reload the page.
|
||||
@@ -138,7 +139,7 @@ export async function setupMutinyWallet(
|
||||
console.log("Using subscriptions address", subscriptions);
|
||||
const mutinyWallet = await new MutinyWallet(
|
||||
// Password
|
||||
"",
|
||||
password ? password : undefined,
|
||||
// Mnemonic
|
||||
undefined,
|
||||
proxy,
|
||||
|
||||
@@ -55,10 +55,13 @@ export default function Backup() {
|
||||
|
||||
const [hasSeenBackup, setHasSeenBackup] = createSignal(false);
|
||||
const [hasCheckedAll, setHasCheckedAll] = createSignal(false);
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
|
||||
function wroteDownTheWords() {
|
||||
setLoading(true);
|
||||
actions.setHasBackedUp();
|
||||
navigate("/");
|
||||
navigate("/settings/encrypt");
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -93,6 +96,7 @@ export default function Backup() {
|
||||
disabled={!hasSeenBackup() || !hasCheckedAll()}
|
||||
intent="blue"
|
||||
onClick={wroteDownTheWords}
|
||||
loading={loading()}
|
||||
>
|
||||
I wrote down the words
|
||||
</Button>
|
||||
|
||||
140
src/routes/settings/Encrypt.tsx
Normal file
140
src/routes/settings/Encrypt.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
import {
|
||||
Button,
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
NiceP,
|
||||
MutinyWalletGuard,
|
||||
SafeArea,
|
||||
VStack,
|
||||
ButtonLink
|
||||
} from "~/components/layout";
|
||||
import NavBar from "~/components/NavBar";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
import { Show, createSignal } from "solid-js";
|
||||
import { BackLink } from "~/components/layout/BackLink";
|
||||
import { createForm } from "@modular-forms/solid";
|
||||
import { TextField } from "~/components/layout/TextField";
|
||||
import { timeout } from "~/utils/timeout";
|
||||
import eify from "~/utils/eify";
|
||||
import { InfoBox } from "~/components/InfoBox";
|
||||
|
||||
type EncryptPasswordForm = {
|
||||
existingPassword: string;
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
};
|
||||
|
||||
export default function Encrypt() {
|
||||
const [store, _actions] = useMegaStore();
|
||||
const [error, setError] = createSignal<Error>();
|
||||
const [loading, setLoading] = createSignal(false);
|
||||
|
||||
const [_encryptPasswordForm, { Form, Field }] =
|
||||
createForm<EncryptPasswordForm>({
|
||||
initialValues: {
|
||||
existingPassword: "",
|
||||
password: "",
|
||||
confirmPassword: ""
|
||||
},
|
||||
validate: (values) => {
|
||||
const errors: Record<string, string> = {};
|
||||
if (values.password !== values.confirmPassword) {
|
||||
errors.confirmPassword = "Passwords do not match";
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
});
|
||||
|
||||
const handleFormSubmit = async (f: EncryptPasswordForm) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await store.mutiny_wallet?.change_password(
|
||||
f.existingPassword === "" ? undefined : f.existingPassword,
|
||||
f.password === "" ? undefined : f.password
|
||||
);
|
||||
|
||||
await timeout(1000);
|
||||
window.location.href = "/";
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
setError(eify(e));
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink href="/settings" title="Settings" />
|
||||
<LargeHeader>
|
||||
Encrypt your seed words (optional)
|
||||
</LargeHeader>
|
||||
<VStack>
|
||||
<NiceP>
|
||||
Mutiny is a "hot wallet" so it needs your seed word
|
||||
to operate, but you can optionally encrypt those
|
||||
words with a password.
|
||||
</NiceP>
|
||||
<NiceP>
|
||||
That way, if someone gets access to your browser,
|
||||
they still won't have access to your funds.
|
||||
</NiceP>
|
||||
<Form onSubmit={handleFormSubmit}>
|
||||
<VStack>
|
||||
<Field name="existingPassword">
|
||||
{(field, props) => (
|
||||
<TextField
|
||||
{...props}
|
||||
{...field}
|
||||
type="password"
|
||||
label="Existing Password (optional)"
|
||||
placeholder="Existing password"
|
||||
caption="Leave blank if you haven't set a password yet."
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
<Field name="password">
|
||||
{(field, props) => (
|
||||
<TextField
|
||||
{...props}
|
||||
{...field}
|
||||
type="password"
|
||||
label="Password"
|
||||
placeholder="Enter a password"
|
||||
caption="This password will be used to encrypt your seed words. If you forget it, you will need to re-enter your seed words to access your funds. You did write down your seed words, right?"
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
<Field name="confirmPassword">
|
||||
{(field, props) => (
|
||||
<TextField
|
||||
{...props}
|
||||
{...field}
|
||||
type="password"
|
||||
label="Confirm Password"
|
||||
placeholder="Enter the same password"
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
<Show when={error()}>
|
||||
<InfoBox accent="red">
|
||||
{error()?.message}
|
||||
</InfoBox>
|
||||
</Show>
|
||||
<div />
|
||||
<Button intent="blue" loading={loading()}>
|
||||
Encrypt
|
||||
</Button>
|
||||
</VStack>
|
||||
</Form>
|
||||
<ButtonLink href="/settings" intent="green">
|
||||
Skip
|
||||
</ButtonLink>
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
Button,
|
||||
DefaultMain,
|
||||
LargeHeader,
|
||||
MutinyWalletGuard,
|
||||
NiceP,
|
||||
SafeArea,
|
||||
VStack
|
||||
@@ -235,30 +234,28 @@ function TwelveWordsEntry() {
|
||||
|
||||
export default function RestorePage() {
|
||||
return (
|
||||
<MutinyWalletGuard>
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
<BackLink title="Settings" href="/settings" />
|
||||
<LargeHeader>Restore</LargeHeader>
|
||||
<VStack>
|
||||
<NiceP>
|
||||
You can restore an existing Mutiny Wallet from your
|
||||
12 word seed phrase. This will replace your existing
|
||||
You can restore an existing Mutiny Wallet from your 12
|
||||
word seed phrase. This will replace your existing
|
||||
wallet, so make sure you know what you're doing!
|
||||
</NiceP>
|
||||
<NiceP>
|
||||
<strong class="font-bold text-m-red">
|
||||
Beta warning:
|
||||
</strong>{" "}
|
||||
you can currently only restore on-chain funds.
|
||||
Lightning backup restore is coming soon.
|
||||
you can currently only restore on-chain funds. Lightning
|
||||
backup restore is coming soon.
|
||||
</NiceP>
|
||||
<TwelveWordsEntry />
|
||||
</VStack>
|
||||
</DefaultMain>
|
||||
<NavBar activeTab="settings" />
|
||||
</SafeArea>
|
||||
</MutinyWalletGuard>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import NavBar from "~/components/NavBar";
|
||||
import { A } from "solid-start";
|
||||
import { For, Show } from "solid-js";
|
||||
import forward from "~/assets/icons/forward.svg";
|
||||
import { useMegaStore } from "~/state/megaStore";
|
||||
|
||||
function SettingsLinkList(props: {
|
||||
header: string;
|
||||
@@ -18,6 +19,7 @@ function SettingsLinkList(props: {
|
||||
text: string;
|
||||
caption?: string;
|
||||
accent?: "red" | "green";
|
||||
disabled?: boolean;
|
||||
}[];
|
||||
}) {
|
||||
return (
|
||||
@@ -26,7 +28,11 @@ function SettingsLinkList(props: {
|
||||
{(link) => (
|
||||
<A
|
||||
href={link.href}
|
||||
class="no-underline flex w-full flex-col gap-1 py-2 hover:bg-m-grey-750 active:bg-m-grey-900 px-4 "
|
||||
class="no-underline flex w-full flex-col gap-1 py-2 hover:bg-m-grey-750 active:bg-m-grey-900 px-4"
|
||||
classList={{
|
||||
"opacity-50 cursor pointer-events-none grayscale":
|
||||
link.disabled
|
||||
}}
|
||||
>
|
||||
<div class="flex justify-between">
|
||||
<span
|
||||
@@ -52,6 +58,8 @@ function SettingsLinkList(props: {
|
||||
}
|
||||
|
||||
export default function Settings() {
|
||||
const [state, _actions] = useMegaStore();
|
||||
|
||||
return (
|
||||
<SafeArea>
|
||||
<DefaultMain>
|
||||
@@ -84,6 +92,14 @@ export default function Settings() {
|
||||
text: "Restore",
|
||||
accent: "red"
|
||||
},
|
||||
{
|
||||
href: "/settings/encrypt",
|
||||
text: "Change Password",
|
||||
disabled: !state.has_backed_up,
|
||||
caption: !state.has_backed_up
|
||||
? "Backup first to unlock encryption"
|
||||
: undefined
|
||||
},
|
||||
{
|
||||
href: "/settings/servers",
|
||||
text: "Servers",
|
||||
|
||||
@@ -47,10 +47,14 @@ export type MegaStore = [
|
||||
existing_tab_detected: boolean;
|
||||
subscription_timestamp?: number;
|
||||
readonly mutiny_plus: boolean;
|
||||
needs_password: boolean;
|
||||
},
|
||||
{
|
||||
fetchUserStatus(): Promise<UserStatus>;
|
||||
setupMutinyWallet(settings?: MutinyWalletSettingStrings): Promise<void>;
|
||||
setupMutinyWallet(
|
||||
settings?: MutinyWalletSettingStrings,
|
||||
password?: string
|
||||
): Promise<void>;
|
||||
deleteMutinyWallet(): Promise<void>;
|
||||
setWaitlistId(waitlist_id: string): void;
|
||||
setScanResult(scan_result: ParsedParams | undefined): void;
|
||||
@@ -95,7 +99,8 @@ export const Provider: ParentComponent = (props) => {
|
||||
if (state.subscription_timestamp < Math.ceil(Date.now() / 1000))
|
||||
return false;
|
||||
else return true;
|
||||
}
|
||||
},
|
||||
needs_password: false
|
||||
});
|
||||
|
||||
const actions = {
|
||||
@@ -161,17 +166,24 @@ export const Provider: ParentComponent = (props) => {
|
||||
}
|
||||
},
|
||||
async setupMutinyWallet(
|
||||
settings?: MutinyWalletSettingStrings
|
||||
settings?: MutinyWalletSettingStrings,
|
||||
password?: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
// If we're already in an error state there should be no reason to continue
|
||||
if (state.setup_error) {
|
||||
throw state.setup_error;
|
||||
}
|
||||
|
||||
setState({ wallet_loading: true });
|
||||
|
||||
// This is where all the real setup happens
|
||||
const mutinyWallet = await setupMutinyWallet(settings);
|
||||
const mutinyWallet = await setupMutinyWallet(
|
||||
settings,
|
||||
password
|
||||
);
|
||||
|
||||
// If we get this far then we don't need the password anymore
|
||||
setState({ needs_password: false });
|
||||
|
||||
// Get balance optimistically
|
||||
const balance = await mutinyWallet.get_balance();
|
||||
@@ -210,8 +222,12 @@ export const Provider: ParentComponent = (props) => {
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (eify(e).message === "Incorrect password entered.") {
|
||||
setState({ needs_password: true });
|
||||
} else {
|
||||
setState({ setup_error: eify(e) });
|
||||
}
|
||||
}
|
||||
},
|
||||
async deleteMutinyWallet(): Promise<void> {
|
||||
try {
|
||||
@@ -315,13 +331,10 @@ export const Provider: ParentComponent = (props) => {
|
||||
});
|
||||
} else {
|
||||
console.log("running setup node manager...");
|
||||
|
||||
actions
|
||||
.setupMutinyWallet()
|
||||
.then(() => console.log("node manager setup done"))
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
setState({ setup_error: eify(e) });
|
||||
});
|
||||
.then(() => console.log("node manager setup done"));
|
||||
|
||||
// Setup an event listener to stop the mutiny wallet when the page unloads
|
||||
window.onunload = async (_e) => {
|
||||
|
||||
@@ -57,7 +57,9 @@ export default defineConfig({
|
||||
"nostr-tools",
|
||||
"class-variance-authority",
|
||||
"@kobalte/core",
|
||||
"@solid-primitives/upload"
|
||||
"@solid-primitives/upload",
|
||||
"i18next",
|
||||
"i18next-browser-languagedetector"
|
||||
],
|
||||
// This is necessary because otherwise `vite dev` can't find the wasm
|
||||
exclude: ["@mutinywallet/mutiny-wasm", "@mutinywallet/waila-wasm"]
|
||||
|
||||
Reference in New Issue
Block a user