mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-25 10:18:31 +02:00
Add option to disable encryption when key is forgotten (#371)
This commit is contained in:
@@ -100,6 +100,15 @@ pub(crate) async fn cmd_set_workspace_key<R: Runtime>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[command]
|
||||||
|
pub(crate) async fn cmd_disable_encryption<R: Runtime>(
|
||||||
|
window: WebviewWindow<R>,
|
||||||
|
workspace_id: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
window.crypto().disable_encryption(workspace_id)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
pub(crate) fn cmd_default_headers() -> Vec<HttpRequestHeader> {
|
pub(crate) fn cmd_default_headers() -> Vec<HttpRequestHeader> {
|
||||||
default_headers()
|
default_headers()
|
||||||
|
|||||||
@@ -1722,6 +1722,7 @@ pub fn run() {
|
|||||||
// Migrated commands
|
// Migrated commands
|
||||||
crate::commands::cmd_decrypt_template,
|
crate::commands::cmd_decrypt_template,
|
||||||
crate::commands::cmd_default_headers,
|
crate::commands::cmd_default_headers,
|
||||||
|
crate::commands::cmd_disable_encryption,
|
||||||
crate::commands::cmd_enable_encryption,
|
crate::commands::cmd_enable_encryption,
|
||||||
crate::commands::cmd_get_themes,
|
crate::commands::cmd_get_themes,
|
||||||
crate::commands::cmd_reveal_workspace_key,
|
crate::commands::cmd_reveal_workspace_key,
|
||||||
|
|||||||
@@ -11,3 +11,7 @@ export function revealWorkspaceKey(workspaceId: string) {
|
|||||||
export function setWorkspaceKey(args: { workspaceId: string; key: string }) {
|
export function setWorkspaceKey(args: { workspaceId: string; key: string }) {
|
||||||
return invoke<void>('cmd_set_workspace_key', args);
|
return invoke<void>('cmd_set_workspace_key', args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function disableEncryption(workspaceId: string) {
|
||||||
|
return invoke<void>('cmd_disable_encryption', { workspaceId });
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,6 +115,35 @@ impl EncryptionManager {
|
|||||||
self.set_workspace_key(workspace_id, &wkey)
|
self.set_workspace_key(workspace_id, &wkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn disable_encryption(&self, workspace_id: &str) -> Result<()> {
|
||||||
|
info!("Disabling encryption for {workspace_id}");
|
||||||
|
|
||||||
|
self.query_manager.with_tx::<(), Error>(|tx| {
|
||||||
|
let workspace = tx.get_workspace(workspace_id)?;
|
||||||
|
let workspace_meta = tx.get_or_create_workspace_meta(workspace_id)?;
|
||||||
|
|
||||||
|
// Clear encryption challenge on workspace
|
||||||
|
tx.upsert_workspace(
|
||||||
|
&Workspace { encryption_key_challenge: None, ..workspace },
|
||||||
|
&UpdateSource::Background,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Clear encryption key on workspace meta
|
||||||
|
tx.upsert_workspace_meta(
|
||||||
|
&WorkspaceMeta { encryption_key: None, ..workspace_meta },
|
||||||
|
&UpdateSource::Background,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Remove from cache
|
||||||
|
let mut cache = self.cached_workspace_keys.lock().unwrap();
|
||||||
|
cache.remove(workspace_id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_workspace_key(&self, workspace_id: &str) -> Result<WorkspaceKey> {
|
fn get_workspace_key(&self, workspace_id: &str) -> Result<WorkspaceKey> {
|
||||||
{
|
{
|
||||||
let cache = self.cached_workspace_keys.lock().unwrap();
|
let cache = self.cached_workspace_keys.lock().unwrap();
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import { enableEncryption, revealWorkspaceKey, setWorkspaceKey } from '@yaakapp-internal/crypto';
|
import {
|
||||||
|
disableEncryption,
|
||||||
|
enableEncryption,
|
||||||
|
revealWorkspaceKey,
|
||||||
|
setWorkspaceKey,
|
||||||
|
} from '@yaakapp-internal/crypto';
|
||||||
import type { WorkspaceMeta } from '@yaakapp-internal/models';
|
import type { WorkspaceMeta } from '@yaakapp-internal/models';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
@@ -6,6 +11,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { activeWorkspaceAtom, activeWorkspaceMetaAtom } from '../hooks/useActiveWorkspace';
|
import { activeWorkspaceAtom, activeWorkspaceMetaAtom } from '../hooks/useActiveWorkspace';
|
||||||
import { createFastMutation } from '../hooks/useFastMutation';
|
import { createFastMutation } from '../hooks/useFastMutation';
|
||||||
import { useStateWithDeps } from '../hooks/useStateWithDeps';
|
import { useStateWithDeps } from '../hooks/useStateWithDeps';
|
||||||
|
import { showConfirm } from '../lib/confirm';
|
||||||
import { CopyIconButton } from './CopyIconButton';
|
import { CopyIconButton } from './CopyIconButton';
|
||||||
import { Banner } from './core/Banner';
|
import { Banner } from './core/Banner';
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
@@ -69,6 +75,9 @@ export function WorkspaceEncryptionSetting({ size, expanded, onDone, onEnabledEn
|
|||||||
onDone?.();
|
onDone?.();
|
||||||
onEnabledEncryption?.();
|
onEnabledEncryption?.();
|
||||||
}}
|
}}
|
||||||
|
onDisabled={() => {
|
||||||
|
onDone?.();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -109,6 +118,7 @@ export function WorkspaceEncryptionSetting({ size, expanded, onDone, onEnabledEn
|
|||||||
return (
|
return (
|
||||||
<div className="mb-auto flex flex-col-reverse">
|
<div className="mb-auto flex flex-col-reverse">
|
||||||
<Button
|
<Button
|
||||||
|
className="mt-3"
|
||||||
color={expanded ? 'info' : 'secondary'}
|
color={expanded ? 'info' : 'secondary'}
|
||||||
size={size}
|
size={size}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
@@ -149,13 +159,39 @@ const setWorkspaceKeyMut = createFastMutation({
|
|||||||
function EnterWorkspaceKey({
|
function EnterWorkspaceKey({
|
||||||
workspaceMeta,
|
workspaceMeta,
|
||||||
onEnabled,
|
onEnabled,
|
||||||
|
onDisabled,
|
||||||
error,
|
error,
|
||||||
}: {
|
}: {
|
||||||
workspaceMeta: WorkspaceMeta;
|
workspaceMeta: WorkspaceMeta;
|
||||||
onEnabled?: () => void;
|
onEnabled?: () => void;
|
||||||
|
onDisabled?: () => void;
|
||||||
error?: string | null;
|
error?: string | null;
|
||||||
}) {
|
}) {
|
||||||
const [key, setKey] = useState<string>('');
|
const [key, setKey] = useState<string>('');
|
||||||
|
|
||||||
|
const handleForgotKey = async () => {
|
||||||
|
const confirmed = await showConfirm({
|
||||||
|
id: 'disable-encryption',
|
||||||
|
title: 'Disable Encryption',
|
||||||
|
color: 'danger',
|
||||||
|
confirmText: 'Disable Encryption',
|
||||||
|
description: (
|
||||||
|
<>
|
||||||
|
This will disable encryption for this workspace. Any previously encrypted values will fail
|
||||||
|
to decrypt and will need to be re-entered manually.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
This action cannot be undone.
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (confirmed) {
|
||||||
|
await disableEncryption(workspaceMeta.workspaceId);
|
||||||
|
onDisabled?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack space={4} className="w-full">
|
<VStack space={4} className="w-full">
|
||||||
{error ? (
|
{error ? (
|
||||||
@@ -192,6 +228,13 @@ function EnterWorkspaceKey({
|
|||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleForgotKey}
|
||||||
|
className="text-text-subtlest text-sm hover:text-text-subtle"
|
||||||
|
>
|
||||||
|
Forgot your key?
|
||||||
|
</button>
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user