testing provider screen
This commit is contained in:
parent
c87be3707e
commit
4ac0b23793
@ -0,0 +1,50 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2021 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||||
|
terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 3, or (at your option) any later version.
|
||||||
|
|
||||||
|
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ReducerState } from 'anastasis-core';
|
||||||
|
import { createExample, reducerStatesExample } from '../../utils';
|
||||||
|
import { AddingProviderScreen as TestedComponent } from './AddingProviderScreen';
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Pages/backup/AddingProviderScreen',
|
||||||
|
component: TestedComponent,
|
||||||
|
args: {
|
||||||
|
order: 4,
|
||||||
|
},
|
||||||
|
argTypes: {
|
||||||
|
onUpdate: { action: 'onUpdate' },
|
||||||
|
onBack: { action: 'onBack' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NewProvider = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.authEditing,
|
||||||
|
} as ReducerState);
|
||||||
|
|
||||||
|
export const NewSMSProvider = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.authEditing,
|
||||||
|
} as ReducerState, { providerType: 'sms'});
|
||||||
|
|
||||||
|
export const NewIBANProvider = createExample(TestedComponent, {
|
||||||
|
...reducerStatesExample.authEditing,
|
||||||
|
} as ReducerState, { providerType: 'iban' });
|
101
packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
Normal file
101
packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
|
import {
|
||||||
|
encodeCrock,
|
||||||
|
stringToBytes
|
||||||
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { h, VNode } from "preact";
|
||||||
|
import { useLayoutEffect, useRef, useState } from "preact/hooks";
|
||||||
|
import { TextInput } from "../../components/fields/TextInput";
|
||||||
|
import { authMethods, KnownAuthMethods } from "./authMethod";
|
||||||
|
import { AnastasisClientFrame } from "./index";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
providerType?: KnownAuthMethods;
|
||||||
|
cancel: () => void;
|
||||||
|
}
|
||||||
|
export function AddingProviderScreen({ providerType, cancel }: Props): VNode {
|
||||||
|
const [providerURL, setProviderURL] = useState("");
|
||||||
|
const [error, setError] = useState<string | undefined>()
|
||||||
|
const providerLabel = providerType ? authMethods[providerType].label : undefined
|
||||||
|
|
||||||
|
function testProvider(): void {
|
||||||
|
setError(undefined)
|
||||||
|
|
||||||
|
fetch(`${providerURL}/config`)
|
||||||
|
.then(r => r.json().catch(d => ({})))
|
||||||
|
.then(r => {
|
||||||
|
if (!("methods" in r) || !Array.isArray(r.methods)) {
|
||||||
|
setError("This provider doesn't have authentication method. Check the provider URL")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!providerLabel) {
|
||||||
|
setError("")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let found = false
|
||||||
|
for (let i = 0; i < r.methods.length && !found; i++) {
|
||||||
|
found = r.methods[i].type !== providerType
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
setError(`This provider does not support authentication method ${providerLabel}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
setError(`There was an error testing this provider, try another one. ${e.message}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
function addProvider(): void {
|
||||||
|
// addAuthMethod({
|
||||||
|
// authentication_method: {
|
||||||
|
// type: "sms",
|
||||||
|
// instructions: `SMS to ${providerURL}`,
|
||||||
|
// challenge: encodeCrock(stringToBytes(providerURL)),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
inputRef.current?.focus();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
let errors = !providerURL ? 'Add provider URL' : undefined
|
||||||
|
try {
|
||||||
|
new URL(providerURL)
|
||||||
|
} catch {
|
||||||
|
errors = 'Check the URL'
|
||||||
|
}
|
||||||
|
if (!!error && !errors) {
|
||||||
|
errors = error
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AnastasisClientFrame hideNav
|
||||||
|
title={!providerLabel ? `Backup: Adding a provider` : `Backup: Adding a ${providerLabel} provider`}
|
||||||
|
hideNext={errors}>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Add a provider url {errors}
|
||||||
|
</p>
|
||||||
|
<div class="container">
|
||||||
|
<TextInput
|
||||||
|
label="Provider URL"
|
||||||
|
placeholder="https://provider.com"
|
||||||
|
grabFocus
|
||||||
|
bind={[providerURL, setProviderURL]} />
|
||||||
|
</div>
|
||||||
|
{!!error && <p class="block has-text-danger">{error}</p>}
|
||||||
|
{error === "" && <p class="block has-text-success">This provider worked!</p>}
|
||||||
|
<div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
|
||||||
|
<button class="button" onClick={testProvider}>TEST</button>
|
||||||
|
</div>
|
||||||
|
<div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
|
||||||
|
<button class="button" onClick={cancel}>Cancel</button>
|
||||||
|
<span data-tooltip={errors}>
|
||||||
|
<button class="button is-info" disabled={errors !== undefined} onClick={addProvider}>Add</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AnastasisClientFrame>
|
||||||
|
);
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
import { AuthMethod } from "anastasis-core";
|
import { AuthMethod } from "anastasis-core";
|
||||||
import { ComponentChildren, h, VNode } from "preact";
|
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { TextInput } from "../../components/fields/TextInput";
|
||||||
import { useAnastasisContext } from "../../context/anastasis";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
import { authMethods, KnownAuthMethods } from "./authMethod";
|
import { authMethods, KnownAuthMethods } from "./authMethod";
|
||||||
import { AnastasisClientFrame } from "./index";
|
import { AnastasisClientFrame } from "./index";
|
||||||
@ -13,6 +14,7 @@ const getKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>
|
|||||||
export function AuthenticationEditorScreen(): VNode {
|
export function AuthenticationEditorScreen(): VNode {
|
||||||
const [noProvidersAck, setNoProvidersAck] = useState(false)
|
const [noProvidersAck, setNoProvidersAck] = useState(false)
|
||||||
const [selectedMethod, setSelectedMethod] = useState<KnownAuthMethods | undefined>(undefined);
|
const [selectedMethod, setSelectedMethod] = useState<KnownAuthMethods | undefined>(undefined);
|
||||||
|
const [addingProvider, setAddingProvider] = useState<string | undefined>(undefined)
|
||||||
|
|
||||||
const reducer = useAnastasisContext()
|
const reducer = useAnastasisContext()
|
||||||
if (!reducer) {
|
if (!reducer) {
|
||||||
@ -62,36 +64,58 @@ export function AuthenticationEditorScreen(): VNode {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AuthSetup = authMethods[selectedMethod].screen ?? AuthMethodNotImplemented;
|
const AuthSetup = authMethods[selectedMethod].screen ?? AuthMethodNotImplemented;
|
||||||
return (
|
return (<Fragment>
|
||||||
<AuthSetup
|
<AuthSetup
|
||||||
cancel={cancel}
|
cancel={cancel}
|
||||||
configured={camByType[selectedMethod] || []}
|
configured={camByType[selectedMethod] || []}
|
||||||
addAuthMethod={addMethod}
|
addAuthMethod={addMethod}
|
||||||
method={selectedMethod} />
|
method={selectedMethod} />
|
||||||
|
|
||||||
|
{!authAvailableSet.has(selectedMethod) && <ConfirmModal active
|
||||||
|
onCancel={cancel} description="No providers founds" label="Add a provider manually"
|
||||||
|
onConfirm={() => {
|
||||||
|
null
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
We have found no trusted cloud providers for your recovery secret. You can add a provider manually.
|
||||||
|
To add a provider you must know the provider URL (e.g. https://provider.com)
|
||||||
|
<p>
|
||||||
|
<a>More about cloud providers</a>
|
||||||
|
</p>
|
||||||
|
</ConfirmModal>}
|
||||||
|
|
||||||
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addingProvider !== undefined) {
|
||||||
|
return <div />
|
||||||
|
}
|
||||||
|
|
||||||
function MethodButton(props: { method: KnownAuthMethods }): VNode {
|
function MethodButton(props: { method: KnownAuthMethods }): VNode {
|
||||||
|
if (authMethods[props.method].skip) return <div />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="block">
|
<div class="block">
|
||||||
<button
|
<button
|
||||||
style={{ justifyContent: 'space-between' }}
|
style={{ justifyContent: 'space-between' }}
|
||||||
class="button is-fullwidth"
|
class="button is-fullwidth"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!authAvailableSet.has(props.method)) {
|
|
||||||
//open add sms dialog
|
|
||||||
} else {
|
|
||||||
setSelectedMethod(props.method);
|
setSelectedMethod(props.method);
|
||||||
}
|
|
||||||
if (reducer) reducer.dismissError();
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
<span class="icon ">
|
<span class="icon ">
|
||||||
{authMethods[props.method].icon}
|
{authMethods[props.method].icon}
|
||||||
</span>
|
</span>
|
||||||
|
{authAvailableSet.has(props.method) ?
|
||||||
<span>
|
<span>
|
||||||
{authMethods[props.method].label}
|
Add a {authMethods[props.method].label} challenge
|
||||||
|
</span> :
|
||||||
|
<span>
|
||||||
|
Add a {authMethods[props.method].label} provider
|
||||||
</span>
|
</span>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
{!authAvailableSet.has(props.method) &&
|
{!authAvailableSet.has(props.method) &&
|
||||||
<span class="icon has-text-danger" >
|
<span class="icon has-text-danger" >
|
||||||
@ -111,41 +135,34 @@ export function AuthenticationEditorScreen(): VNode {
|
|||||||
return (
|
return (
|
||||||
<AnastasisClientFrame title="Backup: Configure Authentication Methods" hideNext={errors}>
|
<AnastasisClientFrame title="Backup: Configure Authentication Methods" hideNext={errors}>
|
||||||
<div class="columns">
|
<div class="columns">
|
||||||
<div class="column is-half">
|
<div class="column one-third">
|
||||||
<div>
|
<div>
|
||||||
{getKeys(authMethods).map(method => <MethodButton key={method} method={method} />)}
|
{getKeys(authMethods).map(method => <MethodButton key={method} method={method} />)}
|
||||||
</div>
|
</div>
|
||||||
{authAvailableSet.size === 0 && <ConfirmModal active={!noProvidersAck} onCancel={() => setNoProvidersAck(true)} description="No providers founds" label="Add a provider manually">
|
{authAvailableSet.size === 0 && <ConfirmModal active={!noProvidersAck}
|
||||||
|
onCancel={() => setNoProvidersAck(true)} description="No providers founds" label="Add a provider manually"
|
||||||
|
onConfirm={() => {
|
||||||
|
null
|
||||||
|
}}
|
||||||
|
>
|
||||||
We have found no trusted cloud providers for your recovery secret. You can add a provider manually.
|
We have found no trusted cloud providers for your recovery secret. You can add a provider manually.
|
||||||
To add a provider you must know the provider URL (e.g. https://provider.com)
|
To add a provider you must know the provider URL (e.g. https://provider.com)
|
||||||
<p>
|
<p>
|
||||||
<a>More about cloud providers</a>
|
<a>More about cloud providers</a>
|
||||||
</p>
|
</p>
|
||||||
</ConfirmModal>}
|
</ConfirmModal>}
|
||||||
|
|
||||||
{/* {haveMethodsConfigured && (
|
|
||||||
configuredAuthMethods.map((x, i) => {
|
|
||||||
return (
|
|
||||||
<p key={i}>
|
|
||||||
{x.type} ({x.instructions}){" "}
|
|
||||||
<button class="button is-danger is-small"
|
|
||||||
onClick={() => reducer.transition("delete_authentication", {
|
|
||||||
authentication_method: i,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
Remove
|
|
||||||
</button>
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
)} */}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-half">
|
<div class="column two-third">
|
||||||
|
<p class="block">
|
||||||
When recovering your wallet, you will be asked to verify your identity via the methods you configure here.
|
When recovering your wallet, you will be asked to verify your identity via the methods you configure here.
|
||||||
|
The list of authentication method is defined by the backup provider list.
|
||||||
<b>Explain the exclamation marks</b>
|
</p>
|
||||||
|
<p class="block">
|
||||||
<a>Explain how to add providers</a>
|
<button class="button is-info">Manage the backup provider's list</button>
|
||||||
|
</p>
|
||||||
|
{authAvailableSet.size > 0 && <p class="block">
|
||||||
|
We couldn't find provider for some of the authentication methods.
|
||||||
|
</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AnastasisClientFrame>
|
</AnastasisClientFrame>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
/* eslint-disable @typescript-eslint/camelcase */
|
/* eslint-disable @typescript-eslint/camelcase */
|
||||||
import { AuthMethod } from "anastasis-core";
|
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useAnastasisContext } from "../../context/anastasis";
|
import { useAnastasisContext } from "../../context/anastasis";
|
||||||
@ -51,8 +50,8 @@ export function ReviewPoliciesScreen(): VNode {
|
|||||||
{policies.length < 1 && <p class="block">
|
{policies.length < 1 && <p class="block">
|
||||||
No policies had been created. Go back and add more authentication methods.
|
No policies had been created. Go back and add more authentication methods.
|
||||||
</p>}
|
</p>}
|
||||||
<div class="block" onClick={() => setEditingPolicy(policies.length + 1)}>
|
<div class="block" style={{justifyContent:'flex-end'}} >
|
||||||
<button class="button is-success">Add new policy</button>
|
<button class="button is-success" onClick={() => setEditingPolicy(policies.length + 1)}>Add new policy</button>
|
||||||
</div>
|
</div>
|
||||||
{policies.map((p, policy_index) => {
|
{policies.map((p, policy_index) => {
|
||||||
const methods = p.methods
|
const methods = p.methods
|
||||||
|
@ -17,6 +17,7 @@ interface AuthMethodConfiguration {
|
|||||||
icon: VNode;
|
icon: VNode;
|
||||||
label: string;
|
label: string;
|
||||||
screen: (props: AuthMethodSetupProps) => VNode;
|
screen: (props: AuthMethodSetupProps) => VNode;
|
||||||
|
skip?: boolean;
|
||||||
}
|
}
|
||||||
export type KnownAuthMethods = "sms" | "email" | "post" | "question" | "video" | "totp" | "iban";
|
export type KnownAuthMethods = "sms" | "email" | "post" | "question" | "video" | "totp" | "iban";
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ export const authMethods: KnowMethodConfig = {
|
|||||||
video: {
|
video: {
|
||||||
icon: <img src={videoIcon} />,
|
icon: <img src={videoIcon} />,
|
||||||
label: "Video",
|
label: "Video",
|
||||||
screen: VideScreen
|
screen: VideScreen,
|
||||||
|
skip: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user