anastasis-webui: show feedback in solution screen
This commit is contained in:
parent
fefdb0d7ad
commit
9fb6536fbc
@ -5,7 +5,7 @@ import { useAnastasisContext } from "../../context/anastasis";
|
|||||||
import { AnastasisClientFrame } from "./index";
|
import { AnastasisClientFrame } from "./index";
|
||||||
import { authMethods, KnownAuthMethods } from "./authMethod";
|
import { authMethods, KnownAuthMethods } from "./authMethod";
|
||||||
|
|
||||||
function FeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
|
function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
|
||||||
const { feedback } = props;
|
const { feedback } = props;
|
||||||
if (!feedback) {
|
if (!feedback) {
|
||||||
return null;
|
return null;
|
||||||
@ -130,7 +130,7 @@ export function ChallengeOverviewScreen(): VNode {
|
|||||||
<span class="icon">{method?.icon}</span>
|
<span class="icon">{method?.icon}</span>
|
||||||
<span>{info.instructions}</span>
|
<span>{info.instructions}</span>
|
||||||
</div>
|
</div>
|
||||||
<FeedbackDisplay feedback={info.feedback} />
|
<OverviewFeedbackDisplay feedback={info.feedback} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{method && info.feedback?.state !== "solved" ? (
|
{method && info.feedback?.state !== "solved" ? (
|
||||||
|
@ -1,38 +1,89 @@
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { AnastasisClientFrame } from ".";
|
import { AnastasisClientFrame } from ".";
|
||||||
import { ChallengeFeedback, ChallengeInfo } from "../../../../anastasis-core/lib";
|
import {
|
||||||
|
ChallengeFeedback,
|
||||||
|
ChallengeFeedbackStatus,
|
||||||
|
ChallengeInfo,
|
||||||
|
} from "../../../../anastasis-core/lib";
|
||||||
import { TextInput } from "../../components/fields/TextInput";
|
import { TextInput } from "../../components/fields/TextInput";
|
||||||
import { useAnastasisContext } from "../../context/anastasis";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
|
|
||||||
|
function SolveOverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
|
||||||
|
const { feedback } = props;
|
||||||
|
if (!feedback) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (feedback.state) {
|
||||||
|
case ChallengeFeedbackStatus.Message:
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>{feedback.message}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
case ChallengeFeedbackStatus.Pending:
|
||||||
|
case ChallengeFeedbackStatus.AuthIban:
|
||||||
|
return null;
|
||||||
|
case ChallengeFeedbackStatus.RateLimitExceeded:
|
||||||
|
return <div>Rate limit exceeded.</div>;
|
||||||
|
case ChallengeFeedbackStatus.Redirect:
|
||||||
|
return <div>Redirect (FIXME: not supported)</div>;
|
||||||
|
case ChallengeFeedbackStatus.Unsupported:
|
||||||
|
return <div>Challenge not supported by client.</div>;
|
||||||
|
case ChallengeFeedbackStatus.TruthUnknown:
|
||||||
|
return <div>Truth unknown</div>;
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<pre>{JSON.stringify(feedback)}</pre>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function SolveScreen(): VNode {
|
export function SolveScreen(): VNode {
|
||||||
const reducer = useAnastasisContext()
|
const reducer = useAnastasisContext();
|
||||||
const [answer, setAnswer] = useState("");
|
const [answer, setAnswer] = useState("");
|
||||||
|
|
||||||
if (!reducer) {
|
if (!reducer) {
|
||||||
return <AnastasisClientFrame hideNav title="Recovery problem">
|
return (
|
||||||
|
<AnastasisClientFrame hideNav title="Recovery problem">
|
||||||
<div>no reducer in context</div>
|
<div>no reducer in context</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
|
if (
|
||||||
return <AnastasisClientFrame hideNav title="Recovery problem">
|
!reducer.currentReducerState ||
|
||||||
|
reducer.currentReducerState.recovery_state === undefined
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<AnastasisClientFrame hideNav title="Recovery problem">
|
||||||
<div>invalid state</div>
|
<div>invalid state</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reducer.currentReducerState.recovery_information) {
|
if (!reducer.currentReducerState.recovery_information) {
|
||||||
return <AnastasisClientFrame hideNext="Recovery document not found" title="Recovery problem">
|
return (
|
||||||
|
<AnastasisClientFrame
|
||||||
|
hideNext="Recovery document not found"
|
||||||
|
title="Recovery problem"
|
||||||
|
>
|
||||||
<div>no recovery information found</div>
|
<div>no recovery information found</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!reducer.currentReducerState.selected_challenge_uuid) {
|
if (!reducer.currentReducerState.selected_challenge_uuid) {
|
||||||
return <AnastasisClientFrame hideNav title="Recovery problem">
|
return (
|
||||||
|
<AnastasisClientFrame hideNav title="Recovery problem">
|
||||||
<div>invalid state</div>
|
<div>invalid state</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const chArr = reducer.currentReducerState.recovery_information.challenges;
|
const chArr = reducer.currentReducerState.recovery_information.challenges;
|
||||||
const challengeFeedback = reducer.currentReducerState.challenge_feedback ?? {};
|
const challengeFeedback =
|
||||||
|
reducer.currentReducerState.challenge_feedback ?? {};
|
||||||
const selectedUuid = reducer.currentReducerState.selected_challenge_uuid;
|
const selectedUuid = reducer.currentReducerState.selected_challenge_uuid;
|
||||||
const challenges: {
|
const challenges: {
|
||||||
[uuid: string]: ChallengeInfo;
|
[uuid: string]: ChallengeInfo;
|
||||||
@ -47,31 +98,44 @@ export function SolveScreen(): VNode {
|
|||||||
email: SolveEmailEntry,
|
email: SolveEmailEntry,
|
||||||
post: SolvePostEntry,
|
post: SolvePostEntry,
|
||||||
};
|
};
|
||||||
const SolveDialog = selectedChallenge === undefined ? SolveUndefinedEntry : dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry;
|
const SolveDialog =
|
||||||
|
selectedChallenge === undefined
|
||||||
|
? SolveUndefinedEntry
|
||||||
|
: dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry;
|
||||||
|
|
||||||
function onNext(): void {
|
function onNext(): void {
|
||||||
reducer?.transition("solve_challenge", { answer })
|
reducer?.transition("solve_challenge", { answer });
|
||||||
}
|
}
|
||||||
function onCancel(): void {
|
function onCancel(): void {
|
||||||
reducer?.back()
|
reducer?.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnastasisClientFrame
|
<AnastasisClientFrame hideNav title="Recovery: Solve challenge">
|
||||||
hideNav
|
<SolveOverviewFeedbackDisplay
|
||||||
title="Recovery: Solve challenge"
|
feedback={challengeFeedback[selectedUuid]}
|
||||||
>
|
/>
|
||||||
<SolveDialog
|
<SolveDialog
|
||||||
id={selectedUuid}
|
id={selectedUuid}
|
||||||
answer={answer}
|
answer={answer}
|
||||||
setAnswer={setAnswer}
|
setAnswer={setAnswer}
|
||||||
challenge={selectedChallenge}
|
challenge={selectedChallenge}
|
||||||
feedback={challengeFeedback[selectedUuid]} />
|
feedback={challengeFeedback[selectedUuid]}
|
||||||
|
/>
|
||||||
|
|
||||||
<div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
|
<div
|
||||||
<button class="button" onClick={onCancel}>Cancel</button>
|
style={{
|
||||||
<button class="button is-info" onClick={onNext} >Confirm</button>
|
marginTop: "2em",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button class="button" onClick={onCancel}>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button class="button is-info" onClick={onNext}>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
);
|
);
|
||||||
@ -85,38 +149,61 @@ export interface SolveEntryProps {
|
|||||||
setAnswer: (s: string) => void;
|
setAnswer: (s: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SolveSmsEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
|
function SolveSmsEntry({
|
||||||
return (<Fragment>
|
challenge,
|
||||||
<p>An sms has been sent to "<b>{challenge.instructions}</b>". Type the code below</p>
|
answer,
|
||||||
|
setAnswer,
|
||||||
|
}: SolveEntryProps): VNode {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<p>
|
||||||
|
An sms has been sent to "<b>{challenge.instructions}</b>". Type the code
|
||||||
|
below
|
||||||
|
</p>
|
||||||
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function SolveQuestionEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
|
function SolveQuestionEntry({
|
||||||
|
challenge,
|
||||||
|
answer,
|
||||||
|
setAnswer,
|
||||||
|
}: SolveEntryProps): VNode {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<p>Type the answer to the following question:</p>
|
<p>Type the answer to the following question:</p>
|
||||||
<pre>
|
<pre>{challenge.instructions}</pre>
|
||||||
{challenge.instructions}
|
|
||||||
</pre>
|
|
||||||
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SolvePostEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
|
function SolvePostEntry({
|
||||||
|
challenge,
|
||||||
|
answer,
|
||||||
|
setAnswer,
|
||||||
|
}: SolveEntryProps): VNode {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<p>instruction for post type challenge "<b>{challenge.instructions}</b>"</p>
|
<p>
|
||||||
|
instruction for post type challenge "<b>{challenge.instructions}</b>"
|
||||||
|
</p>
|
||||||
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SolveEmailEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
|
function SolveEmailEntry({
|
||||||
|
challenge,
|
||||||
|
answer,
|
||||||
|
setAnswer,
|
||||||
|
}: SolveEntryProps): VNode {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<p>An email has been sent to "<b>{challenge.instructions}</b>". Type the code below</p>
|
<p>
|
||||||
|
An email has been sent to "<b>{challenge.instructions}</b>". Type the
|
||||||
|
code below
|
||||||
|
</p>
|
||||||
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
@ -126,7 +213,8 @@ function SolveUnsupportedEntry(props: SolveEntryProps): VNode {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<p>
|
<p>
|
||||||
The challenge selected is not supported for this UI. Please update this version or try using another policy.
|
The challenge selected is not supported for this UI. Please update this
|
||||||
|
version or try using another policy.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<b>Challenge type:</b> {props.challenge.type}
|
<b>Challenge type:</b> {props.challenge.type}
|
||||||
@ -138,7 +226,8 @@ function SolveUndefinedEntry(props: SolveEntryProps): VNode {
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<p>
|
<p>
|
||||||
There is no challenge information for id <b>"{props.id}"</b>. Try resetting the recovery session.
|
There is no challenge information for id <b>"{props.id}"</b>. Try
|
||||||
|
resetting the recovery session.
|
||||||
</p>
|
</p>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user