/* This file is part of GNU Anastasis (C) 2021-2022 Anastasis SARL GNU Anastasis is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Anastasis 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with GNU Anastasis; see the file COPYING. If not, see */ import { ChallengeFeedback, ChallengeFeedbackStatus, } from "@gnu-taler/anastasis-core"; import { Fragment, h, VNode } from "preact"; import { AsyncButton } from "../../components/AsyncButton.js"; import { useAnastasisContext } from "../../context/anastasis.js"; import { authMethods, KnownAuthMethods } from "./authMethod/index.js"; import { AnastasisClientFrame } from "./index.js"; function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback; }): VNode { const { feedback } = props; if (!feedback) { return ; } switch (feedback.state) { case ChallengeFeedbackStatus.Solved: return
; case ChallengeFeedbackStatus.IbanInstructions: return
Payment required.
; case ChallengeFeedbackStatus.ServerFailure: return
Server error.
; case ChallengeFeedbackStatus.RateLimitExceeded: return (
There were to many failed attempts.
); case ChallengeFeedbackStatus.Unsupported: return (
This client doesn't support solving this type of challenge. Use another version or contact the provider.
); case ChallengeFeedbackStatus.TruthUnknown: return (
Provider doesn't recognize the type of challenge. Use another version or contact the provider.
); case ChallengeFeedbackStatus.IncorrectAnswer: return (
The answer was not correct.
); case ChallengeFeedbackStatus.CodeInFile: return
code in file
; case ChallengeFeedbackStatus.CodeSent: return
Code sent
; case ChallengeFeedbackStatus.TalerPayment: return
Payment required
; } } export function ChallengeOverviewScreen(): VNode { const reducer = useAnastasisContext(); if (!reducer) { return
no reducer in context
; } if (reducer.currentReducerState?.reducer_type !== "recovery") { return
invalid state
; } const policies = reducer.currentReducerState.recovery_information?.policies ?? []; const knownChallengesArray = reducer.currentReducerState.recovery_information?.challenges ?? []; const challengeFeedback = reducer.currentReducerState?.challenge_feedback ?? {}; const knownChallengesMap: { [uuid: string]: { type: string; instructions: string; feedback: ChallengeFeedback | undefined; }; } = {}; for (const ch of knownChallengesArray) { knownChallengesMap[ch.uuid] = { type: ch.type, instructions: ch.instructions, feedback: challengeFeedback[ch.uuid], }; } const policiesWithInfo = policies .map((row) => { let isPolicySolved = true; const challenges = row .map(({ uuid }) => { const info = knownChallengesMap[uuid]; const isChallengeSolved = info?.feedback?.state === "solved"; isPolicySolved = isPolicySolved && isChallengeSolved; return { info, uuid, isChallengeSolved }; }) .filter((ch) => ch.info !== undefined); return { isPolicySolved, challenges, corrupted: row.length > challenges.length, }; }) .filter((p) => !p.corrupted); const atLeastThereIsOnePolicySolved = policiesWithInfo.find((p) => p.isPolicySolved) !== undefined; const errors = !atLeastThereIsOnePolicySolved ? "Solve one policy before proceeding" : undefined; return ( {!policiesWithInfo.length ? (

No policies found, try with another version of the secret

) : policiesWithInfo.length === 1 ? (

One policy found for this secret. You need to solve all the challenges in order to recover your secret.

) : (

We have found {policiesWithInfo.length} polices. You need to solve all the challenges from one policy in order to recover your secret.

)} {policiesWithInfo.map((policy, policy_index) => { const tableBody = policy.challenges.map(({ info, uuid }) => { const method = authMethods[info.type as KnownAuthMethods]; if (!method) { return (
unknown challenge
); } function ChallengeButton({ id, feedback, }: { id: string; feedback?: ChallengeFeedback; }): VNode { async function selectChallenge(): Promise { if (reducer) { return reducer.transition("select_challenge", { uuid: id }); } } if (!feedback) { return (
Solve
); } switch (feedback.state) { case ChallengeFeedbackStatus.ServerFailure: case ChallengeFeedbackStatus.Unsupported: case ChallengeFeedbackStatus.TruthUnknown: case ChallengeFeedbackStatus.RateLimitExceeded: return
; case ChallengeFeedbackStatus.IbanInstructions: case ChallengeFeedbackStatus.TalerPayment: return (
Pay
); case ChallengeFeedbackStatus.Solved: return (
Solved
); default: return (
Solve
); } } return (
{method?.icon} {info.instructions}
); }); const policyName = policy.challenges .map((x) => x.info.type) .join(" + "); const opa = !atLeastThereIsOnePolicySolved ? undefined : policy.isPolicySolved ? undefined : "0.6"; return (

Policy #{policy_index + 1}: {policyName}

{policy.challenges.length === 0 && (

This policy doesn't have any challenges.

)} {policy.challenges.length === 1 && (

This policy has one challenge.

)} {policy.challenges.length > 1 && (

This policy has {policy.challenges.length} challenges.

)} {tableBody}
); })} ); }