import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util";
import { FunctionalComponent, h } from "preact";
import { useState } from "preact/hooks";
import {
AnastasisReducerApi,
AuthMethod,
BackupStates,
ReducerStateBackup,
ReducerStateRecovery,
useAnastasisReducer,
} from "../../hooks/use-anastasis-reducer";
import style from "./style.css";
interface ContinentSelectionProps {
reducer: AnastasisReducerApi;
reducerState: ReducerStateBackup | ReducerStateRecovery;
}
function isBackup(reducer: AnastasisReducerApi) {
return !!reducer.currentReducerState?.backup_state;
}
function ContinentSelection(props: ContinentSelectionProps) {
const { reducer, reducerState } = props;
return (
{isBackup(reducer) ? "Backup" : "Recovery"}: Select Continent
{reducerState.continents.map((x: any) => {
const sel = (x: string) =>
reducer.transition("select_continent", { continent: x });
return (
sel(x.name)} key={x.name}>
{x.name}
);
})}
reducer.back()}>Back
);
}
interface CountrySelectionProps {
reducer: AnastasisReducerApi;
reducerState: ReducerStateBackup | ReducerStateRecovery;
}
function CountrySelection(props: CountrySelectionProps) {
const { reducer, reducerState } = props;
return (
Backup: Select Country
{reducerState.countries.map((x: any) => {
const sel = (x: any) =>
reducer.transition("select_country", {
country_code: x.code,
currencies: [x.currency],
});
return (
sel(x)} key={x.name}>
{x.name} ({x.currency})
);
})}
reducer.back()}>Back
);
}
const Home: FunctionalComponent = () => {
const reducer = useAnastasisReducer();
const reducerState = reducer.currentReducerState;
if (!reducerState) {
return (
Home
reducer.startBackup()}>
Backup
reducer.startRecover()}>Recover
);
}
console.log("state", reducer.currentReducerState);
if (reducerState.backup_state === BackupStates.ContinentSelecting) {
return ;
}
if (reducerState.backup_state === BackupStates.CountrySelecting) {
return ;
}
if (reducerState.backup_state === BackupStates.UserAttributesCollecting) {
return ;
}
if (reducerState.backup_state === BackupStates.AuthenticationsEditing) {
return (
);
}
if (reducerState.backup_state === BackupStates.PoliciesReviewing) {
const backupState: ReducerStateBackup = reducerState;
const authMethods = backupState.authentication_methods!;
return (
Backup: Review Recovery Policies
{backupState.policies?.map((p, i) => {
const policyName = p.methods
.map((x) => authMethods[x.authentication_method].type)
.join(" + ");
return (
Policy #{i + 1}: {policyName}
Required Authentications:
{p.methods.map((x) => {
const m = authMethods[x.authentication_method];
return (
{m.type} ({m.instructions}) at provider {x.provider}
);
})}
reducer.transition("delete_policy", { policy_index: i })
}
>
Delete Policy
);
})}
reducer.back()}>Back
reducer.transition("next", {})}>Next
);
}
if (reducerState.backup_state === BackupStates.SecretEditing) {
const [secretName, setSecretName] = useState("");
const [secretValue, setSecretValue] = useState("");
const secretNext = () => {
reducer.runTransaction(async (tx) => {
await tx.transition("enter_secret_name", {
name: secretName,
});
await tx.transition("enter_secret", {
secret: {
value: "EDJP6WK5EG50",
mime: "text/plain",
},
expiration: {
t_ms: new Date().getTime() + 1000 * 60 * 60 * 24 * 365 * 5,
},
});
await tx.transition("next", {});
});
};
return (
);
}
if (reducerState.backup_state === BackupStates.BackupFinished) {
const backupState: ReducerStateBackup = reducerState;
return (
Backup finished
Your backup of secret "{backupState.secret_name ?? "??"}" was
successful.
The backup is stored by the following providers:
{Object.keys(backupState.success_details).map((x, i) => {
const sd = backupState.success_details[x];
return (
{x} (Policy version {sd.policy_version})
);
})}
reducer.reset()}>
Start a new backup/recovery
);
}
if (reducerState.backup_state === BackupStates.TruthsPaying) {
const backupState: ReducerStateBackup = reducerState;
const payments = backupState.payments ?? [];
return (
Backup: Authentication Storage Payments
Some of the providers require a payment to store the encrypted
authentication information.
{payments.map((x) => {
return {x} ;
})}
reducer.back()}>Back
reducer.transition("pay", {})}>
Check payment(s)
);
}
if (reducerState.backup_state === BackupStates.PoliciesPaying) {
const backupState: ReducerStateBackup = reducerState;
const payments = backupState.policy_payment_requests ?? [];
return (
Backup: Recovery Document Payments
Some of the providers require a payment to store the encrypted
recovery document.
{payments.map((x) => {
return (
{x.provider}: {x.payto}
);
})}
reducer.back()}>Back
reducer.transition("pay", {})}>
Check payment(s)
);
}
console.log("unknown state", reducer.currentReducerState);
return (
Home
Bug: Unknown state.
reducer.reset()}>Reset
);
};
interface AuthMethodSetupProps {
method: string;
addAuthMethod: (x: any) => void;
cancel: () => void;
}
function AuthMethodSmsSetup(props: AuthMethodSetupProps) {
const [mobileNumber, setMobileNumber] = useState("");
return (
Add {props.method} authentication
);
}
function AuthMethodQuestionSetup(props: AuthMethodSetupProps) {
const [questionText, setQuestionText] = useState("");
const [answerText, setAnswerText] = useState("");
return (
Add {props.method} authentication
);
}
function AuthMethodNotImplemented(props: AuthMethodSetupProps) {
return (
Add {props.method} authentication
This auth method is not implemented yet, please choose another one.
props.cancel()}>Cancel
);
}
export interface AuthenticationEditorProps {
reducer: AnastasisReducerApi;
backupState: ReducerStateBackup;
}
function AuthenticationEditor(props: AuthenticationEditorProps) {
const [selectedMethod, setSelectedMethod] = useState(
undefined,
);
const { reducer, backupState } = props;
const providers = backupState.authentication_providers;
const authAvailableSet = new Set();
for (const provKey of Object.keys(providers)) {
const p = providers[provKey];
for (const meth of p.methods) {
authAvailableSet.add(meth.type);
}
}
if (selectedMethod) {
const cancel = () => setSelectedMethod(undefined);
const addMethod = (args: any) => {
reducer.transition("add_authentication", args);
setSelectedMethod(undefined);
};
switch (selectedMethod) {
case "sms":
return (
);
case "question":
return (
);
default:
return (
);
}
}
function MethodButton(props: { method: string; label: String }) {
return (
{
setSelectedMethod(props.method);
reducer.dismissError();
}}
>
{props.label}
);
}
const configuredAuthMethods: AuthMethod[] =
backupState.authentication_methods ?? [];
const haveMethodsConfigured = configuredAuthMethods.length;
return (
Backup: Configure Authentication Methods
Add authentication method
Configured authentication methods
{haveMethodsConfigured ? (
configuredAuthMethods.map((x, i) => {
return (
{x.type} ({x.instructions}){" "}
reducer.transition("delete_authentication", {
authentication_method: i,
})
}
>
Delete
);
})
) : (
No authentication methods configured yet.
)}
reducer.back()}>Back
reducer.transition("next", {})}>Next
);
}
export interface AttributeEntryProps {
reducer: AnastasisReducerApi;
backupState: ReducerStateBackup;
}
function AttributeEntry(props: AttributeEntryProps) {
const { reducer, backupState } = props;
const [attrs, setAttrs] = useState>({});
return (
Backup: Enter Basic User Attributes
{backupState.required_attributes.map((x: any, i: number) => {
return (
setAttrs({ ...attrs, [x.name]: v })}
spec={x}
value={attrs[x.name]}
/>
);
})}
reducer.back()}>Back
reducer.transition("enter_user_attributes", {
identity_attributes: attrs,
})
}
>
Next
);
}
export interface AttributeEntryFieldProps {
isFirst: boolean;
value: string;
setValue: (newValue: string) => void;
spec: any;
}
function AttributeEntryField(props: AttributeEntryFieldProps) {
return (
{props.spec.label}
props.setValue((e as any).target.value)}
/>
);
}
interface ErrorBannerProps {
reducer: AnastasisReducerApi;
}
/**
* Show a dismissable error banner if there is a current error.
*/
function ErrorBanner(props: ErrorBannerProps) {
const currentError = props.reducer.currentError;
if (currentError) {
return (
Error: {JSON.stringify(currentError)}
props.reducer.dismissError()}>
Dismiss Error
);
}
return null;
}
export default Home;