This commit is contained in:
Sebastian 2022-01-24 16:47:37 -03:00
parent 171d070a83
commit 1374b37d26
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
9 changed files with 133 additions and 25 deletions

View File

@ -39,15 +39,15 @@ export const Backup = createExample(TestedComponent, {
...reducerStatesExample.backupAttributeEditing, ...reducerStatesExample.backupAttributeEditing,
required_attributes: [ required_attributes: [
{ {
name: "first name", name: "full_name",
label: "first", label: "Full name",
type: "string", type: "string",
uuid: "asdasdsa1", uuid: "asdasdsa1",
widget: "wid", widget: "wid",
}, },
{ {
name: "last name", name: "birthplace",
label: "second", label: "Birthplace",
type: "string", type: "string",
uuid: "asdasdsa2", uuid: "asdasdsa2",
widget: "wid", widget: "wid",
@ -66,15 +66,15 @@ export const Recovery = createExample(TestedComponent, {
...reducerStatesExample.recoveryAttributeEditing, ...reducerStatesExample.recoveryAttributeEditing,
required_attributes: [ required_attributes: [
{ {
name: "first", name: "full_name",
label: "first", label: "Full name",
type: "string", type: "string",
uuid: "asdasdsa1", uuid: "asdasdsa1",
widget: "wid", widget: "wid",
}, },
{ {
name: "pepe", name: "birthplace",
label: "second", label: "Birthplace",
type: "string", type: "string",
uuid: "asdasdsa2", uuid: "asdasdsa2",
widget: "wid", widget: "wid",

View File

@ -1,6 +1,6 @@
import { UserAttributeSpec, validators } from "@gnu-taler/anastasis-core"; import { UserAttributeSpec, validators } from "@gnu-taler/anastasis-core";
import { isAfter, parse } from "date-fns"; import { isAfter, parse } from "date-fns";
import { h, VNode } from "preact"; import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks"; import { useState } from "preact/hooks";
import { DateInput } from "../../components/fields/DateInput"; import { DateInput } from "../../components/fields/DateInput";
import { PhoneNumberInput } from "../../components/fields/NumberInput"; import { PhoneNumberInput } from "../../components/fields/NumberInput";
@ -122,7 +122,7 @@ for (let i = 0; i < 100; i++) {
} }
function AttributeEntryField(props: AttributeEntryFieldProps): VNode { function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
return ( return (
<div> <div style={{ marginTop: 16 }}>
{props.spec.type === "date" && ( {props.spec.type === "date" && (
<DateInput <DateInput
grabFocus={props.isFirst} grabFocus={props.isFirst}
@ -151,6 +151,17 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode {
bind={[props.value, props.setValue]} 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"> <div class="block">
This stays private This stays private
<span class="icon is-right"> <span class="icon is-right">

View File

@ -75,11 +75,15 @@ export function SecretEditorScreen(): VNode {
<div class="block"> <div class="block">
<TextInput <TextInput
label="Secret name:" 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 grabFocus
onConfirm={goNextIfNoErrors} onConfirm={goNextIfNoErrors}
bind={[secretName, setSecretName]} bind={[secretName, setSecretName]}
/> />
<div>
Names should be unique, so that you can easily identify your secret
later.
</div>
</div> </div>
<div class="block"> <div class="block">
<TextInput <TextInput

View File

@ -12,7 +12,28 @@ import { SolveOverviewFeedbackDisplay } from "../SolveScreen";
import { AuthMethodSolveProps } from "./index"; import { AuthMethodSolveProps } from "./index";
export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode { 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 [expanded, setExpanded] = useState(false);
const reducer = useAnastasisContext(); const reducer = useAnastasisContext();
@ -77,7 +98,9 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode {
const feedback = challengeFeedback[selectedUuid]; const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> { 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 { function onCancel(): void {
reducer?.back(); reducer?.back();
@ -127,7 +150,7 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode {
grabFocus grabFocus
onConfirm={onNext} onConfirm={onNext}
bind={[answer, setAnswer]} bind={[answer, setAnswer]}
placeholder="A-1234567812345678" placeholder="A-12345-678-1234-5678"
/> />
<div <div

View File

@ -12,7 +12,28 @@ import { SolveOverviewFeedbackDisplay } from "../SolveScreen";
import { AuthMethodSolveProps } from "./index"; import { AuthMethodSolveProps } from "./index";
export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode { 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(); const reducer = useAnastasisContext();
if (!reducer) { if (!reducer) {
@ -76,7 +97,9 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode {
const feedback = challengeFeedback[selectedUuid]; const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> { 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 { function onCancel(): void {
reducer?.back(); reducer?.back();
@ -96,6 +119,7 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode {
onConfirm={onNext} onConfirm={onNext}
label="Answer" label="Answer"
grabFocus grabFocus
placeholder="A-12345-678-1234-5678"
bind={[answer, setAnswer]} bind={[answer, setAnswer]}
/> />

View File

@ -5,12 +5,18 @@ import { AuthMethodSetupProps } from ".";
import { PhoneNumberInput } from "../../../components/fields/NumberInput"; import { PhoneNumberInput } from "../../../components/fields/NumberInput";
import { AnastasisClientFrame } from "../index"; import { AnastasisClientFrame } from "../index";
const REGEX_JUST_NUMBERS = /^\+[0-9 ]*$/;
function isJustNumbers(str: string): boolean {
return REGEX_JUST_NUMBERS.test(str);
}
export function AuthMethodSmsSetup({ export function AuthMethodSmsSetup({
addAuthMethod, addAuthMethod,
cancel, cancel,
configured, configured,
}: AuthMethodSetupProps): VNode { }: AuthMethodSetupProps): VNode {
const [mobileNumber, setMobileNumber] = useState(""); const [mobileNumber, setMobileNumber] = useState("+");
const addSmsAuth = (): void => { const addSmsAuth = (): void => {
addAuthMethod({ addAuthMethod({
authentication_method: { authentication_method: {
@ -24,7 +30,13 @@ export function AuthMethodSmsSetup({
useLayoutEffect(() => { useLayoutEffect(() => {
inputRef.current?.focus(); 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 { function goNextIfNoErrors(): void {
if (!errors) addSmsAuth(); if (!errors) addSmsAuth();
} }
@ -41,9 +53,13 @@ export function AuthMethodSmsSetup({
label="Mobile number" label="Mobile number"
placeholder="Your mobile number" placeholder="Your mobile number"
onConfirm={goNextIfNoErrors} onConfirm={goNextIfNoErrors}
error={errors}
grabFocus grabFocus
bind={[mobileNumber, setMobileNumber]} bind={[mobileNumber, setMobileNumber]}
/> />
<div>
Enter mobile number including +CC international dialing prefix.
</div>
</div> </div>
{configured.length > 0 && ( {configured.length > 0 && (
<section class="section"> <section class="section">

View File

@ -50,14 +50,15 @@ export const WithoutFeedback = createExample(
cost: "USD:1", cost: "USD:1",
instructions: "SMS to +54 11 2233 4455", instructions: "SMS to +54 11 2233 4455",
type: "question", type: "question",
uuid: "uuid-1", uuid: "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0",
}, },
], ],
policies: [], policies: [],
}, },
selected_challenge_uuid: "uuid-1", selected_challenge_uuid:
"AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0",
} as ReducerState, } as ReducerState,
{ {
id: "uuid-1", id: "AHCC4ZJ3Z1AF8TWBKGVGEKCQ3R7HXHJ51MJ45NHNZMHYZTKJ9NW0",
}, },
); );

View File

@ -12,7 +12,28 @@ import { SolveOverviewFeedbackDisplay } from "../SolveScreen";
import { AuthMethodSolveProps } from "./index"; import { AuthMethodSolveProps } from "./index";
export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode { 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 [expanded, setExpanded] = useState(false);
const reducer = useAnastasisContext(); const reducer = useAnastasisContext();
@ -77,7 +98,9 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode {
const feedback = challengeFeedback[selectedUuid]; const feedback = challengeFeedback[selectedUuid];
async function onNext(): Promise<void> { 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 { function onCancel(): void {
reducer?.back(); reducer?.back();
@ -127,7 +150,7 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode {
grabFocus grabFocus
onConfirm={onNext} onConfirm={onNext}
bind={[answer, setAnswer]} bind={[answer, setAnswer]}
placeholder="A-1234567812345678" placeholder="A-12345-678-1234-5678"
/> />
<div <div

View File

@ -55,13 +55,19 @@ export function AuthMethodTotpSetup({
<QR text={totpURL} /> <QR text={totpURL} />
</div> </div>
<p> <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> </p>
<TextInput <TextInput
label="Test code" label="Test code"
onConfirm={goNextIfNoErrors} onConfirm={goNextIfNoErrors}
bind={[test, setTest]} 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 && ( {configured.length > 0 && (
<section class="section"> <section class="section">
<div class="block">Your TOTP numbers:</div> <div class="block">Your TOTP numbers:</div>