aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-11-03 18:56:19 +0100
committerFlorian Dold <florian@dold.me>2021-11-03 18:56:26 +0100
commit9fb6536fbc91adaf7a8a80860fcef5e1f80bfb3b (patch)
tree0febbc9439784f57eaa2947e2494b2ece35fe34b /packages
parentfefdb0d7adcfe95be20f4ff81af316a0ca64f35a (diff)
anastasis-webui: show feedback in solution screen
Diffstat (limited to 'packages')
-rw-r--r--packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx4
-rw-r--r--packages/anastasis-webui/src/pages/home/SolveScreen.tsx177
2 files changed, 135 insertions, 46 deletions
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
index 69dbce037..7bafbe06a 100644
--- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx
@@ -5,7 +5,7 @@ import { useAnastasisContext } from "../../context/anastasis";
import { AnastasisClientFrame } from "./index";
import { authMethods, KnownAuthMethods } from "./authMethod";
-function FeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
+function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) {
const { feedback } = props;
if (!feedback) {
return null;
@@ -130,7 +130,7 @@ export function ChallengeOverviewScreen(): VNode {
<span class="icon">{method?.icon}</span>
<span>{info.instructions}</span>
</div>
- <FeedbackDisplay feedback={info.feedback} />
+ <OverviewFeedbackDisplay feedback={info.feedback} />
</div>
<div>
{method && info.feedback?.state !== "solved" ? (
diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
index b0cfa9bb0..d4d9271b4 100644
--- a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx
@@ -1,38 +1,89 @@
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
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 { 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 {
- const reducer = useAnastasisContext()
+ const reducer = useAnastasisContext();
const [answer, setAnswer] = useState("");
if (!reducer) {
- return <AnastasisClientFrame hideNav title="Recovery problem">
- <div>no reducer in context</div>
- </AnastasisClientFrame>
+ return (
+ <AnastasisClientFrame hideNav title="Recovery problem">
+ <div>no reducer in context</div>
+ </AnastasisClientFrame>
+ );
}
- if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) {
- return <AnastasisClientFrame hideNav title="Recovery problem">
- <div>invalid state</div>
- </AnastasisClientFrame>
+ if (
+ !reducer.currentReducerState ||
+ reducer.currentReducerState.recovery_state === undefined
+ ) {
+ return (
+ <AnastasisClientFrame hideNav title="Recovery problem">
+ <div>invalid state</div>
+ </AnastasisClientFrame>
+ );
}
if (!reducer.currentReducerState.recovery_information) {
- return <AnastasisClientFrame hideNext="Recovery document not found" title="Recovery problem">
- <div>no recovery information found</div>
- </AnastasisClientFrame>
+ return (
+ <AnastasisClientFrame
+ hideNext="Recovery document not found"
+ title="Recovery problem"
+ >
+ <div>no recovery information found</div>
+ </AnastasisClientFrame>
+ );
}
if (!reducer.currentReducerState.selected_challenge_uuid) {
- return <AnastasisClientFrame hideNav title="Recovery problem">
- <div>invalid state</div>
- </AnastasisClientFrame>
+ return (
+ <AnastasisClientFrame hideNav title="Recovery problem">
+ <div>invalid state</div>
+ </AnastasisClientFrame>
+ );
}
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 challenges: {
[uuid: string]: ChallengeInfo;
@@ -47,31 +98,44 @@ export function SolveScreen(): VNode {
email: SolveEmailEntry,
post: SolvePostEntry,
};
- const SolveDialog = selectedChallenge === undefined ? SolveUndefinedEntry : dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry;
+ const SolveDialog =
+ selectedChallenge === undefined
+ ? SolveUndefinedEntry
+ : dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry;
function onNext(): void {
- reducer?.transition("solve_challenge", { answer })
+ reducer?.transition("solve_challenge", { answer });
}
function onCancel(): void {
- reducer?.back()
+ reducer?.back();
}
-
return (
- <AnastasisClientFrame
- hideNav
- title="Recovery: Solve challenge"
- >
+ <AnastasisClientFrame hideNav title="Recovery: Solve challenge">
+ <SolveOverviewFeedbackDisplay
+ feedback={challengeFeedback[selectedUuid]}
+ />
<SolveDialog
id={selectedUuid}
answer={answer}
setAnswer={setAnswer}
challenge={selectedChallenge}
- feedback={challengeFeedback[selectedUuid]} />
+ feedback={challengeFeedback[selectedUuid]}
+ />
- <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
- <button class="button" onClick={onCancel}>Cancel</button>
- <button class="button is-info" onClick={onNext} >Confirm</button>
+ <div
+ style={{
+ marginTop: "2em",
+ display: "flex",
+ justifyContent: "space-between",
+ }}
+ >
+ <button class="button" onClick={onCancel}>
+ Cancel
+ </button>
+ <button class="button is-info" onClick={onNext}>
+ Confirm
+ </button>
</div>
</AnastasisClientFrame>
);
@@ -85,38 +149,61 @@ export interface SolveEntryProps {
setAnswer: (s: string) => void;
}
-function SolveSmsEntry({ challenge, 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]} />
- </Fragment>
+function SolveSmsEntry({
+ challenge,
+ 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]} />
+ </Fragment>
);
}
-function SolveQuestionEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
+function SolveQuestionEntry({
+ challenge,
+ answer,
+ setAnswer,
+}: SolveEntryProps): VNode {
return (
<Fragment>
<p>Type the answer to the following question:</p>
- <pre>
- {challenge.instructions}
- </pre>
+ <pre>{challenge.instructions}</pre>
<TextInput label="Answer" grabFocus bind={[answer, setAnswer]} />
</Fragment>
);
}
-function SolvePostEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
+function SolvePostEntry({
+ challenge,
+ answer,
+ setAnswer,
+}: SolveEntryProps): VNode {
return (
<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]} />
</Fragment>
);
}
-function SolveEmailEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode {
+function SolveEmailEntry({
+ challenge,
+ answer,
+ setAnswer,
+}: SolveEntryProps): VNode {
return (
<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]} />
</Fragment>
);
@@ -126,7 +213,8 @@ function SolveUnsupportedEntry(props: SolveEntryProps): VNode {
return (
<Fragment>
<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>
<b>Challenge type:</b> {props.challenge.type}
@@ -136,9 +224,10 @@ function SolveUnsupportedEntry(props: SolveEntryProps): VNode {
}
function SolveUndefinedEntry(props: SolveEntryProps): VNode {
return (
- <Fragment >
+ <Fragment>
<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>
</Fragment>
);