taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit e8d8b0ec6d7cf6df13f6c37be9f3293789ad15e6
parent c79277409593343a9ab6cddd813edf6f792b2559
Author: Sebastian <sebasjm@gmail.com>
Date:   Mon,  5 May 2025 00:59:19 -0300

fix #9841

Diffstat:
Mpackages/kyc-ui/src/hooks/session.ts | 19+++++++++++++++++--
Mpackages/kyc-ui/src/pages/Start.tsx | 80++++++-------------------------------------------------------------------------
2 files changed, 23 insertions(+), 76 deletions(-)

diff --git a/packages/kyc-ui/src/hooks/session.ts b/packages/kyc-ui/src/hooks/session.ts @@ -25,10 +25,13 @@ import { } from "@gnu-taler/taler-util"; import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser"; import { usePreferences } from "../context/preferences.js"; +import { codecForNumber } from "@gnu-taler/taler-util"; +import { useEffect } from "preact/compat"; export type SessionState = { accessToken: AccessToken; testAccounts: PrivPub[]; + time: number; }; type PrivPub = { @@ -39,6 +42,7 @@ type PrivPub = { export const codecForSessionState = (): Codec<SessionState> => buildCodecForObject<SessionState>() .property("accessToken", codecForAccessToken()) + .property("time", codecOptionalDefault(codecForNumber(), 0)) .property( "testAccounts", codecOptionalDefault(codecForList(codecForPrivPub()), []), @@ -61,13 +65,15 @@ const SESSION_STATE_KEY = buildStorageKey( codecForSessionState(), ); +const SESSION_EXPIRATION_TIME_MS = 1000 * 60 * 60 * 24 * 7; // 1 week + /** * Return getters and setters for * login credentials and backend's * base URL. */ export function useSessionState(): SessionStateHandler { - const { value: state, update } = useLocalStorage(SESSION_STATE_KEY); + const { value: state, update, reset } = useLocalStorage(SESSION_STATE_KEY); const [pref] = usePreferences(); const urlToken = getAccessTokenFromURL(); @@ -81,15 +87,24 @@ export function useSessionState(): SessionStateHandler { } else { accessToken = urlToken ?? state?.accessToken; } + useEffect(() => { + if (state) { + const diff = new Date().getTime() - state.time; + if (diff > SESSION_EXPIRATION_TIME_MS) { + reset(); + } + } + }, []); return { state: accessToken ? { accessToken, testAccounts: state?.testAccounts ?? [], + time: state?.time ?? new Date().getTime(), } : undefined, start(accessToken) { - update({ accessToken, testAccounts: [] }); + update({ accessToken, testAccounts: [], time: new Date().getTime() }); }, }; } diff --git a/packages/kyc-ui/src/pages/Start.tsx b/packages/kyc-ui/src/pages/Start.tsx @@ -33,6 +33,7 @@ import { useState } from "preact/hooks"; import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js"; import { useKycInfo } from "../hooks/kyc.js"; import { FillForm } from "./FillForm.js"; +import { useSessionState } from "../hooks/session.js"; const TALER_SCREEN_ID = 104; @@ -48,17 +49,8 @@ export function ShowReqList({ onFormSelected: (r: KycRequirementInformation) => void; }): VNode { const { i18n } = useTranslationContext(); - const [notification, withErrorHandler] = useLocalNotificationHandler(); const result = useKycInfo(token); - const firstAccount = - result && - !(result instanceof TalerError) && - result.type === "ok" && - result.body.requirements.length > 0 - ? result.body.requirements[0] - : undefined; - if (!result) { return <Loading />; } @@ -77,77 +69,16 @@ export function ShowReqList({ case HttpStatusCode.Accepted: { return <div> accepted </div>; } - // case HttpStatusCode.Forbidden: { - // return <div> forbidden </div>; - // } default: { assertUnreachable(result); } } } - const errors = undefinedIfEmpty({ - // password: !password ? i18n.str`required` : undefined, - // url: !url - // ? i18n.str`required` - // : !safeToURL(url) - // ? i18n.str`invalid format` - // : undefined, - }); - - // const onStart = - // !!errors - // ? undefined - // : withErrorHandler( - // async () => { - // return { - // type: "ok", - // body: {}, - // } - // // return lib.exchange.uploadKycForm( - // // "clientId", - // // createRFC8959AccessTokenEncoded(password), - // // ); - // }, - // (ok) => { - // // start({ - // // nonce: ok.body.nonce, - // // clientId, - // // redirectURL: url, - // // state: encodeCrock(randomBytes(32)), - // // }); - - // onCreated(); - // }, - // // () => { - // // // switch (fail.case) { - // // // case HttpStatusCode.NotFound: - // // // return i18n.str`Client doesn't exist.`; - // // // } - // // }, - // ); - - // const requirements: typeof result.body.requirements = [{ - // description: "this is the form description, click to show the form field bla bla bla", - // form: "asdasd" as KycBuiltInFromId, - // description_i18n: {}, - // id: "ASDASD" as KycRequirementInformationId, - // }, { - // description: "this is the description of the link and service provider.", - // form: "LINK", - // description_i18n: {}, - // id: "ASDASD" as KycRequirementInformationId, - // }, { - // description: "you can't click this because this is only information, wait until AML officer replies.", - // form: "INFO", - // description_i18n: {}, - // id: "ASDASD" as KycRequirementInformationId, - // }] const requirements = result.body.requirements; - if (!result.body.requirements.length) { + if (!requirements.length) { return ( <Fragment> - <LocalNotificationBanner notification={notification} /> <div class="isolate bg-white px-6 py-12"> <div class="mx-auto max-w-2xl text-center"> <h2 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl"> @@ -167,8 +98,6 @@ export function ShowReqList({ } return ( <Fragment> - <LocalNotificationBanner notification={notification} /> - <div class="isolate bg-white px-6 py-12"> <div class="mx-auto max-w-2xl text-center"> <h2 class="text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl"> @@ -214,6 +143,7 @@ export function Start({ token }: Props): VNode { const [req, setReq] = useState<KycRequirementInformation>(); const { lib } = useExchangeApiContext(); const [notification, withErrorHandler] = useLocalNotificationHandler(); + const { state, start } = useSessionState(); if (!req) { return ( <Fragment> @@ -224,12 +154,14 @@ export function Start({ token }: Props): VNode { onFormSelected={async (r) => { const reqId = r.id; if (r.form === "LINK" && reqId) { - // const result = await lib.exchange.startExternalKycProcess(r.id); const action = withErrorHandler( async () => { return lib.exchange.startExternalKycProcess(reqId); }, (res) => { + if (state) { + start(state.accessToken) + } window.open(res.body.redirect_url, "_blank"); }, );