parent
171d070a83
commit
1374b37d26
@ -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",
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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]}
|
||||
/>
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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",
|
||||
},
|
||||
);
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user