diff options
9 files changed, 133 insertions, 25 deletions
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx index e61b13279..a2ecbd604 100644 --- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.stories.tsx @@ -39,15 +39,15 @@ export const Backup = createExample(TestedComponent, { ...reducerStatesExample.backupAttributeEditing, required_attributes: [ { - name: "first name", - label: "first", + name: "full_name", + label: "Full name", type: "string", uuid: "asdasdsa1", widget: "wid", }, { - name: "last name", - label: "second", + name: "birthplace", + label: "Birthplace", type: "string", uuid: "asdasdsa2", widget: "wid", @@ -66,15 +66,15 @@ export const Recovery = createExample(TestedComponent, { ...reducerStatesExample.recoveryAttributeEditing, required_attributes: [ { - name: "first", - label: "first", + name: "full_name", + label: "Full name", type: "string", uuid: "asdasdsa1", widget: "wid", }, { - name: "pepe", - label: "second", + name: "birthplace", + label: "Birthplace", type: "string", uuid: "asdasdsa2", widget: "wid", diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx index 1d5896e4d..9c1a93d8e 100644 --- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx @@ -1,6 +1,6 @@ import { UserAttributeSpec, validators } from "@gnu-taler/anastasis-core"; import { isAfter, parse } from "date-fns"; -import { h, VNode } from "preact"; +import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { DateInput } from "../../components/fields/DateInput"; import { PhoneNumberInput } from "../../components/fields/NumberInput"; @@ -122,7 +122,7 @@ for (let i = 0; i < 100; i++) { } function AttributeEntryField(props: AttributeEntryFieldProps): VNode { return ( - <div> + <div style={{ marginTop: 16 }}> {props.spec.type === "date" && ( <DateInput grabFocus={props.isFirst} @@ -151,6 +151,17 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode { bind={[props.value, props.setValue]} /> )} + {props.spec.type === "string" && ( + <div> + This field is case-sensitive. You must enter exactly the same value + during recovery. + </div> + )} + {props.spec.name === "full_name" && ( + <div> + If possible, use "LASTNAME, Firstname(s)" without abbreviations. + </div> + )} <div class="block"> This stays private <span class="icon is-right"> diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx index ccef8b942..e401c3d73 100644 --- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx @@ -75,11 +75,15 @@ export function SecretEditorScreen(): VNode { <div class="block"> <TextInput label="Secret name:" - tooltip="The secret name allows you to identify your secret when restoring it. It is a label that you can choose freely." + tooltip="This allows you to uniquely identify a secret if you have made multiple back ups. The value entered here will NOT be protected by the authentication checks!" grabFocus onConfirm={goNextIfNoErrors} bind={[secretName, setSecretName]} /> + <div> + Names should be unique, so that you can easily identify your secret + later. + </div> </div> <div class="block"> <TextInput diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx index 7252ca2fd..9ee52d8ed 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx @@ -12,7 +12,28 @@ import { SolveOverviewFeedbackDisplay } from "../SolveScreen"; import { AuthMethodSolveProps } from "./index"; export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode { - const [answer, setAnswer] = useState("A-"); + const [answer, _setAnswer] = useState("A-"); + + function setAnswer(str: string): void { + //A-12345-678-1234-5678 + const unformatted = str + .replace(/^A-/, "") + .replace(/-/g, "") + .toLocaleUpperCase(); + + let result = `A-${unformatted.substring(0, 5)}`; + if (unformatted.length > 5) { + result += `-${unformatted.substring(5, 8)}`; + } + if (unformatted.length > 8) { + result += `-${unformatted.substring(8, 12)}`; + } + if (unformatted.length > 12) { + result += `-${unformatted.substring(12, 16)}`; + } + + _setAnswer(result); + } const [expanded, setExpanded] = useState(false); const reducer = useAnastasisContext(); @@ -77,7 +98,9 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode { const feedback = challengeFeedback[selectedUuid]; async function onNext(): Promise<void> { - return reducer?.transition("solve_challenge", { answer }); + return reducer?.transition("solve_challenge", { + answer: `A-${answer.replace(/^A-/, "").replace(/-/g, "").trim()}`, + }); } function onCancel(): void { reducer?.back(); @@ -127,7 +150,7 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode { grabFocus onConfirm={onNext} bind={[answer, setAnswer]} - placeholder="A-1234567812345678" + placeholder="A-12345-678-1234-5678" /> <div diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx index af7a62e6a..5f03437af 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx @@ -12,7 +12,28 @@ import { SolveOverviewFeedbackDisplay } from "../SolveScreen"; import { AuthMethodSolveProps } from "./index"; export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode { - const [answer, setAnswer] = useState("A-"); + const [answer, _setAnswer] = useState("A-"); + + function setAnswer(str: string): void { + //A-12345-678-1234-5678 + const unformatted = str + .replace(/^A-/, "") + .replace(/-/g, "") + .toLocaleUpperCase(); + + let result = `A-${unformatted.substring(0, 5)}`; + if (unformatted.length > 5) { + result += `-${unformatted.substring(5, 8)}`; + } + if (unformatted.length > 8) { + result += `-${unformatted.substring(8, 12)}`; + } + if (unformatted.length > 12) { + result += `-${unformatted.substring(12, 16)}`; + } + + _setAnswer(result); + } const reducer = useAnastasisContext(); if (!reducer) { @@ -76,7 +97,9 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode { const feedback = challengeFeedback[selectedUuid]; async function onNext(): Promise<void> { - return reducer?.transition("solve_challenge", { answer }); + return reducer?.transition("solve_challenge", { + answer: `A-${answer.replace(/^A-/, "").replace(/-/g, "").trim()}`, + }); } function onCancel(): void { reducer?.back(); @@ -96,6 +119,7 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode { onConfirm={onNext} label="Answer" grabFocus + placeholder="A-12345-678-1234-5678" bind={[answer, setAnswer]} /> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx index e70b2a53b..fd9e889cf 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx @@ -5,12 +5,18 @@ import { AuthMethodSetupProps } from "."; import { PhoneNumberInput } from "../../../components/fields/NumberInput"; import { AnastasisClientFrame } from "../index"; +const REGEX_JUST_NUMBERS = /^\+[0-9 ]*$/; + +function isJustNumbers(str: string): boolean { + return REGEX_JUST_NUMBERS.test(str); +} + export function AuthMethodSmsSetup({ addAuthMethod, cancel, configured, }: AuthMethodSetupProps): VNode { - const [mobileNumber, setMobileNumber] = useState(""); + const [mobileNumber, setMobileNumber] = useState("+"); const addSmsAuth = (): void => { addAuthMethod({ authentication_method: { @@ -24,7 +30,13 @@ export function AuthMethodSmsSetup({ useLayoutEffect(() => { inputRef.current?.focus(); }, []); - const errors = !mobileNumber ? "Add a mobile number" : undefined; + const errors = !mobileNumber + ? "Add a mobile number" + : !mobileNumber.startsWith("+") + ? "Mobile number should start with '+'" + : !isJustNumbers(mobileNumber) + ? "Mobile number can't have other than numbers" + : undefined; function goNextIfNoErrors(): void { if (!errors) addSmsAuth(); } @@ -41,9 +53,13 @@ export function AuthMethodSmsSetup({ label="Mobile number" placeholder="Your mobile number" onConfirm={goNextIfNoErrors} + error={errors} grabFocus bind={[mobileNumber, setMobileNumber]} /> + <div> + Enter mobile number including +CC international dialing prefix. + </div> </div> {configured.length > 0 && ( <section class="section"> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx index c33dbd785..4fdbb2ce3 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.stories.tsx @@ -50,14 +50,15 @@ export const WithoutFeedback = createExample( cost: "USD:1", instructions: "SMS to +54 11 2233 4455", type: "question", - uuid: "uuid-1", + uuid: "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0", }, ], policies: [], }, - selected_challenge_uuid: "uuid-1", + selected_challenge_uuid: + "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0", } as ReducerState, { - id: "uuid-1", + id: "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0", }, ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx index 61dad3f51..1fd4343ab 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx @@ -12,7 +12,28 @@ import { SolveOverviewFeedbackDisplay } from "../SolveScreen"; import { AuthMethodSolveProps } from "./index"; export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode { - const [answer, setAnswer] = useState("A-"); + const [answer, _setAnswer] = useState("A-"); + + function setAnswer(str: string): void { + //A-12345-678-1234-5678 + const unformatted = str + .replace(/^A-/, "") + .replace(/-/g, "") + .toLocaleUpperCase(); + + let result = `A-${unformatted.substring(0, 5)}`; + if (unformatted.length > 5) { + result += `-${unformatted.substring(5, 8)}`; + } + if (unformatted.length > 8) { + result += `-${unformatted.substring(8, 12)}`; + } + if (unformatted.length > 12) { + result += `-${unformatted.substring(12, 16)}`; + } + + _setAnswer(result); + } const [expanded, setExpanded] = useState(false); const reducer = useAnastasisContext(); @@ -77,7 +98,9 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode { const feedback = challengeFeedback[selectedUuid]; async function onNext(): Promise<void> { - return reducer?.transition("solve_challenge", { answer }); + return reducer?.transition("solve_challenge", { + answer: `A-${answer.replace(/^A-/, "").replace(/-/g, "").trim()}`, + }); } function onCancel(): void { reducer?.back(); @@ -127,7 +150,7 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode { grabFocus onConfirm={onNext} bind={[answer, setAnswer]} - placeholder="A-1234567812345678" + placeholder="A-12345-678-1234-5678" /> <div diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx index 6b0dd7a79..e0f0cc5e2 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx @@ -55,13 +55,19 @@ export function AuthMethodTotpSetup({ <QR text={totpURL} /> </div> <p> - After scanning the code with your TOTP App, test it in the input below. + Confirm that your TOTP App works by entering the current 8-digit TOTP + code here: </p> <TextInput label="Test code" onConfirm={goNextIfNoErrors} bind={[test, setTest]} /> + <div> + We note that Google's implementation of TOTP is incomplete and will not + work. We recommend using FreeOTP+. + </div> + {configured.length > 0 && ( <section class="section"> <div class="block">Your TOTP numbers:</div> |