diff options
author | Sebastian <sebasjm@gmail.com> | 2024-04-26 14:31:48 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-04-26 14:31:48 -0300 |
commit | a1c5917e626856f2abd9dbe6ddaa71c1458334c6 (patch) | |
tree | d7456b0b27bda5b4b04b78384fd67d3d5f8db379 /packages/aml-backoffice-ui/src/hooks/officer.ts | |
parent | 6837a9dc6f677babe798bc94c0baa1f11c0edb55 (diff) | |
download | wallet-core-a1c5917e626856f2abd9dbe6ddaa71c1458334c6.tar.xz |
update code to match others
Diffstat (limited to 'packages/aml-backoffice-ui/src/hooks/officer.ts')
-rw-r--r-- | packages/aml-backoffice-ui/src/hooks/officer.ts | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/packages/aml-backoffice-ui/src/hooks/officer.ts b/packages/aml-backoffice-ui/src/hooks/officer.ts new file mode 100644 index 000000000..3ac4c857c --- /dev/null +++ b/packages/aml-backoffice-ui/src/hooks/officer.ts @@ -0,0 +1,159 @@ +/* + This file is part of GNU Taler + (C) 2022-2024 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { + AbsoluteTime, + Codec, + LockedAccount, + OfficerAccount, + OfficerId, + SigningKey, + buildCodecForObject, + codecForAbsoluteTime, + codecForString, + createNewOfficerAccount, + decodeCrock, + encodeCrock, + unlockOfficerAccount, +} from "@gnu-taler/taler-util"; +import { buildStorageKey, useExchangeApiContext, useLocalStorage } from "@gnu-taler/web-util/browser"; +import { useMemo } from "preact/hooks"; +import { usePreferences } from "./preferences.js"; + +export interface Officer { + account: LockedAccount; + when: AbsoluteTime; +} + +const codecForLockedAccount = codecForString() as Codec<LockedAccount>; + +type OfficerAccountString = { + id: string; + strKey: string; +}; + +export const codecForOfficerAccount = (): Codec<OfficerAccountString> => + buildCodecForObject<OfficerAccountString>() + .property("id", codecForString()) // FIXME + .property("strKey", codecForString()) // FIXME + .build("OfficerAccount"); + +export const codecForOfficer = (): Codec<Officer> => + buildCodecForObject<Officer>() + .property("account", codecForLockedAccount) // FIXME + .property("when", codecForAbsoluteTime) // FIXME + .build("Officer"); + +export type OfficerState = OfficerNotReady | OfficerReady; +export type OfficerNotReady = OfficerNotFound | OfficerLocked; +interface OfficerNotFound { + state: "not-found"; + create: (password: string) => Promise<void>; +} +interface OfficerLocked { + state: "locked"; + forget: () => void; + tryUnlock: (password: string) => Promise<void>; +} +interface OfficerReady { + state: "ready"; + account: OfficerAccount; + forget: () => void; + lock: () => void; +} + +const OFFICER_KEY = buildStorageKey("officer", codecForOfficer()); +const DEV_ACCOUNT_KEY = buildStorageKey( + "account-dev", + codecForOfficerAccount(), +); + +export function useOfficer(): OfficerState { + const exchangeContext = useExchangeApiContext(); + const [pref] = usePreferences(); + pref.keepSessionAfterReload; + // dev account, is kept on reloaded. + const accountStorage = useLocalStorage(DEV_ACCOUNT_KEY); + const account = useMemo(() => { + if (!accountStorage.value) return undefined; + + return { + id: accountStorage.value.id as OfficerId, + signingKey: decodeCrock(accountStorage.value.strKey) as SigningKey, + }; + }, [accountStorage.value?.id, accountStorage.value?.strKey]); + + const officerStorage = useLocalStorage(OFFICER_KEY); + const officer = useMemo(() => { + if (!officerStorage.value) return undefined; + return officerStorage.value; + }, [officerStorage.value?.account, officerStorage.value?.when.t_ms]); + + if (officer === undefined) { + return { + state: "not-found", + create: async (pwd: string) => { + const req = await fetch( + new URL("seed", exchangeContext.lib.exchange.baseUrl).href, + ); + const b = await req.blob(); + const ar = await b.arrayBuffer(); + const uintar = new Uint8Array(ar); + + const { id, safe, signingKey } = await createNewOfficerAccount( + pwd, + uintar, + ); + officerStorage.update({ + account: safe, + when: AbsoluteTime.now(), + }); + + // accountStorage.update({ id, signingKey }); + const strKey = encodeCrock(signingKey); + accountStorage.update({ id, strKey }); + }, + }; + } + + if (account === undefined) { + return { + state: "locked", + forget: () => { + officerStorage.reset(); + }, + tryUnlock: async (pwd: string) => { + const ac = await unlockOfficerAccount(officer.account, pwd); + // accountStorage.update(ac); + accountStorage.update({ + id: ac.id, + strKey: encodeCrock(ac.signingKey), + }); + }, + }; + } + + return { + state: "ready", + account, + lock: () => { + accountStorage.reset(); + }, + forget: () => { + officerStorage.reset(); + accountStorage.reset(); + }, + }; +} |