commit e8d8b0ec6d7cf6df13f6c37be9f3293789ad15e6
parent c79277409593343a9ab6cddd813edf6f792b2559
Author: Sebastian <sebasjm@gmail.com>
Date: Mon, 5 May 2025 00:59:19 -0300
fix #9841
Diffstat:
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");
},
);