diff options
Diffstat (limited to 'packages/challenger-ui/src/hooks/session.ts')
-rw-r--r-- | packages/challenger-ui/src/hooks/session.ts | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/packages/challenger-ui/src/hooks/session.ts b/packages/challenger-ui/src/hooks/session.ts new file mode 100644 index 000000000..ed7ea8986 --- /dev/null +++ b/packages/challenger-ui/src/hooks/session.ts @@ -0,0 +1,143 @@ +/* + 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 { + ChallengerApi, + Codec, + buildCodecForObject, + codecForBoolean, + codecForChallengeStatus, + codecForNumber, + codecForString, + codecForStringURL, + codecOptional, +} from "@gnu-taler/taler-util"; +import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser"; +import { mutate } from "swr"; + +/** + * Has the information to reach and + * authenticate at the bank's backend. + */ +export type SessionId = { + clientId: string; + redirectURL: string; + state: string; +}; + +export type LastChallengeResponse = { + attemptsLeft: number; + nextSend: string; + transmitted: boolean; +}; + +export type SessionState = SessionId & { + lastTry: LastChallengeResponse | undefined; + lastStatus: ChallengerApi.ChallengeStatus | undefined; + completedURL: string | undefined; +}; +export const codecForLastChallengeResponse = (): Codec<LastChallengeResponse> => + buildCodecForObject<LastChallengeResponse>() + .property("attemptsLeft", codecForNumber()) + .property("nextSend", codecForString()) + .property("transmitted", codecForBoolean()) + .build("LastChallengeResponse"); + +export const codecForSessionState = (): Codec<SessionState> => + buildCodecForObject<SessionState>() + .property("clientId", codecForString()) + .property("redirectURL", codecForStringURL()) + .property("completedURL", codecOptional(codecForStringURL())) + .property("state", codecForString()) + .property("lastStatus", codecOptional(codecForChallengeStatus())) + .property("lastTry", codecOptional(codecForLastChallengeResponse())) + .build("SessionState"); + +export interface SessionStateHandler { + state: SessionState | undefined; + start(s: SessionId): void; + accepted(l: LastChallengeResponse): void; + completed(e: URL): void; + updateStatus(s: ChallengerApi.ChallengeStatus): void; +} + +const SESSION_STATE_KEY = buildStorageKey( + "challenger-session", + codecForSessionState(), +); + +/** + * Return getters and setters for + * login credentials and backend's + * base URL. + */ +export function useSessionState(): SessionStateHandler { + const { value: state, update } = useLocalStorage(SESSION_STATE_KEY); + + return { + state, + start(info) { + update({ + ...info, + lastTry: undefined, + completedURL: undefined, + lastStatus: undefined, + }); + cleanAllCache(); + }, + accepted(lastTry) { + if (!state) return; + update({ + ...state, + lastTry, + }); + }, + completed(url) { + if (!state) return; + update({ + ...state, + completedURL: url.href, + }); + }, + updateStatus(st: ChallengerApi.ChallengeStatus) { + if (!state) return; + if (!state.lastStatus) { + update({ + ...state, + lastStatus: st, + }); + return; + } + // current status + const ls = state.lastStatus; + if ( + ls.changes_left !== st.changes_left || + ls.fix_address !== st.fix_address || + ls.last_address !== st.last_address + ) { + update({ + ...state, + lastStatus: st, + }); + return; + } + }, + }; +} + +function cleanAllCache(): void { + mutate(() => true, undefined, { revalidate: false }); +} |