wallet-core/packages/exchange-backoffice-ui/src/pages/Officer.tsx

266 lines
7.2 KiB
TypeScript
Raw Normal View History

2023-05-19 18:26:47 +02:00
import { TranslatedString } from "@gnu-taler/taler-util";
import {
notifyError,
notifyInfo,
useLocalStorage,
useMemoryStorage,
} from "@gnu-taler/web-util/browser";
import { VNode, h } from "preact";
2023-05-19 01:32:20 +02:00
import { useEffect, useState } from "preact/hooks";
2023-05-19 18:26:47 +02:00
import {
UnwrapKeyError,
createNewAccount,
createNewSessionId,
unlockAccount,
} from "../account.js";
import { createNewForm } from "../handlers/forms.js";
2023-05-19 01:32:20 +02:00
export function Officer() {
2023-05-19 18:26:47 +02:00
const password = useMemoryStorage("password");
const session = useLocalStorage("session");
const officer = useLocalStorage("officer");
const [keys, setKeys] = useState({ accountId: "", pub: "" });
2023-05-19 01:32:20 +02:00
useEffect(() => {
2023-05-19 18:26:47 +02:00
if (
officer.value === undefined ||
session.value === undefined ||
password.value === undefined
) {
return;
}
unlockAccount(session.value, officer.value, password.value)
.then((keys) => setKeys(keys ?? { accountId: "", pub: "" }))
.catch((e) => {
if (e instanceof UnwrapKeyError) {
console.log(e);
}
});
}, [officer.value, session.value, password.value]);
useEffect(() => {
if (!session.value) {
session.update(createNewSessionId());
}
2023-05-19 01:32:20 +02:00
}, []);
2023-05-19 18:26:47 +02:00
const { value: sessionId } = session;
if (!sessionId) {
return <div>loading...</div>;
}
if (officer.value === undefined) {
return (
<CreateAccount
sessionId={sessionId}
onNewAccount={(id) => {
password.reset();
officer.update(id);
}}
/>
);
}
console.log("pwd", password.value);
if (password.value === undefined) {
return (
<UnlockAccount
sessionId={sessionId}
accountId={officer.value}
onAccountUnlocked={(pwd) => {
password.update(pwd);
}}
/>
);
}
2023-05-19 01:32:20 +02:00
return (
<div>
<div>Officer</div>
2023-05-19 18:26:47 +02:00
<h1>{sessionId}</h1>
2023-05-19 01:32:20 +02:00
<h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 ">
Public key
</h1>
<div>
2023-05-19 18:26:47 +02:00
<p class="mt-6 leading-8 text-gray-700 break-all">
-----BEGIN PUBLIC KEY-----
<div>{keys.pub}</div>
-----END PUBLIC KEY-----
</p>
2023-05-19 01:32:20 +02:00
</div>
<h1 class="my-2 text-3xl font-bold tracking-tight text-gray-900 ">
Private key
</h1>
<div>
2023-05-19 18:26:47 +02:00
<p class="mt-6 leading-8 text-gray-700 break-all">
-----BEGIN PRIVATE KEY-----
<div>{keys.accountId}</div>
-----END PRIVATE KEY-----
</p>
2023-05-19 01:32:20 +02:00
</div>
</div>
);
}
2023-05-19 18:26:47 +02:00
function CreateAccount({
sessionId,
onNewAccount,
}: {
sessionId: string;
onNewAccount: (accountId: string) => void;
}): VNode {
const Form = createNewForm<{
email: string;
password: string;
}>();
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
return (
<div class="flex min-h-full flex-col ">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
Create account
</h2>
</div>
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] ">
<div class="bg-gray-100 px-6 py-6 shadow sm:rounded-lg sm:px-12">
<Form.Provider
onSubmit={async (v) => {
const keys = await createNewAccount(sessionId, v.password);
onNewAccount(keys.accountId);
}}
>
<div class="mb-4">
<Form.InputLine
label={"Email" as TranslatedString}
name="email"
type="email"
required
/>
</div>
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
<div class="mb-4">
<Form.InputLine
label={"Password" as TranslatedString}
name="password"
type="password"
required
/>
</div>
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
<div class="mt-8">
<button
type="submit"
class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Create
</button>
</div>
</Form.Provider>
</div>
</div>
</div>
);
}
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
function UnlockAccount({
sessionId,
accountId,
onAccountUnlocked,
}: {
sessionId: string;
accountId: string;
onAccountUnlocked: (password: string) => void;
}): VNode {
const Form = createNewForm<{
sessionId: string;
accountId: string;
password: string;
}>();
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
return (
<div class="flex min-h-full flex-col ">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h2 class="mt-6 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
Unlock account
</h2>
</div>
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-[480px] ">
<div class="bg-gray-100 px-6 py-6 shadow sm:rounded-lg sm:px-12">
<Form.Provider
initialValue={{
sessionId,
accountId:
accountId.substring(0, 6) +
"..." +
accountId.substring(accountId.length - 6),
}}
computeFormState={(v) => {
return {
accountId: {
disabled: true,
},
sessionId: {
disabled: true,
},
};
}}
onSubmit={async (v) => {
try {
// test login
await unlockAccount(sessionId, accountId, v.password);
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
onAccountUnlocked(v.password ?? "");
notifyInfo("Account unlocked" as TranslatedString);
} catch (e) {
if (e instanceof UnwrapKeyError) {
notifyError(
"Could not unlock account" as any,
e.message as any,
);
} else {
throw e;
}
}
}}
>
<div class="mb-4">
<Form.InputLine
label={"Session" as TranslatedString}
name="sessionId"
type="text"
/>
</div>
<div class="mb-4">
<Form.InputLine
label={"AccountId" as TranslatedString}
name="accountId"
type="text"
/>
</div>
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
<div class="mb-4">
<Form.InputLine
label={"Password" as TranslatedString}
name="password"
type="password"
required
/>
</div>
2023-05-19 01:32:20 +02:00
2023-05-19 18:26:47 +02:00
<div class="mt-8">
<button
type="submit"
class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Unlock
</button>
</div>
</Form.Provider>
</div>
</div>
</div>
);
2023-05-19 01:32:20 +02:00
}