diff options
Diffstat (limited to 'packages/challenger-ui/src/Routing.tsx')
-rw-r--r-- | packages/challenger-ui/src/Routing.tsx | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/packages/challenger-ui/src/Routing.tsx b/packages/challenger-ui/src/Routing.tsx new file mode 100644 index 000000000..6166f159a --- /dev/null +++ b/packages/challenger-ui/src/Routing.tsx @@ -0,0 +1,270 @@ +/* + 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 { + Loading, + urlPattern, + useCurrentLocation, + useNavigationContext, +} from "@gnu-taler/web-util/browser"; +import { Fragment, VNode, h } from "preact"; + +import { assertUnreachable } from "@gnu-taler/taler-util"; +import { CheckChallengeIsUpToDate } from "./components/CheckChallengeIsUpToDate.js"; +import { SessionId, useSessionState } from "./hooks/session.js"; +import { AnswerChallenge } from "./pages/AnswerChallenge.js"; +import { AskChallenge } from "./pages/AskChallenge.js"; +import { CallengeCompleted } from "./pages/CallengeCompleted.js"; +import { Frame } from "./pages/Frame.js"; +import { MissingParams } from "./pages/MissingParams.js"; +import { NonceNotFound } from "./pages/NonceNotFound.js"; +import { Setup } from "./pages/Setup.js"; + +export function Routing(): VNode { + // check session and defined if this is + // public routing or private + return ( + <Frame> + <PublicRounting /> + </Frame> + ); +} + +const publicPages = { + noinfo: urlPattern<{ nonce: string }>( + /\/noinfo\/(?<nonce>[a-zA-Z0-9]+)/, + ({ nonce }) => `#/noinfo/${nonce}`, + ), + authorize: urlPattern<{ nonce: string }>( + /\/authorize\/(?<nonce>[a-zA-Z0-9]+)/, + ({ nonce }) => `#/authorize/${nonce}`, + ), + ask: urlPattern<{ nonce: string }>( + /\/ask\/(?<nonce>[a-zA-Z0-9]+)/, + ({ nonce }) => `#/ask/${nonce}`, + ), + answer: urlPattern<{ nonce: string }>( + /\/answer\/(?<nonce>[a-zA-Z0-9]+)/, + ({ nonce }) => `#/answer/${nonce}`, + ), + completed: urlPattern<{ nonce: string }>( + /\/completed\/(?<nonce>[a-zA-Z0-9]+)/, + ({ nonce }) => `#/completed/${nonce}`, + ), + setup: urlPattern<{ client: string }>( + /\/setup\/(?<client>[0-9]+)/, + ({ client }) => `#/setup/${client}`, + ), +}; + +function safeGetParam( + ps: Record<string, string[]>, + n: string, +): string | undefined { + if (!ps[n] || ps[n].length == 0) return undefined; + return ps[n][0]; +} + +function safeToURL(s: string | undefined): URL | undefined { + if (s === undefined) return undefined; + try { + return new URL(s); + } catch (e) { + return undefined; + } +} + +function PublicRounting(): VNode { + const location = useCurrentLocation(publicPages); + const { navigateTo } = useNavigationContext(); + const { start } = useSessionState(); + + if (location === undefined) { + return <NonceNotFound />; + } + + switch (location.name) { + case "noinfo": { + return <div>no info</div>; + } + case "setup": { + return ( + <Setup + clientId={location.values.client} + onCreated={(nonce) => { + navigateTo(publicPages.ask.url({ nonce })); + //response_type=code + //client_id=1 + //redirect_uri=http://exchange.taler.test:1180/kyc-proof/kyc-provider-wallet + //state=123 + }} + /> + ); + } + case "authorize": { + const responseType = safeGetParam(location.params, "response_type"); + const clientId = safeGetParam(location.params, "client_id"); + const redirectURL = safeToURL( + safeGetParam(location.params, "redirect_uri"), + ); + const state = safeGetParam(location.params, "state"); + // http://localhost:8080/app/#/authorize/ASDASD123?response_type=code&client_id=1&redirect_uri=goog.ecom&state=123 + // + + // http://localhost:8080/app/?response_type=code&client_id=1&redirect_uri=http://exchange.taler.test:1180/kyc-proof/kyc-provider-wallet&state=123#/authorize/X9668AR2CFC26X55H0M87GJZXGM45VD4SZE05C5SNS5FADPWN220 + + if ( + !responseType || + !clientId || + !redirectURL || + !state || + responseType !== "code" + ) { + return <MissingParams />; + } + const sessionId: SessionId = { + clientId, + redirectURL: redirectURL.href, + state, + }; + return ( + <CheckChallengeIsUpToDate + sessionId={sessionId} + nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} + onCompleted={() => { + start(sessionId); + navigateTo( + publicPages.completed.url({ + nonce: location.values.nonce, + }), + ); + }} + onChangeLeft={() => { + start(sessionId); + navigateTo( + publicPages.ask.url({ + nonce: location.values.nonce, + }), + ); + }} + onNoMoreChanges={() => { + start(sessionId); + navigateTo( + publicPages.ask.url({ + nonce: location.values.nonce, + }), + ); + }} + > + <Loading /> + </CheckChallengeIsUpToDate> + ); + } + case "ask": { + return ( + <CheckChallengeIsUpToDate + nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} + onCompleted={() => { + navigateTo( + publicPages.completed.url({ + nonce: location.values.nonce, + }), + ); + }} + > + <AskChallenge + focus + nonce={location.values.nonce} + routeSolveChallenge={publicPages.answer} + onSendSuccesful={() => { + navigateTo( + publicPages.answer.url({ + nonce: location.values.nonce, + }), + ); + }} + /> + </CheckChallengeIsUpToDate> + ); + } + case "answer": { + return ( + <CheckChallengeIsUpToDate + nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} + onCompleted={() => { + navigateTo( + publicPages.completed.url({ + nonce: location.values.nonce, + }), + ); + }} + > + <AnswerChallenge + focus + nonce={location.values.nonce} + routeAsk={publicPages.ask} + onComplete={() => { + navigateTo( + publicPages.completed.url({ + nonce: location.values.nonce, + }), + ); + }} + /> + </CheckChallengeIsUpToDate> + ); + } + case "completed": { + return ( + <CheckChallengeIsUpToDate + nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} + > + <CallengeCompleted nonce={location.values.nonce} /> + </CheckChallengeIsUpToDate> + ); + } + default: + assertUnreachable(location); + } +} |