import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { AnastasisClientFrame } from "."; import { ChallengeFeedback, ChallengeFeedbackStatus, ChallengeInfo, } from "../../../../anastasis-core/lib"; import { AsyncButton } from "../../components/AsyncButton"; import { TextInput } from "../../components/fields/TextInput"; import { useAnastasisContext } from "../../context/anastasis"; function SolveOverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) { const { feedback } = props; if (!feedback) { return null; } switch (feedback.state) { case ChallengeFeedbackStatus.Message: return (

{feedback.message}

); case ChallengeFeedbackStatus.Pending: case ChallengeFeedbackStatus.AuthIban: return null; case ChallengeFeedbackStatus.RateLimitExceeded: return
Rate limit exceeded.
; case ChallengeFeedbackStatus.Redirect: return
Redirect (FIXME: not supported)
; case ChallengeFeedbackStatus.Unsupported: return
Challenge not supported by client.
; case ChallengeFeedbackStatus.TruthUnknown: return
Truth unknown
; default: return (
{JSON.stringify(feedback)}
); } } export function SolveScreen(): VNode { const reducer = useAnastasisContext(); const [answer, setAnswer] = useState(""); if (!reducer) { return (
no reducer in context
); } if ( !reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined ) { return (
invalid state
); } if (!reducer.currentReducerState.recovery_information) { return (
no recovery information found
); } if (!reducer.currentReducerState.selected_challenge_uuid) { return (
invalid state
); } const chArr = reducer.currentReducerState.recovery_information.challenges; const challengeFeedback = reducer.currentReducerState.challenge_feedback ?? {}; const selectedUuid = reducer.currentReducerState.selected_challenge_uuid; const challenges: { [uuid: string]: ChallengeInfo; } = {}; for (const ch of chArr) { challenges[ch.uuid] = ch; } const selectedChallenge = challenges[selectedUuid]; const dialogMap: Record h.JSX.Element> = { question: SolveQuestionEntry, sms: SolveSmsEntry, email: SolveEmailEntry, post: SolvePostEntry, }; const SolveDialog = selectedChallenge === undefined ? SolveUndefinedEntry : dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry; async function onNext(): Promise { return reducer?.transition("solve_challenge", { answer }); } function onCancel(): void { reducer?.back(); } return (
Confirm
); } export interface SolveEntryProps { id: string; challenge: ChallengeInfo; feedback?: ChallengeFeedback; answer: string; setAnswer: (s: string) => void; } function SolveSmsEntry({ challenge, answer, setAnswer, }: SolveEntryProps): VNode { return (

An sms has been sent to "{challenge.instructions}". Type the code below

); } function SolveQuestionEntry({ challenge, answer, setAnswer, }: SolveEntryProps): VNode { return (

Type the answer to the following question:

{challenge.instructions}
); } function SolvePostEntry({ challenge, answer, setAnswer, }: SolveEntryProps): VNode { return (

instruction for post type challenge "{challenge.instructions}"

); } function SolveEmailEntry({ challenge, answer, setAnswer, }: SolveEntryProps): VNode { return (

An email has been sent to "{challenge.instructions}". Type the code below

); } function SolveUnsupportedEntry(props: SolveEntryProps): VNode { return (

The challenge selected is not supported for this UI. Please update this version or try using another policy.

Challenge type: {props.challenge.type}

); } function SolveUndefinedEntry(props: SolveEntryProps): VNode { return (

There is no challenge information for id "{props.id}". Try resetting the recovery session.

); }