mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-18 22:29:11 +00:00
[ENG-329] Crypto dialog refactor (#509)
* update backup restoration dialog * restructure MPC dialog * refactor `EncryptFileDialog` * dialog changes Co-authored-by: Brendan Allan <brendonovich@outlook.com>
This commit is contained in:
parent
50b788f9e6
commit
434bc81deb
|
@ -2,7 +2,7 @@ import { useLibraryMutation } from '@sd/client';
|
||||||
import { Button, Dialog, Input } from '@sd/ui';
|
import { Button, Dialog, Input } from '@sd/ui';
|
||||||
import { Eye, EyeSlash } from 'phosphor-react';
|
import { Eye, EyeSlash } from 'phosphor-react';
|
||||||
import { ReactNode, useState } from 'react';
|
import { ReactNode, useState } from 'react';
|
||||||
import { SubmitHandler, useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { usePlatform } from '../../util/Platform';
|
import { usePlatform } from '../../util/Platform';
|
||||||
import { GenericAlertDialogProps } from './AlertDialog';
|
import { GenericAlertDialogProps } from './AlertDialog';
|
||||||
|
@ -20,6 +20,39 @@ export interface BackupRestorationDialogProps {
|
||||||
|
|
||||||
export const BackupRestoreDialog = (props: BackupRestorationDialogProps) => {
|
export const BackupRestoreDialog = (props: BackupRestorationDialogProps) => {
|
||||||
const platform = usePlatform();
|
const platform = usePlatform();
|
||||||
|
|
||||||
|
const restoreKeystoreMutation = useLibraryMutation('keys.restoreKeystore', {
|
||||||
|
onSuccess: (total) => {
|
||||||
|
setShow((old) => ({ ...old, backupRestoreDialog: false }));
|
||||||
|
props.setAlertDialogData({
|
||||||
|
open: true,
|
||||||
|
title: 'Import Successful',
|
||||||
|
description: '',
|
||||||
|
value: `${total} ${total !== 1 ? 'keys were imported.' : 'key was imported.'}`,
|
||||||
|
inputBox: false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
setShow((old) => ({ ...old, backupRestoreDialog: false }));
|
||||||
|
props.setAlertDialogData({
|
||||||
|
open: true,
|
||||||
|
title: 'Import Error',
|
||||||
|
description: '',
|
||||||
|
value: 'There was an error while restoring your backup.',
|
||||||
|
inputBox: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [show, setShow] = useState({
|
||||||
|
backupRestoreDialog: false,
|
||||||
|
masterPassword: false,
|
||||||
|
secretKey: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const MPCurrentEyeIcon = show.masterPassword ? EyeSlash : Eye;
|
||||||
|
const SKCurrentEyeIcon = show.secretKey ? EyeSlash : Eye;
|
||||||
|
|
||||||
const form = useForm<FormValues>({
|
const form = useForm<FormValues>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
masterPassword: '',
|
masterPassword: '',
|
||||||
|
@ -28,124 +61,89 @@ export const BackupRestoreDialog = (props: BackupRestorationDialogProps) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit: SubmitHandler<FormValues> = (data) => {
|
const onSubmit = form.handleSubmit((data) => {
|
||||||
const sk = data.secretKey || null;
|
const sk = data.secretKey || null;
|
||||||
|
|
||||||
if (data.filePath !== '') {
|
if (data.filePath !== '') {
|
||||||
restoreKeystoreMutation.mutate(
|
restoreKeystoreMutation.mutate({
|
||||||
{
|
password: data.masterPassword,
|
||||||
password: data.masterPassword,
|
secret_key: sk,
|
||||||
secret_key: sk,
|
path: data.filePath
|
||||||
path: data.filePath
|
});
|
||||||
},
|
|
||||||
{
|
|
||||||
onSuccess: (total) => {
|
|
||||||
setShowBackupRestoreDialog(false);
|
|
||||||
props.setAlertDialogData({
|
|
||||||
open: true,
|
|
||||||
title: 'Import Successful',
|
|
||||||
description: '',
|
|
||||||
value: `${total} ${total !== 1 ? 'keys were imported.' : 'key was imported.'}`,
|
|
||||||
inputBox: false
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
setShowBackupRestoreDialog(false);
|
|
||||||
props.setAlertDialogData({
|
|
||||||
open: true,
|
|
||||||
title: 'Import Error',
|
|
||||||
description: '',
|
|
||||||
value: 'There was an error while restoring your backup.',
|
|
||||||
inputBox: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
form.reset();
|
form.reset();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const [showBackupRestoreDialog, setShowBackupRestoreDialog] = useState(false);
|
|
||||||
const restoreKeystoreMutation = useLibraryMutation('keys.restoreKeystore');
|
|
||||||
|
|
||||||
const [showMasterPassword, setShowMasterPassword] = useState(false);
|
|
||||||
const [showSecretKey, setShowSecretKey] = useState(false);
|
|
||||||
|
|
||||||
const MPCurrentEyeIcon = showMasterPassword ? EyeSlash : Eye;
|
|
||||||
const SKCurrentEyeIcon = showSecretKey ? EyeSlash : Eye;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<form onSubmit={onSubmit}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
<Dialog
|
||||||
<Dialog
|
open={show.backupRestoreDialog}
|
||||||
open={showBackupRestoreDialog}
|
setOpen={(e) => setShow((old) => ({ ...old, backupRestoreDialog: e }))}
|
||||||
setOpen={setShowBackupRestoreDialog}
|
title="Restore Keys"
|
||||||
title="Restore Keys"
|
description="Restore keys from a backup."
|
||||||
description="Restore keys from a backup."
|
loading={restoreKeystoreMutation.isLoading}
|
||||||
loading={restoreKeystoreMutation.isLoading}
|
ctaLabel="Restore"
|
||||||
ctaLabel="Restore"
|
trigger={props.trigger}
|
||||||
trigger={props.trigger}
|
>
|
||||||
>
|
<div className="relative flex flex-grow mt-3 mb-2">
|
||||||
<div className="relative flex flex-grow mt-3 mb-2">
|
<Input
|
||||||
<Input
|
className="flex-grow !py-0.5"
|
||||||
className="flex-grow !py-0.5"
|
placeholder="Master Password"
|
||||||
placeholder="Master Password"
|
required
|
||||||
required
|
type={show.masterPassword ? 'text' : 'password'}
|
||||||
type={showMasterPassword ? 'text' : 'password'}
|
{...form.register('masterPassword', { required: true })}
|
||||||
{...form.register('masterPassword', { required: true })}
|
/>
|
||||||
/>
|
<Button
|
||||||
<Button
|
onClick={() => setShow((old) => ({ ...old, masterPassword: !old.masterPassword }))}
|
||||||
onClick={() => setShowMasterPassword(!showMasterPassword)}
|
size="icon"
|
||||||
size="icon"
|
className="border-none absolute right-[5px] top-[5px]"
|
||||||
className="border-none absolute right-[5px] top-[5px]"
|
type="button"
|
||||||
type="button"
|
>
|
||||||
>
|
<MPCurrentEyeIcon className="w-4 h-4" />
|
||||||
<MPCurrentEyeIcon className="w-4 h-4" />
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
<div className="relative flex flex-grow mb-3">
|
||||||
<div className="relative flex flex-grow mb-3">
|
<Input
|
||||||
<Input
|
className="flex-grow !py-0.5"
|
||||||
className="flex-grow !py-0.5"
|
placeholder="Secret Key"
|
||||||
placeholder="Secret Key"
|
{...form.register('secretKey', { required: false })}
|
||||||
{...form.register('secretKey', { required: false })}
|
type={show.secretKey ? 'text' : 'password'}
|
||||||
type={showSecretKey ? 'text' : 'password'}
|
/>
|
||||||
/>
|
<Button
|
||||||
<Button
|
onClick={() => setShow((old) => ({ ...old, secretKey: !old.secretKey }))}
|
||||||
onClick={() => setShowSecretKey(!showSecretKey)}
|
size="icon"
|
||||||
size="icon"
|
className="border-none absolute right-[5px] top-[5px]"
|
||||||
className="border-none absolute right-[5px] top-[5px]"
|
type="button"
|
||||||
type="button"
|
>
|
||||||
>
|
<SKCurrentEyeIcon className="w-4 h-4" />
|
||||||
<SKCurrentEyeIcon className="w-4 h-4" />
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
<div className="relative flex flex-grow mb-2">
|
||||||
<div className="relative flex flex-grow mb-2">
|
<Button
|
||||||
<Button
|
size="sm"
|
||||||
size="sm"
|
variant={form.watch('filePath') !== '' ? 'accent' : 'gray'}
|
||||||
variant={form.watch('filePath') !== '' ? 'accent' : 'gray'}
|
type="button"
|
||||||
type="button"
|
onClick={() => {
|
||||||
onClick={() => {
|
if (!platform.openFilePickerDialog) {
|
||||||
if (!platform.openFilePickerDialog) {
|
// TODO: Support opening locations on web
|
||||||
// TODO: Support opening locations on web
|
props.setAlertDialogData({
|
||||||
props.setAlertDialogData({
|
open: true,
|
||||||
open: true,
|
title: 'Error',
|
||||||
title: 'Error',
|
description: '',
|
||||||
description: '',
|
value: "System dialogs aren't supported on this platform.",
|
||||||
value: "System dialogs aren't supported on this platform.",
|
inputBox: false
|
||||||
inputBox: false
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
platform.openFilePickerDialog().then((result) => {
|
|
||||||
if (result) form.setValue('filePath', result as string);
|
|
||||||
});
|
});
|
||||||
}}
|
return;
|
||||||
>
|
}
|
||||||
Select File
|
platform.openFilePickerDialog().then((result) => {
|
||||||
</Button>
|
if (result) form.setValue('filePath', result as string);
|
||||||
</div>
|
});
|
||||||
</Dialog>
|
}}
|
||||||
</form>
|
>
|
||||||
</>
|
Select File
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { useLibraryMutation, useLibraryQuery } from '@sd/client';
|
||||||
import { Button, Dialog, Input, Switch } from '@sd/ui';
|
import { Button, Dialog, Input, Switch } from '@sd/ui';
|
||||||
import { Eye, EyeSlash, Info } from 'phosphor-react';
|
import { Eye, EyeSlash, Info } from 'phosphor-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { usePlatform } from '../../util/Platform';
|
import { usePlatform } from '../../util/Platform';
|
||||||
import { Tooltip } from '../tooltip/Tooltip';
|
import { Tooltip } from '../tooltip/Tooltip';
|
||||||
|
@ -16,23 +17,23 @@ interface DecryptDialogProps {
|
||||||
setAlertDialogData: (data: GenericAlertDialogProps) => void;
|
setAlertDialogData: (data: GenericAlertDialogProps) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormValues = {
|
||||||
|
type: 'password' | 'key';
|
||||||
|
outputPath: string;
|
||||||
|
password: string;
|
||||||
|
saveToKeyManager: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
const platform = usePlatform();
|
const platform = usePlatform();
|
||||||
const { location_id, path_id } = props;
|
|
||||||
const decryptFile = useLibraryMutation('files.decryptFiles');
|
|
||||||
const [outputPath, setOutputpath] = useState('');
|
|
||||||
const [password, setPassword] = useState('');
|
|
||||||
const [saveToKeyManager, setSaveToKeyManager] = useState(true);
|
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
|
||||||
const PasswordCurrentEyeIcon = showPassword ? EyeSlash : Eye;
|
|
||||||
|
|
||||||
const mountedUuids = useLibraryQuery(['keys.listMounted'], {
|
const mountedUuids = useLibraryQuery(['keys.listMounted'], {
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
hasMountedKeys = data.length > 0 ? true : false;
|
hasMountedKeys = data.length > 0 ? true : false;
|
||||||
if (!hasMountedKeys) {
|
if (!hasMountedKeys) {
|
||||||
setDecryptType('password');
|
form.setValue('type', 'password');
|
||||||
} else {
|
} else {
|
||||||
setDecryptType('key');
|
form.setValue('type', 'key');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -40,10 +41,63 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
let hasMountedKeys =
|
let hasMountedKeys =
|
||||||
mountedUuids.data !== undefined && mountedUuids.data.length > 0 ? true : false;
|
mountedUuids.data !== undefined && mountedUuids.data.length > 0 ? true : false;
|
||||||
|
|
||||||
const [decryptType, setDecryptType] = useState(hasMountedKeys ? 'key' : 'password');
|
const decryptFile = useLibraryMutation('files.decryptFiles', {
|
||||||
|
onSuccess: () => {
|
||||||
|
props.setAlertDialogData({
|
||||||
|
open: true,
|
||||||
|
title: 'Info',
|
||||||
|
value:
|
||||||
|
'The decryption job has started successfully. You may track the progress in the job overview panel.',
|
||||||
|
inputBox: false,
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
props.setAlertDialogData({
|
||||||
|
open: true,
|
||||||
|
title: 'Error',
|
||||||
|
value: 'The decryption job failed to start.',
|
||||||
|
inputBox: false,
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const [show, setShow] = useState({ password: false });
|
||||||
|
|
||||||
|
const PasswordCurrentEyeIcon = show.password ? EyeSlash : Eye;
|
||||||
|
|
||||||
|
const form = useForm<FormValues>({
|
||||||
|
defaultValues: {
|
||||||
|
type: hasMountedKeys ? 'key' : 'password',
|
||||||
|
outputPath: '',
|
||||||
|
password: '',
|
||||||
|
saveToKeyManager: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = form.handleSubmit((data) => {
|
||||||
|
const output = data.outputPath !== '' ? data.outputPath : null;
|
||||||
|
const pw = data.type === 'password' ? data.password : null;
|
||||||
|
const save = data.type === 'password' ? data.saveToKeyManager : null;
|
||||||
|
|
||||||
|
props.setOpen(false);
|
||||||
|
|
||||||
|
props.location_id &&
|
||||||
|
props.path_id &&
|
||||||
|
decryptFile.mutate({
|
||||||
|
location_id: props.location_id,
|
||||||
|
path_id: props.path_id,
|
||||||
|
output_path: output,
|
||||||
|
password: pw,
|
||||||
|
save_to_library: save
|
||||||
|
});
|
||||||
|
|
||||||
|
form.reset();
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<form onSubmit={onSubmit}>
|
||||||
<Dialog
|
<Dialog
|
||||||
open={props.open}
|
open={props.open}
|
||||||
setOpen={props.setOpen}
|
setOpen={props.setOpen}
|
||||||
|
@ -51,48 +105,12 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
description="Leave the output file blank for the default."
|
description="Leave the output file blank for the default."
|
||||||
loading={decryptFile.isLoading}
|
loading={decryptFile.isLoading}
|
||||||
ctaLabel="Decrypt"
|
ctaLabel="Decrypt"
|
||||||
ctaAction={() => {
|
|
||||||
const output = outputPath !== '' ? outputPath : null;
|
|
||||||
const pw = decryptType === 'password' ? password : null;
|
|
||||||
const save = decryptType === 'password' ? saveToKeyManager : null;
|
|
||||||
|
|
||||||
props.setOpen(false);
|
|
||||||
|
|
||||||
location_id &&
|
|
||||||
path_id &&
|
|
||||||
decryptFile.mutate(
|
|
||||||
{
|
|
||||||
location_id,
|
|
||||||
path_id,
|
|
||||||
output_path: output,
|
|
||||||
password: pw,
|
|
||||||
save_to_library: save
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onSuccess: () => {
|
|
||||||
props.setAlertDialogData({
|
|
||||||
open: true,
|
|
||||||
title: 'Info',
|
|
||||||
value:
|
|
||||||
'The decryption job has started successfully. You may track the progress in the job overview panel.',
|
|
||||||
inputBox: false,
|
|
||||||
description: ''
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
props.setAlertDialogData({
|
|
||||||
open: true,
|
|
||||||
title: 'Error',
|
|
||||||
value: 'The decryption job failed to start.',
|
|
||||||
inputBox: false,
|
|
||||||
description: ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<RadioGroup value={decryptType} onChange={setDecryptType} className="mt-2">
|
<RadioGroup
|
||||||
|
value={form.watch('type')}
|
||||||
|
onChange={(e: 'key' | 'password') => form.setValue('type', e)}
|
||||||
|
className="mt-2"
|
||||||
|
>
|
||||||
<span className="text-xs font-bold">Key Type</span>
|
<span className="text-xs font-bold">Key Type</span>
|
||||||
<div className="flex flex-row gap-2 mt-2">
|
<div className="flex flex-row gap-2 mt-2">
|
||||||
<RadioGroup.Option disabled={!hasMountedKeys} value="key">
|
<RadioGroup.Option disabled={!hasMountedKeys} value="key">
|
||||||
|
@ -117,19 +135,18 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
{decryptType === 'password' && (
|
{form.watch('type') === 'password' && (
|
||||||
<>
|
<>
|
||||||
<div className="relative flex flex-grow mt-3 mb-2">
|
<div className="relative flex flex-grow mt-3 mb-2">
|
||||||
<Input
|
<Input
|
||||||
className={`flex-grow w-max !py-0.5`}
|
className={`flex-grow w-max !py-0.5`}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
{...form.register('password', { required: false })}
|
||||||
value={password}
|
type={show.password ? 'text' : 'password'}
|
||||||
type={showPassword ? 'text' : 'password'}
|
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setShowPassword(!showPassword)}
|
onClick={() => setShow((old) => ({ ...old, password: !old.password }))}
|
||||||
size="icon"
|
size="icon"
|
||||||
className="border-none absolute right-[5px] top-[5px]"
|
className="border-none absolute right-[5px] top-[5px]"
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -143,8 +160,8 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
<Switch
|
<Switch
|
||||||
className="bg-app-selected"
|
className="bg-app-selected"
|
||||||
size="sm"
|
size="sm"
|
||||||
checked={saveToKeyManager}
|
checked={form.watch('saveToKeyManager')}
|
||||||
onCheckedChange={setSaveToKeyManager}
|
onCheckedChange={(e) => form.setValue('saveToKeyManager', e)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="ml-3 text-xs font-medium mt-0.5">Save to Key Manager</span>
|
<span className="ml-3 text-xs font-medium mt-0.5">Save to Key Manager</span>
|
||||||
|
@ -161,7 +178,7 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={outputPath !== '' ? 'accent' : 'gray'}
|
variant={form.watch('outputPath') !== '' ? 'accent' : 'gray'}
|
||||||
className="h-[23px] text-xs leading-3 mt-2"
|
className="h-[23px] text-xs leading-3 mt-2"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -178,7 +195,7 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
platform.saveFilePickerDialog().then((result) => {
|
platform.saveFilePickerDialog().then((result) => {
|
||||||
if (result) setOutputpath(result as string);
|
if (result) form.setValue('outputPath', result as string);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -187,6 +204,6 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Algorithm, useLibraryMutation, useLibraryQuery } from '@sd/client';
|
import { Algorithm, useLibraryMutation, useLibraryQuery } from '@sd/client';
|
||||||
import { Button, Dialog, Select, SelectOption } from '@sd/ui';
|
import { Button, Dialog, Select, SelectOption } from '@sd/ui';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
|
||||||
import { getHashingAlgorithmString } from '../../screens/settings/library/KeysSetting';
|
import { getHashingAlgorithmString } from '../../screens/settings/library/KeysSetting';
|
||||||
import { usePlatform } from '../../util/Platform';
|
import { usePlatform } from '../../util/Platform';
|
||||||
|
@ -16,19 +17,25 @@ interface EncryptDialogProps {
|
||||||
setAlertDialogData: (data: GenericAlertDialogProps) => void;
|
setAlertDialogData: (data: GenericAlertDialogProps) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormValues = {
|
||||||
|
key: string;
|
||||||
|
encryptionAlgo: string;
|
||||||
|
hashingAlgo: string;
|
||||||
|
metadata: boolean;
|
||||||
|
previewMedia: boolean;
|
||||||
|
outputPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
const { location_id, path_id } = props;
|
|
||||||
const platform = usePlatform();
|
const platform = usePlatform();
|
||||||
|
|
||||||
// the selected key will be random, we should prioritise the default
|
const UpdateKey = (uuid: string) => {
|
||||||
const [key, setKey] = useState('');
|
form.setValue('key', uuid);
|
||||||
|
const hashAlg = keys.data?.find((key) => {
|
||||||
// decided against react-hook-form, as it doesn't allow us to work with select boxes and such
|
return key.uuid === uuid;
|
||||||
const [metadata, setMetadata] = useState(false);
|
})?.hashing_algorithm;
|
||||||
const [previewMedia, setPreviewMedia] = useState(false);
|
hashAlg && form.setValue('hashingAlgo', getHashingAlgorithmString(hashAlg));
|
||||||
const [encryptionAlgo, setEncryptionAlgo] = useState('XChaCha20Poly1305');
|
};
|
||||||
const [hashingAlgo, setHashingAlgo] = useState('');
|
|
||||||
const [outputPath, setOutputpath] = useState('');
|
|
||||||
|
|
||||||
const keys = useLibraryQuery(['keys.list']);
|
const keys = useLibraryQuery(['keys.list']);
|
||||||
const mountedUuids = useLibraryQuery(['keys.listMounted'], {
|
const mountedUuids = useLibraryQuery(['keys.listMounted'], {
|
||||||
|
@ -37,18 +44,60 @@ export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const UpdateKey = (uuid: string) => {
|
const encryptFile = useLibraryMutation('files.encryptFiles', {
|
||||||
setKey(uuid);
|
onSuccess: () => {
|
||||||
const hashAlg = keys.data?.find((key) => {
|
props.setAlertDialogData({
|
||||||
return key.uuid === uuid;
|
open: true,
|
||||||
})?.hashing_algorithm;
|
title: 'Success',
|
||||||
hashAlg && setHashingAlgo(getHashingAlgorithmString(hashAlg));
|
value:
|
||||||
};
|
'The encryption job has started successfully. You may track the progress in the job overview panel.',
|
||||||
|
inputBox: false,
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
props.setAlertDialogData({
|
||||||
|
open: true,
|
||||||
|
title: 'Error',
|
||||||
|
value: 'The encryption job failed to start.',
|
||||||
|
inputBox: false,
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const encryptFile = useLibraryMutation('files.encryptFiles');
|
const form = useForm<FormValues>({
|
||||||
|
defaultValues: {
|
||||||
|
key: '',
|
||||||
|
encryptionAlgo: 'XChaCha20Poly1305',
|
||||||
|
hashingAlgo: 'Argon2id-s',
|
||||||
|
metadata: false,
|
||||||
|
previewMedia: false,
|
||||||
|
outputPath: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = form.handleSubmit((data) => {
|
||||||
|
const output = data.outputPath !== '' ? data.outputPath : null;
|
||||||
|
props.setOpen(false);
|
||||||
|
|
||||||
|
props.location_id &&
|
||||||
|
props.path_id &&
|
||||||
|
encryptFile.mutate({
|
||||||
|
algorithm: data.encryptionAlgo as Algorithm,
|
||||||
|
key_uuid: data.key,
|
||||||
|
location_id: props.location_id,
|
||||||
|
path_id: props.path_id,
|
||||||
|
metadata: data.metadata,
|
||||||
|
preview_media: data.previewMedia,
|
||||||
|
output_path: output
|
||||||
|
});
|
||||||
|
|
||||||
|
form.reset();
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<form onSubmit={onSubmit}>
|
||||||
<Dialog
|
<Dialog
|
||||||
open={props.open}
|
open={props.open}
|
||||||
setOpen={props.setOpen}
|
setOpen={props.setOpen}
|
||||||
|
@ -56,52 +105,13 @@ export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
description="Configure your encryption settings. Leave the output file blank for the default."
|
description="Configure your encryption settings. Leave the output file blank for the default."
|
||||||
loading={encryptFile.isLoading}
|
loading={encryptFile.isLoading}
|
||||||
ctaLabel="Encrypt"
|
ctaLabel="Encrypt"
|
||||||
ctaAction={() => {
|
|
||||||
const output = outputPath !== '' ? outputPath : null;
|
|
||||||
props.setOpen(false);
|
|
||||||
|
|
||||||
location_id &&
|
|
||||||
path_id &&
|
|
||||||
encryptFile.mutate(
|
|
||||||
{
|
|
||||||
algorithm: encryptionAlgo as Algorithm,
|
|
||||||
key_uuid: key,
|
|
||||||
location_id,
|
|
||||||
path_id,
|
|
||||||
metadata,
|
|
||||||
preview_media: previewMedia,
|
|
||||||
output_path: output
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onSuccess: () => {
|
|
||||||
props.setAlertDialogData({
|
|
||||||
open: true,
|
|
||||||
title: 'Success',
|
|
||||||
value:
|
|
||||||
'The encryption job has started successfully. You may track the progress in the job overview panel.',
|
|
||||||
inputBox: false,
|
|
||||||
description: ''
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onError: () => {
|
|
||||||
props.setAlertDialogData({
|
|
||||||
open: true,
|
|
||||||
title: 'Error',
|
|
||||||
value: 'The encryption job failed to start.',
|
|
||||||
inputBox: false,
|
|
||||||
description: ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="text-xs font-bold">Key</span>
|
<span className="text-xs font-bold">Key</span>
|
||||||
<Select
|
<Select
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
value={key}
|
value={form.watch('key')}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
UpdateKey(e);
|
UpdateKey(e);
|
||||||
}}
|
}}
|
||||||
|
@ -114,7 +124,7 @@ export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
variant={outputPath !== '' ? 'accent' : 'gray'}
|
variant={form.watch('outputPath') !== '' ? 'accent' : 'gray'}
|
||||||
className="h-[23px] text-xs leading-3 mt-2"
|
className="h-[23px] text-xs leading-3 mt-2"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -131,7 +141,7 @@ export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
platform.saveFilePickerDialog().then((result) => {
|
platform.saveFilePickerDialog().then((result) => {
|
||||||
if (result) setOutputpath(result as string);
|
if (result) form.setValue('outputPath', result as string);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -143,7 +153,11 @@ export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="text-xs font-bold">Encryption</span>
|
<span className="text-xs font-bold">Encryption</span>
|
||||||
<Select className="mt-2" value={encryptionAlgo} onChange={(e) => setEncryptionAlgo(e)}>
|
<Select
|
||||||
|
className="mt-2"
|
||||||
|
value={form.watch('encryptionAlgo')}
|
||||||
|
onChange={(e) => form.setValue('encryptionAlgo', e)}
|
||||||
|
>
|
||||||
<SelectOption value="XChaCha20Poly1305">XChaCha20-Poly1305</SelectOption>
|
<SelectOption value="XChaCha20Poly1305">XChaCha20-Poly1305</SelectOption>
|
||||||
<SelectOption value="Aes256Gcm">AES-256-GCM</SelectOption>
|
<SelectOption value="Aes256Gcm">AES-256-GCM</SelectOption>
|
||||||
</Select>
|
</Select>
|
||||||
|
@ -154,7 +168,7 @@ export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
className="mt-2 text-gray-400/80"
|
className="mt-2 text-gray-400/80"
|
||||||
onChange={() => {}}
|
onChange={() => {}}
|
||||||
disabled
|
disabled
|
||||||
value={hashingAlgo}
|
value={form.watch('hashingAlgo')}
|
||||||
>
|
>
|
||||||
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
||||||
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
||||||
|
@ -169,14 +183,20 @@ export const EncryptFileDialog = (props: EncryptDialogProps) => {
|
||||||
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-sm font-bold mr-3 ml-0.5 mt-0.5">Metadata</span>
|
<span className="text-sm font-bold mr-3 ml-0.5 mt-0.5">Metadata</span>
|
||||||
<Checkbox checked={metadata} onChange={(e) => setMetadata(e.target.checked)} />
|
<Checkbox
|
||||||
|
checked={form.watch('metadata')}
|
||||||
|
onChange={(e) => form.setValue('metadata', e.target.checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<span className="text-sm font-bold mr-3 ml-0.5 mt-0.5">Preview Media</span>
|
<span className="text-sm font-bold mr-3 ml-0.5 mt-0.5">Preview Media</span>
|
||||||
<Checkbox checked={previewMedia} onChange={(e) => setPreviewMedia(e.target.checked)} />
|
<Checkbox
|
||||||
|
checked={form.watch('previewMedia')}
|
||||||
|
onChange={(e) => form.setValue('previewMedia', e.target.checked)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,18 +24,6 @@ type FormValues = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MasterPasswordChangeDialog = (props: MasterPasswordChangeDialogProps) => {
|
export const MasterPasswordChangeDialog = (props: MasterPasswordChangeDialogProps) => {
|
||||||
const { trigger } = props;
|
|
||||||
|
|
||||||
const form = useForm<FormValues>({
|
|
||||||
defaultValues: {
|
|
||||||
masterPassword: '',
|
|
||||||
masterPassword2: '',
|
|
||||||
secretKey: '',
|
|
||||||
encryptionAlgo: 'XChaCha20Poly1305',
|
|
||||||
hashingAlgo: 'Argon2id-s'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const changeMasterPassword = useLibraryMutation('keys.changeMasterPassword', {
|
const changeMasterPassword = useLibraryMutation('keys.changeMasterPassword', {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setShow((old) => ({ ...old, masterPasswordDialog: false }));
|
setShow((old) => ({ ...old, masterPasswordDialog: false }));
|
||||||
|
@ -71,6 +59,16 @@ export const MasterPasswordChangeDialog = (props: MasterPasswordChangeDialogProp
|
||||||
const MP2CurrentEyeIcon = show.masterPassword2 ? EyeSlash : Eye;
|
const MP2CurrentEyeIcon = show.masterPassword2 ? EyeSlash : Eye;
|
||||||
const SKCurrentEyeIcon = show.secretKey ? EyeSlash : Eye;
|
const SKCurrentEyeIcon = show.secretKey ? EyeSlash : Eye;
|
||||||
|
|
||||||
|
const form = useForm<FormValues>({
|
||||||
|
defaultValues: {
|
||||||
|
masterPassword: '',
|
||||||
|
masterPassword2: '',
|
||||||
|
secretKey: '',
|
||||||
|
encryptionAlgo: 'XChaCha20Poly1305',
|
||||||
|
hashingAlgo: 'Argon2id-s'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const onSubmit = form.handleSubmit((data) => {
|
const onSubmit = form.handleSubmit((data) => {
|
||||||
if (data.masterPassword !== data.masterPassword2) {
|
if (data.masterPassword !== data.masterPassword2) {
|
||||||
props.setAlertDialogData({
|
props.setAlertDialogData({
|
||||||
|
@ -96,153 +94,151 @@ export const MasterPasswordChangeDialog = (props: MasterPasswordChangeDialogProp
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<form onSubmit={onSubmit}>
|
||||||
<form onSubmit={onSubmit}>
|
<Dialog
|
||||||
<Dialog
|
open={show.masterPasswordDialog}
|
||||||
open={show.masterPasswordDialog}
|
setOpen={(e) => {
|
||||||
setOpen={(e) => {
|
setShow((old) => ({ ...old, masterPasswordDialog: e }));
|
||||||
setShow((old) => ({ ...old, masterPasswordDialog: e }));
|
}}
|
||||||
}}
|
title="Change Master Password"
|
||||||
title="Change Master Password"
|
description="Select a new master password for your key manager. Leave the key secret blank to disable it."
|
||||||
description="Select a new master password for your key manager. Leave the key secret blank to disable it."
|
ctaDanger={true}
|
||||||
ctaDanger={true}
|
loading={changeMasterPassword.isLoading}
|
||||||
loading={changeMasterPassword.isLoading}
|
ctaLabel="Change"
|
||||||
ctaLabel="Change"
|
trigger={props.trigger}
|
||||||
trigger={trigger}
|
>
|
||||||
>
|
<div className="relative flex flex-grow mt-3 mb-2">
|
||||||
<div className="relative flex flex-grow mt-3 mb-2">
|
<Input
|
||||||
<Input
|
className={`flex-grow w-max !py-0.5`}
|
||||||
className={`flex-grow w-max !py-0.5`}
|
placeholder="New password"
|
||||||
placeholder="New password"
|
required
|
||||||
required
|
{...form.register('masterPassword', { required: true })}
|
||||||
{...form.register('masterPassword', { required: true })}
|
type={show.masterPassword ? 'text' : 'password'}
|
||||||
type={show.masterPassword ? 'text' : 'password'}
|
/>
|
||||||
/>
|
<Button
|
||||||
<Button
|
onClick={() => {
|
||||||
onClick={() => {
|
const password = generatePassword(32);
|
||||||
const password = generatePassword(32);
|
form.setValue('masterPassword', password);
|
||||||
form.setValue('masterPassword', password);
|
form.setValue('masterPassword2', password);
|
||||||
form.setValue('masterPassword2', password);
|
setShow((old) => ({
|
||||||
setShow((old) => ({
|
...old,
|
||||||
...old,
|
masterPassword: true,
|
||||||
masterPassword: true,
|
masterPassword2: true
|
||||||
masterPassword2: true
|
}));
|
||||||
}));
|
}}
|
||||||
}}
|
size="icon"
|
||||||
size="icon"
|
className="border-none absolute right-[65px] top-[5px]"
|
||||||
className="border-none absolute right-[65px] top-[5px]"
|
type="button"
|
||||||
type="button"
|
>
|
||||||
>
|
<ArrowsClockwise className="w-4 h-4" />
|
||||||
<ArrowsClockwise className="w-4 h-4" />
|
</Button>
|
||||||
</Button>
|
<Button
|
||||||
<Button
|
type="button"
|
||||||
type="button"
|
onClick={() => {
|
||||||
onClick={() => {
|
navigator.clipboard.writeText(form.watch('masterPassword') as string);
|
||||||
navigator.clipboard.writeText(form.watch('masterPassword') as string);
|
}}
|
||||||
}}
|
size="icon"
|
||||||
size="icon"
|
className="border-none absolute right-[35px] top-[5px]"
|
||||||
className="border-none absolute right-[35px] top-[5px]"
|
>
|
||||||
>
|
<Clipboard className="w-4 h-4" />
|
||||||
<Clipboard className="w-4 h-4" />
|
</Button>
|
||||||
</Button>
|
<Button
|
||||||
<Button
|
onClick={() => setShow((old) => ({ ...old, masterPassword: !old.masterPassword }))}
|
||||||
onClick={() => setShow((old) => ({ ...old, masterPassword: !old.masterPassword }))}
|
size="icon"
|
||||||
size="icon"
|
className="border-none absolute right-[5px] top-[5px]"
|
||||||
className="border-none absolute right-[5px] top-[5px]"
|
type="button"
|
||||||
type="button"
|
>
|
||||||
>
|
<MP1CurrentEyeIcon className="w-4 h-4" />
|
||||||
<MP1CurrentEyeIcon className="w-4 h-4" />
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
<div className="relative flex flex-grow mb-2">
|
||||||
<div className="relative flex flex-grow mb-2">
|
<Input
|
||||||
<Input
|
className={`flex-grow !py-0.5}`}
|
||||||
className={`flex-grow !py-0.5}`}
|
placeholder="New password (again)"
|
||||||
placeholder="New password (again)"
|
required
|
||||||
required
|
{...form.register('masterPassword2', { required: true })}
|
||||||
{...form.register('masterPassword2', { required: true })}
|
type={show.masterPassword2 ? 'text' : 'password'}
|
||||||
type={show.masterPassword2 ? 'text' : 'password'}
|
/>
|
||||||
/>
|
<Button
|
||||||
<Button
|
onClick={() => setShow((old) => ({ ...old, masterPassword2: !old.masterPassword2 }))}
|
||||||
onClick={() => setShow((old) => ({ ...old, masterPassword2: !old.masterPassword2 }))}
|
size="icon"
|
||||||
size="icon"
|
className="border-none absolute right-[5px] top-[5px]"
|
||||||
className="border-none absolute right-[5px] top-[5px]"
|
type="button"
|
||||||
type="button"
|
>
|
||||||
>
|
<MP2CurrentEyeIcon className="w-4 h-4" />
|
||||||
<MP2CurrentEyeIcon className="w-4 h-4" />
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="relative flex flex-grow mb-2">
|
<div className="relative flex flex-grow mb-2">
|
||||||
<Input
|
<Input
|
||||||
className={`flex-grow !py-0.5}`}
|
className={`flex-grow !py-0.5}`}
|
||||||
placeholder="Key secret"
|
placeholder="Key secret"
|
||||||
{...form.register('secretKey', { required: false })}
|
{...form.register('secretKey', { required: false })}
|
||||||
type={show.secretKey ? 'text' : 'password'}
|
type={show.secretKey ? 'text' : 'password'}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
// onClick={() => setmasterPassword2(!masterPassword2)}
|
// onClick={() => setmasterPassword2(!masterPassword2)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
form.setValue('secretKey', cryptoRandomString({ length: 24 }));
|
form.setValue('secretKey', cryptoRandomString({ length: 24 }));
|
||||||
setShow((old) => ({ ...old, secretKey: true }));
|
setShow((old) => ({ ...old, secretKey: true }));
|
||||||
}}
|
}}
|
||||||
size="icon"
|
size="icon"
|
||||||
className="border-none absolute right-[65px] top-[5px]"
|
className="border-none absolute right-[65px] top-[5px]"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<ArrowsClockwise className="w-4 h-4" />
|
<ArrowsClockwise className="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(form.watch('secretKey') as string);
|
navigator.clipboard.writeText(form.watch('secretKey') as string);
|
||||||
}}
|
}}
|
||||||
size="icon"
|
size="icon"
|
||||||
className="border-none absolute right-[35px] top-[5px]"
|
className="border-none absolute right-[35px] top-[5px]"
|
||||||
>
|
>
|
||||||
<Clipboard className="w-4 h-4" />
|
<Clipboard className="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setShow((old) => ({ ...old, secretKey: !old.secretKey }))}
|
onClick={() => setShow((old) => ({ ...old, secretKey: !old.secretKey }))}
|
||||||
size="icon"
|
size="icon"
|
||||||
className="border-none absolute right-[5px] top-[5px]"
|
className="border-none absolute right-[5px] top-[5px]"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
<SKCurrentEyeIcon className="w-4 h-4" />
|
<SKCurrentEyeIcon className="w-4 h-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PasswordMeter password={form.watch('masterPassword')} />
|
<PasswordMeter password={form.watch('masterPassword')} />
|
||||||
|
|
||||||
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
<div className="grid w-full grid-cols-2 gap-4 mt-4 mb-3">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="text-xs font-bold">Encryption</span>
|
<span className="text-xs font-bold">Encryption</span>
|
||||||
<Select
|
<Select
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
value={form.watch('encryptionAlgo')}
|
value={form.watch('encryptionAlgo')}
|
||||||
onChange={(e) => form.setValue('encryptionAlgo', e)}
|
onChange={(e) => form.setValue('encryptionAlgo', e)}
|
||||||
>
|
>
|
||||||
<SelectOption value="XChaCha20Poly1305">XChaCha20-Poly1305</SelectOption>
|
<SelectOption value="XChaCha20Poly1305">XChaCha20-Poly1305</SelectOption>
|
||||||
<SelectOption value="Aes256Gcm">AES-256-GCM</SelectOption>
|
<SelectOption value="Aes256Gcm">AES-256-GCM</SelectOption>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
|
||||||
<div className="flex flex-col">
|
|
||||||
<span className="text-xs font-bold">Hashing</span>
|
|
||||||
<Select
|
|
||||||
className="mt-2"
|
|
||||||
value={form.watch('hashingAlgo')}
|
|
||||||
onChange={(e) => form.setValue('hashingAlgo', e)}
|
|
||||||
>
|
|
||||||
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
|
||||||
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
|
||||||
<SelectOption value="Argon2id-p">Argon2id (paranoid)</SelectOption>
|
|
||||||
<SelectOption value="BalloonBlake3-s">BLAKE3-Balloon (standard)</SelectOption>
|
|
||||||
<SelectOption value="BalloonBlake3-h">BLAKE3-Balloon (hardened)</SelectOption>
|
|
||||||
<SelectOption value="BalloonBlake3-p">BLAKE3-Balloon (paranoid)</SelectOption>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Dialog>
|
<div className="flex flex-col">
|
||||||
</form>
|
<span className="text-xs font-bold">Hashing</span>
|
||||||
</>
|
<Select
|
||||||
|
className="mt-2"
|
||||||
|
value={form.watch('hashingAlgo')}
|
||||||
|
onChange={(e) => form.setValue('hashingAlgo', e)}
|
||||||
|
>
|
||||||
|
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
||||||
|
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
||||||
|
<SelectOption value="Argon2id-p">Argon2id (paranoid)</SelectOption>
|
||||||
|
<SelectOption value="BalloonBlake3-s">BLAKE3-Balloon (standard)</SelectOption>
|
||||||
|
<SelectOption value="BalloonBlake3-h">BLAKE3-Balloon (hardened)</SelectOption>
|
||||||
|
<SelectOption value="BalloonBlake3-p">BLAKE3-Balloon (paranoid)</SelectOption>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Dialog>
|
||||||
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue