[WIP] Encryption for secure values (#183)

This commit is contained in:
Gregory Schier
2025-04-15 07:18:26 -07:00
committed by GitHub
parent e114a85c39
commit 2e55a1bd6d
208 changed files with 4063 additions and 28698 deletions

View File

@@ -0,0 +1,30 @@
import type { GrpcRequest, HttpRequest, WebsocketRequest } from '@yaakapp-internal/models';
import { createWorkspaceModel } from '@yaakapp-internal/models';
import { activeRequestAtom } from '../hooks/useActiveRequest';
import { jotaiStore } from './jotai';
import { router } from './router';
export async function createRequestAndNavigate<
T extends HttpRequest | GrpcRequest | WebsocketRequest,
>(patch: Partial<T> & Pick<T, 'model' | 'workspaceId'>) {
const activeRequest = jotaiStore.get(activeRequestAtom);
if (patch.sortPriority === undefined) {
if (activeRequest != null) {
// Place above currently active request
patch.sortPriority = activeRequest.sortPriority - 0.0001;
} else {
// Place at the very top
patch.sortPriority = -Date.now();
}
}
patch.folderId = patch.folderId || activeRequest?.folderId;
const newId = await createWorkspaceModel(patch);
await router.navigate({
to: '/workspaces/$workspaceId',
params: { workspaceId: patch.workspaceId },
search: (prev) => ({ ...prev, request_id: newId }),
});
}

View File

@@ -7,7 +7,7 @@ import { router } from './router';
export async function duplicateRequestAndNavigate(
model: HttpRequest | GrpcRequest | WebsocketRequest | null,
) {
if (model == null ){
if (model == null) {
throw new Error('Cannot duplicate null request');
}

57
src-web/lib/encryption.ts Normal file
View File

@@ -0,0 +1,57 @@
import { parseTemplate } from '@yaakapp-internal/templates';
import { activeEnvironmentIdAtom } from '../hooks/useActiveEnvironment';
import { activeWorkspaceIdAtom } from '../hooks/useActiveWorkspace';
import { jotaiStore } from './jotai';
import { invokeCmd } from './tauri';
export function analyzeTemplate(template: string): 'global_secured' | 'local_secured' | 'insecure' {
let secureTags = 0;
let insecureTags = 0;
let totalTags = 0;
for (const t of parseTemplate(template).tokens) {
if (t.type === 'eof') continue;
totalTags++;
if (t.type === 'tag' && t.val.type === 'fn' && t.val.name === 'secure') {
secureTags++;
} else if (t.type === 'tag' && t.val.type === 'var') {
// Variables are secure
} else if (t.type === 'tag' && t.val.type === 'bool') {
// Booleans are secure
} else {
insecureTags++;
}
}
if (secureTags === 1 && totalTags === 1) {
return 'global_secured';
} else if (insecureTags === 0) {
return 'local_secured';
} else {
return 'insecure';
}
}
export async function convertTemplateToInsecure(template: string) {
if (template === '') {
return '';
}
const workspaceId = jotaiStore.get(activeWorkspaceIdAtom) ?? 'n/a';
const environmentId = jotaiStore.get(activeEnvironmentIdAtom) ?? null;
return invokeCmd<string>('cmd_decrypt_template', { template, workspaceId, environmentId });
}
export async function convertTemplateToSecure(template: string): Promise<string> {
if (template === '') {
return '';
}
if (analyzeTemplate(template) === 'global_secured') {
return template;
}
const workspaceId = jotaiStore.get(activeWorkspaceIdAtom) ?? 'n/a';
const environmentId = jotaiStore.get(activeEnvironmentIdAtom) ?? null;
return invokeCmd<string>('cmd_secure_template', { template, workspaceId, environmentId });
}

View File

@@ -0,0 +1,32 @@
import { VStack } from '../components/core/Stacks';
import { WorkspaceEncryptionSetting } from '../components/WorkspaceEncryptionSetting';
import { activeWorkspaceMetaAtom } from '../hooks/useActiveWorkspace';
import { showDialog } from './dialog';
import { jotaiStore } from './jotai';
export function setupOrConfigureEncryption() {
setupOrConfigure();
}
export function withEncryptionEnabled(callback?: () => void) {
const workspaceMeta = jotaiStore.get(activeWorkspaceMetaAtom);
if (workspaceMeta?.encryptionKey != null) {
callback?.(); // Already set up
return;
}
setupOrConfigure(callback);
}
function setupOrConfigure(onEnable?: () => void) {
showDialog({
id: 'workspace-encryption',
title: 'Workspace Encryption',
size: 'md',
render: ({ hide }) => (
<VStack space={3} className="pb-2" alignItems="end">
<WorkspaceEncryptionSetting expanded onDone={hide} onEnabledEncryption={onEnable} />
</VStack>
),
});
}

View File

@@ -7,6 +7,8 @@ type TauriCmd =
| 'cmd_check_for_updates'
| 'cmd_create_grpc_request'
| 'cmd_curl_to_request'
| 'cmd_decrypt_template'
| 'cmd_secure_template'
| 'cmd_delete_all_grpc_connections'
| 'cmd_delete_all_http_responses'
| 'cmd_delete_send_history'
@@ -26,13 +28,13 @@ type TauriCmd =
| 'cmd_metadata'
| 'cmd_new_child_window'
| 'cmd_new_main_window'
| 'cmd_parse_template'
| 'cmd_plugin_info'
| 'cmd_reload_plugins'
| 'cmd_render_template'
| 'cmd_save_response'
| 'cmd_send_ephemeral_request'
| 'cmd_send_http_request'
| 'cmd_show_workspace_key'
| 'cmd_template_functions'
| 'cmd_template_tokens_to_string'
| 'cmd_uninstall_plugin';

View File

@@ -112,7 +112,7 @@ function bannerColorVariables(color: YaakColor): Partial<CSSVariables> {
return {
text: color.lift(0.8),
textSubtle: color.translucify(0.3),
textSubtlest: color,
textSubtlest: color.translucify(0.6),
surface: color.translucify(0.95),
border: color.lift(0.3).translucify(0.8),
};