mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-08 07:12:49 +00:00
[ENG-357] Automatically mount associated key during decryption (#564)
* auto-mount associated key during decryption based on content salt * use iterator directly * cleanup
This commit is contained in:
parent
5b78bbbb7d
commit
9c3aab2f70
|
@ -19,6 +19,7 @@ pub struct FileDecryptorJobState {}
|
||||||
pub struct FileDecryptorJobInit {
|
pub struct FileDecryptorJobInit {
|
||||||
pub location_id: i32,
|
pub location_id: i32,
|
||||||
pub path_id: i32,
|
pub path_id: i32,
|
||||||
|
pub mount_associated_key: bool,
|
||||||
pub output_path: Option<PathBuf>,
|
pub output_path: Option<PathBuf>,
|
||||||
pub password: Option<String>, // if this is set, we can assume the user chose password decryption
|
pub password: Option<String>, // if this is set, we can assume the user chose password decryption
|
||||||
pub save_to_library: Option<bool>,
|
pub save_to_library: Option<bool>,
|
||||||
|
@ -66,6 +67,7 @@ impl StatefulJob for FileDecryptorJob {
|
||||||
) -> Result<(), JobError> {
|
) -> Result<(), JobError> {
|
||||||
let step = &state.steps[0];
|
let step = &state.steps[0];
|
||||||
let info = &step.fs_info;
|
let info = &step.fs_info;
|
||||||
|
let key_manager = &ctx.library_ctx.key_manager;
|
||||||
|
|
||||||
// handle overwriting checks, and making sure there's enough available space
|
// handle overwriting checks, and making sure there's enough available space
|
||||||
let output_path = state.init.output_path.clone().map_or_else(
|
let output_path = state.init.output_path.clone().map_or_else(
|
||||||
|
@ -98,8 +100,7 @@ impl StatefulJob for FileDecryptorJob {
|
||||||
let index = header.find_key_index(password_bytes.clone()).await?;
|
let index = header.find_key_index(password_bytes.clone()).await?;
|
||||||
|
|
||||||
// inherit the encryption algorithm from the keyslot
|
// inherit the encryption algorithm from the keyslot
|
||||||
ctx.library_ctx
|
key_manager
|
||||||
.key_manager
|
|
||||||
.add_to_keystore(
|
.add_to_keystore(
|
||||||
Password::new(password),
|
Password::new(password),
|
||||||
header.algorithm,
|
header.algorithm,
|
||||||
|
@ -118,7 +119,18 @@ impl StatefulJob for FileDecryptorJob {
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let keys = ctx.library_ctx.key_manager.enumerate_hashed_keys();
|
if state.init.mount_associated_key {
|
||||||
|
for key in key_manager.dump_keystore().iter().filter(|x| {
|
||||||
|
header
|
||||||
|
.keyslots
|
||||||
|
.iter()
|
||||||
|
.any(|k| k.content_salt == x.content_salt)
|
||||||
|
}) {
|
||||||
|
key_manager.mount(key.uuid).await.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let keys = key_manager.enumerate_hashed_keys();
|
||||||
|
|
||||||
header.decrypt_master_key_from_prehashed(keys).await?
|
header.decrypt_master_key_from_prehashed(keys).await?
|
||||||
};
|
};
|
||||||
|
|
|
@ -107,7 +107,7 @@ export interface FileCopierJobInit { source_location_id: number, source_path_id:
|
||||||
|
|
||||||
export interface FileCutterJobInit { source_location_id: number, source_path_id: number, target_location_id: number, target_path: string }
|
export interface FileCutterJobInit { source_location_id: number, source_path_id: number, target_location_id: number, target_path: string }
|
||||||
|
|
||||||
export interface FileDecryptorJobInit { location_id: number, path_id: number, output_path: string | null, password: string | null, save_to_library: boolean | null }
|
export interface FileDecryptorJobInit { location_id: number, path_id: number, mount_associated_key: boolean, output_path: string | null, password: string | null, save_to_library: boolean | null }
|
||||||
|
|
||||||
export interface FileDeleterJobInit { location_id: number, path_id: number }
|
export interface FileDeleterJobInit { location_id: number, path_id: number }
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ interface DecryptDialogProps extends UseDialogProps {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
type: z.union([z.literal('password'), z.literal('key')]),
|
type: z.union([z.literal('password'), z.literal('key')]),
|
||||||
outputPath: z.string(),
|
outputPath: z.string(),
|
||||||
|
mountAssociatedKey: z.boolean(),
|
||||||
password: z.string(),
|
password: z.string(),
|
||||||
saveToKeyManager: z.boolean()
|
saveToKeyManager: z.boolean()
|
||||||
});
|
});
|
||||||
|
@ -63,7 +64,8 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
type: hasMountedKeys ? 'key' : 'password',
|
type: hasMountedKeys ? 'key' : 'password',
|
||||||
saveToKeyManager: true,
|
saveToKeyManager: true,
|
||||||
outputPath: '',
|
outputPath: '',
|
||||||
password: ''
|
password: '',
|
||||||
|
mountAssociatedKey: true
|
||||||
},
|
},
|
||||||
schema
|
schema
|
||||||
});
|
});
|
||||||
|
@ -73,6 +75,7 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
location_id: props.location_id,
|
location_id: props.location_id,
|
||||||
path_id: props.path_id,
|
path_id: props.path_id,
|
||||||
output_path: data.outputPath !== '' ? data.outputPath : null,
|
output_path: data.outputPath !== '' ? data.outputPath : null,
|
||||||
|
mount_associated_key: data.mountAssociatedKey,
|
||||||
password: data.type === 'password' ? data.password : null,
|
password: data.type === 'password' ? data.password : null,
|
||||||
save_to_library: data.type === 'password' ? data.saveToKeyManager : null
|
save_to_library: data.type === 'password' ? data.saveToKeyManager : null
|
||||||
})
|
})
|
||||||
|
@ -117,6 +120,24 @@ export const DecryptFileDialog = (props: DecryptDialogProps) => {
|
||||||
</div>
|
</div>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
|
||||||
|
{form.watch('type') === 'key' && (
|
||||||
|
<div className="relative flex flex-grow mt-3 mb-2">
|
||||||
|
<div className="space-x-2">
|
||||||
|
<Switch
|
||||||
|
className="bg-app-selected"
|
||||||
|
size="sm"
|
||||||
|
name=""
|
||||||
|
checked={form.watch('mountAssociatedKey')}
|
||||||
|
onCheckedChange={(e) => form.setValue('mountAssociatedKey', e)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="ml-3 text-xs font-medium mt-0.5">Automatically mount key</span>
|
||||||
|
<Tooltip label="The key linked with the file will be automatically mounted">
|
||||||
|
<Info className="w-4 h-4 ml-1.5 text-ink-faint mt-0.5" />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{form.watch('type') === '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">
|
||||||
|
|
Loading…
Reference in a new issue