diff options
Diffstat (limited to 'packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx')
-rw-r--r-- | packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx | 113 |
1 files changed, 86 insertions, 27 deletions
diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx index a5235d66c..93a27837c 100644 --- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx @@ -1,65 +1,124 @@ -/* eslint-disable @typescript-eslint/camelcase */ +/* + This file is part of GNU Anastasis + (C) 2021-2022 Anastasis SARL + + GNU Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Anastasis 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ import { encodeCrock, stringToBytes } from "@gnu-taler/taler-util"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; -import { useAnastasisContext } from "../../context/anastasis"; import { - AnastasisClientFrame, - LabeledInput -} from "./index"; + FileInput, + FileTypeContent, +} from "../../components/fields/FileInput.js"; +import { TextInput } from "../../components/fields/TextInput.js"; +import { useAnastasisContext } from "../../context/anastasis.js"; +import { AnastasisClientFrame } from "./index.js"; export function SecretEditorScreen(): VNode { - const reducer = useAnastasisContext() + const reducer = useAnastasisContext(); const [secretValue, setSecretValue] = useState(""); + const [secretFile, _setSecretFile] = useState<FileTypeContent | undefined>( + undefined, + ); + function setSecretFile(v: FileTypeContent | undefined): void { + setSecretValue(""); // reset secret value when uploading a file + _setSecretFile(v); + } - const currentSecretName = reducer?.currentReducerState - && ("secret_name" in reducer.currentReducerState) - && reducer.currentReducerState.secret_name; + const currentSecretName = + reducer?.currentReducerState && + "secret_name" in reducer.currentReducerState && + reducer.currentReducerState.secret_name; const [secretName, setSecretName] = useState(currentSecretName || ""); - + if (!reducer) { - return <div>no reducer in context</div> + return <div>no reducer in context</div>; } - if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) { - return <div>invalid state</div> + if (reducer.currentReducerState?.reducer_type !== "backup") { + return <div>invalid state</div>; } - const secretNext = (): void => { - reducer.runTransaction(async (tx) => { + const secretNext = async (): Promise<void> => { + const secret = secretFile + ? { + value: encodeCrock(stringToBytes(secretFile.content)), + filename: secretFile.name, + mime: secretFile.type, + } + : { + value: encodeCrock(stringToBytes(secretValue)), + mime: "text/plain", + }; + return reducer.runTransaction(async (tx) => { await tx.transition("enter_secret_name", { name: secretName, }); await tx.transition("enter_secret", { - secret: { - value: encodeCrock(stringToBytes(secretValue)), - mime: "text/plain", - }, + secret, expiration: { - t_ms: new Date().getTime() + 1000 * 60 * 60 * 24 * 365 * 5, + t_s: new Date().getTime() + 60 * 60 * 24 * 365 * 5, }, }); await tx.transition("next", {}); }); }; + const errors = !secretName + ? "Add a secret name" + : !secretValue && !secretFile + ? "Add a secret value or a choose a file to upload" + : undefined; + function goNextIfNoErrors(): void { + if (!errors) secretNext(); + } return ( <AnastasisClientFrame - title="Backup: Provide secret" + hideNext={errors} + title="Backup: Provide secret to backup" onNext={() => secretNext()} > - <div> - <LabeledInput - label="Secret Name:" + <div class="block"> + <TextInput + label="Secret name:" + 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> - <LabeledInput - label="Secret Value:" + <div class="block"> + <TextInput + inputType="multiline" + disabled={!!secretFile} + onConfirm={goNextIfNoErrors} + label="Enter the secret as text:" bind={[secretValue, setSecretValue]} /> </div> + <div class="block"> + Or upload a secret file + <FileInput label="Choose file" onChange={setSecretFile} /> + {secretFile && ( + <div> + Uploading secret file <b>{secretFile.name}</b>{" "} + <a onClick={() => setSecretFile(undefined)}>cancel</a> + </div> + )} + </div> </AnastasisClientFrame> ); } |