summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-04-22 12:18:41 -0300
committerSebastian <sebasjm@gmail.com>2024-04-22 12:18:41 -0300
commit5db4cb99e3f16c8471117ca7443bc323180e67ec (patch)
treea2340eb33b259cf420abb6a1e3cf295c0393b4f9
parent594dd1fd4638d658303c4c8a0f24c4082564eceb (diff)
downloadwallet-core-5db4cb99e3f16c8471117ca7443bc323180e67ec.tar.gz
wallet-core-5db4cb99e3f16c8471117ca7443bc323180e67ec.tar.bz2
wallet-core-5db4cb99e3f16c8471117ca7443bc323180e67ec.zip
fix #8393
-rw-r--r--packages/challenger-ui/src/Routing.tsx39
-rw-r--r--packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx11
-rw-r--r--packages/challenger-ui/src/hooks/session.ts28
-rw-r--r--packages/challenger-ui/src/pages/AnswerChallenge.tsx24
-rw-r--r--packages/challenger-ui/src/pages/AskChallenge.tsx98
-rw-r--r--packages/challenger-ui/src/pages/CallengeCompleted.tsx3
-rw-r--r--packages/taler-util/src/http-client/types.ts19
7 files changed, 140 insertions, 82 deletions
diff --git a/packages/challenger-ui/src/Routing.tsx b/packages/challenger-ui/src/Routing.tsx
index eae182be5..f1f4d82d2 100644
--- a/packages/challenger-ui/src/Routing.tsx
+++ b/packages/challenger-ui/src/Routing.tsx
@@ -44,6 +44,10 @@ export function Routing(): VNode {
}
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}`,
@@ -93,6 +97,9 @@ function PublicRounting(): VNode {
}
switch (location.name) {
+ case "noinfo": {
+ return <div>no info</div>;
+ }
case "setup": {
return (
<Setup
@@ -137,6 +144,13 @@ function PublicRounting(): VNode {
<CheckChallengeIsUpToDate
sessionId={sessionId}
nonce={location.values.nonce}
+ onNoInfo={() => {
+ navigateTo(
+ publicPages.noinfo.url({
+ nonce: location.values.nonce,
+ }),
+ );
+ }}
onCompleted={() => {
start(sessionId);
navigateTo(
@@ -170,6 +184,13 @@ function PublicRounting(): VNode {
return (
<CheckChallengeIsUpToDate
nonce={location.values.nonce}
+ onNoInfo={() => {
+ navigateTo(
+ publicPages.noinfo.url({
+ nonce: location.values.nonce,
+ }),
+ );
+ }}
onCompleted={() => {
navigateTo(
publicPages.completed.url({
@@ -196,6 +217,13 @@ function PublicRounting(): VNode {
return (
<CheckChallengeIsUpToDate
nonce={location.values.nonce}
+ onNoInfo={() => {
+ navigateTo(
+ publicPages.noinfo.url({
+ nonce: location.values.nonce,
+ }),
+ );
+ }}
onCompleted={() => {
navigateTo(
publicPages.completed.url({
@@ -219,7 +247,16 @@ function PublicRounting(): VNode {
}
case "completed": {
return (
- <CheckChallengeIsUpToDate nonce={location.values.nonce}>
+ <CheckChallengeIsUpToDate
+ nonce={location.values.nonce}
+ onNoInfo={() => {
+ navigateTo(
+ publicPages.noinfo.url({
+ nonce: location.values.nonce,
+ }),
+ );
+ }}
+ >
<CallengeCompleted nonce={location.values.nonce} />
</CheckChallengeIsUpToDate>
);
diff --git a/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx b/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx
index 04556696b..70e41bf1e 100644
--- a/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx
+++ b/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx
@@ -16,7 +16,7 @@
import {
HttpStatusCode,
TalerError,
- assertUnreachable
+ assertUnreachable,
} from "@gnu-taler/taler-util";
import {
Attention,
@@ -34,6 +34,7 @@ interface Props {
onCompleted?: () => void;
onChangeLeft?: () => void;
onNoMoreChanges?: () => void;
+ onNoInfo: () => void;
}
export function CheckChallengeIsUpToDate({
sessionId: sessionFromParam,
@@ -42,6 +43,7 @@ export function CheckChallengeIsUpToDate({
onCompleted,
onChangeLeft,
onNoMoreChanges,
+ onNoInfo,
}: Props): VNode {
const { state, updateStatus } = useSessionState();
const { i18n } = useTranslationContext();
@@ -57,12 +59,17 @@ export function CheckChallengeIsUpToDate({
};
const result = useChallengeSession(nonce, sessionId);
+ console.log("asd");
+ if (!sessionId) {
+ onNoInfo();
+ return <Loading />;
+ }
if (!result) {
return <Loading />;
}
if (result instanceof TalerError) {
- return <div />;
+ return <pre>{JSON.stringify(result, undefined, 2)}</pre>;
}
if (result.type === "fail") {
diff --git a/packages/challenger-ui/src/hooks/session.ts b/packages/challenger-ui/src/hooks/session.ts
index 4d0ffeccf..ed7ea8986 100644
--- a/packages/challenger-ui/src/hooks/session.ts
+++ b/packages/challenger-ui/src/hooks/session.ts
@@ -45,9 +45,8 @@ export type LastChallengeResponse = {
};
export type SessionState = SessionId & {
- email: string | undefined;
lastTry: LastChallengeResponse | undefined;
- challengeStatus: ChallengerApi.ChallengeStatus | undefined;
+ lastStatus: ChallengerApi.ChallengeStatus | undefined;
completedURL: string | undefined;
};
export const codecForLastChallengeResponse = (): Codec<LastChallengeResponse> =>
@@ -63,15 +62,14 @@ export const codecForSessionState = (): Codec<SessionState> =>
.property("redirectURL", codecForStringURL())
.property("completedURL", codecOptional(codecForStringURL()))
.property("state", codecForString())
- .property("challengeStatus", codecOptional(codecForChallengeStatus()))
+ .property("lastStatus", codecOptional(codecForChallengeStatus()))
.property("lastTry", codecOptional(codecForLastChallengeResponse()))
- .property("email", codecOptional(codecForString()))
.build("SessionState");
export interface SessionStateHandler {
state: SessionState | undefined;
start(s: SessionId): void;
- accepted(e: string, l: LastChallengeResponse): void;
+ accepted(l: LastChallengeResponse): void;
completed(e: URL): void;
updateStatus(s: ChallengerApi.ChallengeStatus): void;
}
@@ -96,16 +94,14 @@ export function useSessionState(): SessionStateHandler {
...info,
lastTry: undefined,
completedURL: undefined,
- challengeStatus: undefined,
- email: undefined,
+ lastStatus: undefined,
});
cleanAllCache();
},
- accepted(email, lastTry) {
+ accepted(lastTry) {
if (!state) return;
update({
...state,
- email,
lastTry,
});
},
@@ -118,23 +114,23 @@ export function useSessionState(): SessionStateHandler {
},
updateStatus(st: ChallengerApi.ChallengeStatus) {
if (!state) return;
- if (!state.challengeStatus) {
+ if (!state.lastStatus) {
update({
...state,
- challengeStatus: st,
+ lastStatus: st,
});
return;
}
// current status
- const cu = state.challengeStatus;
+ const ls = state.lastStatus;
if (
- cu.changes_left !== st.changes_left ||
- cu.fix_address !== st.fix_address ||
- cu.last_address !== st.last_address
+ ls.changes_left !== st.changes_left ||
+ ls.fix_address !== st.fix_address ||
+ ls.last_address !== st.last_address
) {
update({
...state,
- challengeStatus: st,
+ lastStatus: st,
});
return;
}
diff --git a/packages/challenger-ui/src/pages/AnswerChallenge.tsx b/packages/challenger-ui/src/pages/AnswerChallenge.tsx
index bad6d70de..62b7e775d 100644
--- a/packages/challenger-ui/src/pages/AnswerChallenge.tsx
+++ b/packages/challenger-ui/src/pages/AnswerChallenge.tsx
@@ -16,7 +16,7 @@
import {
ChallengerApi,
HttpStatusCode,
- assertUnreachable
+ assertUnreachable,
} from "@gnu-taler/taler-util";
import {
Attention,
@@ -25,7 +25,7 @@ import {
ShowInputErrorLabel,
useChallengerApiContext,
useLocalNotificationHandler,
- useTranslationContext
+ useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -50,19 +50,25 @@ export function AnswerChallenge({ nonce, onComplete }: Props): VNode {
pin: !pin ? i18n.str`Can't be empty` : undefined,
});
+ const lastEmail = !state
+ ? undefined
+ : !state.lastStatus
+ ? undefined
+ : ((state.lastStatus.last_address as any)["email"] as string);
+
const onSendAgain =
- !state || state.email === undefined
+ !state || lastEmail === undefined
? undefined
: withErrorHandler(
async () => {
- if (!state?.email) return;
- return await lib.bank.challenge(nonce, { email: state.email });
+ if (!lastEmail) return;
+ return await lib.bank.challenge(nonce, { email: lastEmail });
},
(ok) => {
if ("redirectURL" in ok.body) {
completed(ok.body.redirectURL);
} else {
- accepted(state.email!, {
+ accepted({
attemptsLeft: ok.body.attempts_left,
nextSend: ok.body.next_tx_time,
transmitted: ok.body.transmitted,
@@ -141,13 +147,13 @@ export function AnswerChallenge({ nonce, onComplete }: Props): VNode {
<p class="mt-2 text-lg leading-8 text-gray-600">
{state.lastTry.transmitted ? (
<i18n.Translate>
- A TAN was sent to your address &quot;{state.email}&quot;.
+ A TAN was sent to your address &quot;{lastEmail}&quot;.
</i18n.Translate>
) : (
<Attention title={i18n.str`Resend failed`} type="warning">
<i18n.Translate>
We recently already sent a TAN to your address &quot;
- {state.email}&quot;. A new TAN will not be transmitted again
+ {lastEmail}&quot;. A new TAN will not be transmitted again
before &quot;{state.lastTry.nextSend}&quot;.
</i18n.Translate>
</Attention>
@@ -227,7 +233,7 @@ export function AnswerChallenge({ nonce, onComplete }: Props): VNode {
</form>
</div>
</Fragment>
- )
+ );
}
export function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
diff --git a/packages/challenger-ui/src/pages/AskChallenge.tsx b/packages/challenger-ui/src/pages/AskChallenge.tsx
index 813636fa4..76fe6f00a 100644
--- a/packages/challenger-ui/src/pages/AskChallenge.tsx
+++ b/packages/challenger-ui/src/pages/AskChallenge.tsx
@@ -13,9 +13,7 @@
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 {
- HttpStatusCode
-} from "@gnu-taler/taler-util";
+import { HttpStatusCode } from "@gnu-taler/taler-util";
import {
Attention,
Button,
@@ -24,7 +22,7 @@ import {
ShowInputErrorLabel,
useChallengerApiContext,
useLocalNotificationHandler,
- useTranslationContext
+ useTranslationContext,
} from "@gnu-taler/web-util/browser";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
@@ -38,24 +36,22 @@ export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
type Props = {
nonce: string;
onSendSuccesful: () => void;
- routeSolveChallenge: RouteDefinition<{nonce:string}>,
+ routeSolveChallenge: RouteDefinition<{ nonce: string }>;
};
-export function AskChallenge({ nonce, onSendSuccesful,routeSolveChallenge }: Props): VNode {
+export function AskChallenge({
+ nonce,
+ onSendSuccesful,
+ routeSolveChallenge,
+}: Props): VNode {
const { state, accepted, completed } = useSessionState();
- const status = state?.challengeStatus;
+ const status = state?.lastStatus;
const prevEmail =
- !status || !status.last_address
- ? undefined
- : ((status.last_address as any)["email"] as string);
+ !status || !status.last_address ? undefined : status.last_address["email"];
const regexEmail =
!status || !status.restrictions
? undefined
- : ((status.restrictions as any)["email"] as {
- regex?: string;
- hint?: string;
- hint_i18n?: string;
- });
+ : status.restrictions["email"];
const { lib } = useChallengerApiContext();
const { i18n } = useTranslationContext();
@@ -82,37 +78,39 @@ export function AskChallenge({ nonce, onSendSuccesful,routeSolveChallenge }: Pro
: undefined,
});
- const onSend = errors? undefined : withErrorHandler(
- async () => {
- return lib.bank.challenge(nonce, { email: email! });
- },
- (ok) => {
- if ("redirectURL" in ok.body) {
- completed(ok.body.redirectURL);
- } else {
- accepted(email!, {
- attemptsLeft: ok.body.attempts_left,
- nextSend: ok.body.next_tx_time,
- transmitted: ok.body.transmitted,
- });
- }
- onSendSuccesful();
- },
- (fail) => {
- switch (fail.case) {
- case HttpStatusCode.BadRequest:
- return i18n.str``;
- case HttpStatusCode.NotFound:
- return i18n.str``;
- case HttpStatusCode.NotAcceptable:
- return i18n.str``;
- case HttpStatusCode.TooManyRequests:
- return i18n.str``;
- case HttpStatusCode.InternalServerError:
- return i18n.str``;
- }
- },
- );
+ const onSend = errors
+ ? undefined
+ : withErrorHandler(
+ async () => {
+ return lib.bank.challenge(nonce, { email: email! });
+ },
+ (ok) => {
+ if ("redirectURL" in ok.body) {
+ completed(ok.body.redirectURL);
+ } else {
+ accepted({
+ attemptsLeft: ok.body.attempts_left,
+ nextSend: ok.body.next_tx_time,
+ transmitted: ok.body.transmitted,
+ });
+ }
+ onSendSuccesful();
+ },
+ (fail) => {
+ switch (fail.case) {
+ case HttpStatusCode.BadRequest:
+ return i18n.str``;
+ case HttpStatusCode.NotFound:
+ return i18n.str``;
+ case HttpStatusCode.NotAcceptable:
+ return i18n.str``;
+ case HttpStatusCode.TooManyRequests:
+ return i18n.str``;
+ case HttpStatusCode.InternalServerError:
+ return i18n.str``;
+ }
+ },
+ );
if (!status) {
return <div>no status loaded</div>;
@@ -136,9 +134,13 @@ export function AskChallenge({ nonce, onSendSuccesful,routeSolveChallenge }: Pro
</div>
{state.lastTry && (
<Fragment>
- <Attention title={i18n.str`A code has been sent to ${state.email}`}>
+ <Attention title={i18n.str`A code has been sent to ${prevEmail}`}>
<i18n.Translate>
- You can change the destination or <a href={routeSolveChallenge.url({nonce })}><i18n.Translate>complete the challenge here</i18n.Translate></a>.
+ You can change the destination or{" "}
+ <a href={routeSolveChallenge.url({ nonce })}>
+ <i18n.Translate>complete the challenge here</i18n.Translate>
+ </a>
+ .
</i18n.Translate>
</Attention>
</Fragment>
diff --git a/packages/challenger-ui/src/pages/CallengeCompleted.tsx b/packages/challenger-ui/src/pages/CallengeCompleted.tsx
index 24a05c67f..f8cd7ce60 100644
--- a/packages/challenger-ui/src/pages/CallengeCompleted.tsx
+++ b/packages/challenger-ui/src/pages/CallengeCompleted.tsx
@@ -19,7 +19,8 @@ type Props = {
nonce: string;
}
export function CallengeCompleted({nonce}:Props):VNode {
+
return <div>
- completed
+ completed {nonce}
</div>
} \ No newline at end of file
diff --git a/packages/taler-util/src/http-client/types.ts b/packages/taler-util/src/http-client/types.ts
index 329acd484..a2f709769 100644
--- a/packages/taler-util/src/http-client/types.ts
+++ b/packages/taler-util/src/http-client/types.ts
@@ -18,6 +18,7 @@ import {
import { PaytoString, codecForPaytoString } from "../payto.js";
import {
AmountString,
+ InternationalizedString,
codecForInternationalizedString,
codecForLocation,
} from "../taler-types.js";
@@ -223,7 +224,9 @@ export function createRFC8959AccessToken(token: string): AccessToken {
* @param clientSecret
* @returns
*/
-export function createClientSecretAccessToken(clientSecret: string): AccessToken {
+export function createClientSecretAccessToken(
+ clientSecret: string,
+): AccessToken {
return clientSecret as AccessToken;
}
@@ -1516,9 +1519,9 @@ export const codecForChallengeSetupResponse =
export const codecForChallengeStatus =
(): Codec<ChallengerApi.ChallengeStatus> =>
buildCodecForObject<ChallengerApi.ChallengeStatus>()
- .property("restrictions", codecForAny())
+ .property("restrictions", codecOptional(codecForMap(codecForAny())))
.property("fix_address", codecForBoolean())
- .property("last_address", codecForAny())
+ .property("last_address", codecOptional(codecForMap(codecForAny())))
.property("changes_left", codecForNumber())
.build("ChallengerApi.ChallengeStatus");
export const codecForChallengeCreateResponse =
@@ -5279,6 +5282,12 @@ export namespace ChallengerApi {
nonce: string;
}
+ export interface Restriction {
+ regex?: string;
+ hint?: string;
+ hint_i18n?: InternationalizedString;
+ }
+
export interface ChallengeStatus {
// Object; map of keys (names of the fields of the address
// to be entered by the user) to objects with a "regex" (string)
@@ -5288,7 +5297,7 @@ export namespace ChallengerApi {
// by the user does not match the regex. Keys that are not mapped
// to such an object have no restriction on the value provided by
// the user. See "ADDRESS_RESTRICTIONS" in the challenger configuration.
- restrictions: Object;
+ restrictions: Record<string, Restriction> | undefined;
// indicates if the given address cannot be changed anymore, the
// form should be read-only if set to true.
@@ -5296,7 +5305,7 @@ export namespace ChallengerApi {
// form values from the previous submission if available, details depend
// on the ADDRESS_TYPE, should be used to pre-populate the form
- last_address: Object;
+ last_address: Record<string, string> | undefined;
// number of times the address can still be changed, may or may not be
// shown to the user