Split out high-risk runtime changes

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
jackkav
2026-05-29 11:21:23 +02:00
parent 8586b07dc6
commit b5e86d2a8a
19 changed files with 19 additions and 358 deletions

View File

@@ -47,6 +47,9 @@ jobs:
- name: Lint
run: npm run lint
- name: Check renderer Node import baseline
run: npm run check:renderer-node-imports
- name: Type checks
run: npm run type-check

View File

@@ -26,6 +26,7 @@
"scripts": {
"dev": "npm start -w insomnia",
"dev:autoRestart": "npm run start:autoRestart -w insomnia",
"check:renderer-node-imports": "npm run check:renderer-node-imports -w insomnia",
"lint": "npm run lint --workspaces --if-present",
"type-check": "npm run type-check --workspaces --if-present",
"test": "npm run test --workspaces --if-present",

View File

@@ -20,6 +20,9 @@
"verify-bundle-plugins": "esr --cache ./scripts/verify-bundle-plugins.ts",
"install-x64-native-dependencies": "esr --cache ./scripts/install-x64-native-dependencies.ts",
"build": "react-router build && esr --cache ./scripts/build.ts --noErrorTruncation",
"analyze:renderer-node-imports": "cross-env NODE_OPTIONS=--max-old-space-size=8192 INSOMNIA_NODE_IMPORT_REPORT=1 react-router build",
"check:renderer-node-imports": "npm run analyze:renderer-node-imports && esr --cache ./scripts/check-renderer-node-imports.ts",
"update:renderer-node-import-baseline": "npm run analyze:renderer-node-imports && esr --cache ./scripts/check-renderer-node-imports.ts --write-baseline",
"build:react-router": "react-router build",
"generate:schema": "esr ./src/schema.ts",
"build:electron-entrypoints": "cross-env NODE_ENV=development esr esbuild.entrypoints.ts",

View File

@@ -26,7 +26,6 @@ import { registerInsomniaProtocols } from './main/api.protocol';
import { backupIfNewerVersionAvailable } from './main/backup';
import { registerSyncHandlers } from './main/cloud-sync/ipc';
import { registerGitServiceAPI } from './main/git-service';
import { registerCookieHandlers } from './main/ipc/cookies';
import { ipcMainOn, ipcMainOnce, registerElectronHandlers } from './main/ipc/electron';
import { registerElectronStorageHandlers } from './main/ipc/electron-storage';
import { registergRPCHandlers } from './main/ipc/grpc';
@@ -89,7 +88,6 @@ app.on('ready', async () => {
// @TODO - Maybe move the register stuff in the registerMainHandlers function
registerMainHandlers();
registerPathHandlers();
registerCookieHandlers();
registergRPCHandlers();
registerGitServiceAPI();
registerLLMConfigServiceAPI();

View File

@@ -3,9 +3,6 @@ import { ipcRenderer } from 'electron';
// Provide window.app so plugin-loading code (which checks process.type === 'renderer')
// can resolve the userData path without needing the main renderer's full preload.
window.app = {
env: Object.fromEntries(
Object.entries(process.env).filter(([key, value]) => value !== undefined && key.startsWith('INSOMNIA_')),
),
getPath: (name: string) => ipcRenderer.sendSync('getPath', name) as string,
getAppPath: () => ipcRenderer.sendSync('getAppPath') as string,
process: { platform: process.platform as NodeJS.Platform },

View File

@@ -9,7 +9,6 @@ import { servicesProxy } from '~/ui/renderer-services-proxy';
import type { SyncBridgeAPI } from './main/cloud-sync/ipc';
import type { GitServiceAPI } from './main/git-service';
import type { CookiesBridgeAPI } from './main/ipc/cookies';
import type { electronStorageBridgeAPI } from './main/ipc/electron-storage';
import type { gRPCBridgeAPI } from './main/ipc/grpc';
import type { secretStorageBridgeAPI } from './main/ipc/secret-storage';
@@ -124,17 +123,9 @@ const grpc: gRPCBridgeAPI = {
closeAll: () => ipcRenderer.send('grpc.closeAll'),
loadMethods: options => invokeWithNormalizedError('grpc.loadMethods', options),
loadMethodsFromReflection: options => invokeWithNormalizedError('grpc.loadMethodsFromReflection', options),
validateProtoFile: filePath => invokeWithNormalizedError('grpc.validateProtoFile', filePath),
writeProtoFile: protoFileId => invokeWithNormalizedError('grpc.writeProtoFile', protoFileId),
};
const cookies: CookiesBridgeAPI = {
fromJSON: cookie => invokeWithNormalizedError('cookies.fromJSON', cookie),
parse: cookie => invokeWithNormalizedError('cookies.parse', cookie),
toString: cookie => invokeWithNormalizedError('cookies.toString', cookie),
getCookiesForUrl: args => invokeWithNormalizedError('cookies.getCookiesForUrl', args),
};
const secretStorage: secretStorageBridgeAPI = {
setSecret: (key, secret) => invokeWithNormalizedError('secretStorage.setSecret', key, secret),
getSecret: key => invokeWithNormalizedError('secretStorage.getSecret', key),
@@ -261,30 +252,6 @@ const llm: LLMConfigServiceAPI = {
invokeWithNormalizedError('llm.setAIFeatureEnabled', feature, enabled),
};
const rendererProcessEnv = Object.fromEntries(
Object.entries(process.env).filter(
([key, value]) =>
value !== undefined &&
(key.startsWith('INSOMNIA_') ||
key === 'BUILD_DATE' ||
key === 'NODE_ENV' ||
key === 'PLAYWRIGHT_TEST' ||
key === 'PORTABLE_EXECUTABLE_DIR'),
),
);
const rendererProcess = {
env: rendererProcessEnv,
platform: process.platform as NodeJS.Platform,
type: 'renderer' as const,
versions: {
chrome: process.versions.chrome,
electron: process.versions.electron,
node: process.versions.node,
v8: process.versions.v8,
},
};
const main: Window['main'] = {
startExecution: options => ipcRenderer.send('startExecution', options),
addExecutionStep: options => ipcRenderer.send('addExecutionStep', options),
@@ -338,7 +305,6 @@ const main: Window['main'] = {
webSocket,
socketIO,
mcp,
cookies,
git,
llm,
grpc,
@@ -447,7 +413,6 @@ const dialog: Window['dialog'] = {
showSaveDialog: options => invokeWithNormalizedError('showSaveDialog', options),
};
const app: Window['app'] = {
env: rendererProcessEnv,
getPath: options => ipcRenderer.sendSync('getPath', options),
getAppPath: () => ipcRenderer.sendSync('getAppPath'),
process: {
@@ -474,8 +439,6 @@ const database: Window['database'] = {
if (process.contextIsolated) {
contextBridge.exposeInMainWorld('main', main);
contextBridge.exposeInMainWorld('process', rendererProcess);
contextBridge.exposeInMainWorld('global', globalThis);
contextBridge.exposeInMainWorld('dialog', dialog);
contextBridge.exposeInMainWorld('app', app);
contextBridge.exposeInMainWorld('shell', shell);
@@ -486,14 +449,6 @@ if (process.contextIsolated) {
contextBridge.exposeInMainWorld('_dataServices', servicesProxy);
} else {
window.main = main;
Object.defineProperty(window, 'process', {
configurable: true,
value: rendererProcess,
});
Object.defineProperty(window, 'global', {
configurable: true,
value: window,
});
window.dialog = dialog;
window.app = app;
window.shell = shell;

View File

@@ -1,64 +0,0 @@
import { Cookie as ToughCookie, CookieJar } from 'tough-cookie';
import type { Cookie } from '~/insomnia-data';
import { ipcMainHandle } from './electron';
type CookieInput = Cookie | string;
const parseCookieFromJSON = (cookie: CookieInput) => {
return typeof cookie === 'string' ? ToughCookie.fromJSON(cookie) : ToughCookie.fromJSON(cookie);
};
const cookieToString = (cookie: CookieInput) => {
const parsedCookie = parseCookieFromJSON(cookie);
if (parsedCookie === null) {
throw new Error(`Unable to read cookie: ${cookie}`);
}
let value = parsedCookie.toString();
if (parsedCookie.domain && parsedCookie.hostOnly) {
value += `; Domain=${parsedCookie.domain}`;
}
return value;
};
const getCookiesForUrl = (cookies: Cookie[], url: string): Cookie[] => {
try {
const sanitized = cookies.map(c => ({
...c,
expires: c.expires === null || c.expires === undefined ? 'Infinity' : c.expires,
}));
const jar = CookieJar.fromJSON(JSON.stringify({ cookies: sanitized }));
jar.rejectPublicSuffixes = false;
jar.looseMode = true;
return jar.getCookiesSync(url).map(c => c.toJSON() as Cookie);
} catch {
return [];
}
};
export interface CookiesBridgeAPI {
fromJSON: (cookie: CookieInput) => Promise<Cookie | null>;
parse: (cookie: string) => Promise<Cookie | null>;
toString: (cookie: CookieInput) => Promise<string>;
getCookiesForUrl: (args: { cookies: Cookie[]; url: string }) => Promise<Cookie[]>;
}
export function registerCookieHandlers() {
ipcMainHandle('cookies.fromJSON', (_, cookie: CookieInput) => {
return parseCookieFromJSON(cookie)?.toJSON() as Cookie | null;
});
ipcMainHandle('cookies.parse', (_, cookie: string) => {
return ToughCookie.parse(cookie, { loose: true })?.toJSON() as Cookie | null;
});
ipcMainHandle('cookies.toString', (_, cookie: CookieInput) => {
return cookieToString(cookie);
});
ipcMainHandle('cookies.getCookiesForUrl', (_, { cookies, url }: { cookies: Cookie[]; url: string }) => {
return getCookiesForUrl(cookies, url);
});
}

View File

@@ -26,10 +26,6 @@ export type HandleChannels =
| 'curl.event.findMany'
| 'curl.open'
| 'curl.readyState'
| 'cookies.fromJSON'
| 'cookies.getCookiesForUrl'
| 'cookies.parse'
| 'cookies.toString'
| 'createPlugin'
| 'curlRequest'
| 'database.caCertificate.create'
@@ -84,7 +80,6 @@ export type HandleChannels =
| 'git.getGitProviderEmails'
| 'grpc.loadMethods'
| 'grpc.loadMethodsFromReflection'
| 'grpc.validateProtoFile'
| 'grpc.writeProtoFile'
| 'initializeWorkspaceBackendProject'
| 'insecureReadFile'

View File

@@ -1,5 +1,3 @@
import path from 'node:path';
import {
FileDescriptorSet as ProtobufEsFileDescriptorSet,
MethodIdempotency,
@@ -62,7 +60,6 @@ export interface gRPCBridgeAPI {
cancel: typeof cancel;
loadMethods: typeof loadMethods;
loadMethodsFromReflection: typeof loadMethodsFromReflection;
validateProtoFile: (filePath: string) => Promise<void>;
closeAll: typeof closeAll;
writeProtoFile: (protoFileId: string) => Promise<{ filePath: string; dirs: string[] }>;
}
@@ -94,17 +91,9 @@ export function registergRPCHandlers() {
ipcMainOn('grpc.closeAll', closeAll);
ipcMainHandle('grpc.loadMethods', (_, requestId) => loadMethods(requestId));
ipcMainHandle('grpc.loadMethodsFromReflection', (_, requestId) => loadMethodsFromReflection(requestId));
ipcMainHandle('grpc.validateProtoFile', (_, filePath: string) => validateProtoFile(filePath));
ipcMainHandle('grpc.writeProtoFile', (_, protoFileId: string) => writeProtoFileById(protoFileId));
}
const validateProtoFile = async (filePath: string): Promise<void> => {
await protoLoader.load(filePath, {
...grpcOptions,
includeDirs: [path.dirname(filePath)],
});
};
const loadMethodsFromFilePath = async (filePath: string, includeDirs: string[]): Promise<MethodDefs[]> => {
const definition = await protoLoader.load(filePath, {
...grpcOptions,

View File

@@ -67,7 +67,6 @@ import {
import type { SocketIOBridgeAPI } from '../network/socket-io';
import type { WebSocketBridgeAPI } from '../network/websocket';
import { registerPluginIpcHandlers } from '../plugin-window';
import type { CookiesBridgeAPI } from './cookies';
import { ipcMainHandle, ipcMainOn, type RendererOnChannels } from './electron';
import type { electronStorageBridgeAPI } from './electron-storage';
import extractPostmanDataDumpHandler from './extract-postman-data-dump';
@@ -227,7 +226,6 @@ export interface RendererToMainBridgeAPI {
webSocket: WebSocketBridgeAPI;
socketIO: SocketIOBridgeAPI;
mcp: McpBridgeAPI;
cookies: CookiesBridgeAPI;
grpc: gRPCBridgeAPI;
curl: CurlBridgeAPI;
git: GitServiceAPI;

View File

@@ -201,7 +201,7 @@ export function createWindow(): ElectronBrowserWindow {
webPreferences: {
preload: path.join(__dirname, 'entry.preload.min.js'),
zoomFactor: getZoomFactor(),
nodeIntegration: false,
nodeIntegration: true,
nodeIntegrationInWorker: false, // must remain false to ensure the nunjucks web worker sandbox does not have access to Node.js APIs
webviewTag: true,
// TODO: enable context isolation

View File

@@ -4,7 +4,6 @@ import nodePath from 'node:path';
import clone from 'clone';
import type { RequestHeader } from '~/insomnia-data';
import { services } from '~/insomnia-data';
import type { RenderedRequest } from '~/templating/types';
import type { RequestContext } from '../../../insomnia-scripting-environment/src/objects';
@@ -48,23 +47,10 @@ export const runScript = (options: {
context: RequestContext;
}): Promise<RequestContext | { error: string }> => executeScript(options);
async function canRunPluginHooksInNodeAdapter() {
if (!process.versions?.electron || typeof global.require !== 'function') {
return false;
}
const settings = await services.settings.get();
return Boolean(settings);
}
export async function applyRequestHooks(
newRenderedRequest: RenderedRequest,
renderedContext: Record<string, any>,
): Promise<RenderedRequest> {
if (!await canRunPluginHooksInNodeAdapter()) {
return newRenderedRequest;
}
const pluginIndex = require('../plugins/index');
for (const { plugin, hook } of await pluginIndex.getRequestHooks()) {
const context = {
@@ -90,10 +76,6 @@ export async function applyResponseHooks(
renderedRequest: RenderedRequest,
renderedContext: Record<string, any>,
): Promise<ResponsePatch> {
if (!await canRunPluginHooksInNodeAdapter()) {
return response;
}
const newResponse = clone(response);
const newRequest = clone(renderedRequest);
const pluginIndex = require('../plugins/index');

View File

@@ -31,10 +31,6 @@ export async function applyRequestHooks(
newRenderedRequest: RenderedRequest,
renderedContext: Record<string, any>,
): Promise<RenderedRequest> {
if (!globalThis.window?.main?.plugins) {
return newRenderedRequest;
}
if (!await pluginsBridge.hasRequestHooks()) {
return newRenderedRequest;
}
@@ -50,10 +46,6 @@ export async function applyResponseHooks(
renderedRequest: RenderedRequest,
renderedContext: Record<string, any>,
): Promise<ResponsePatch> {
if (!globalThis.window?.main?.plugins) {
return response;
}
if (!await pluginsBridge.hasResponseHooks()) {
return response;
}

View File

@@ -4,10 +4,7 @@ import type * as AdapterType from './network-adapter.renderer';
const impl = (
(process as any).type === 'renderer' &&
globalThis.window !== undefined &&
globalThis.window.main !== undefined &&
globalThis.window.main.plugins !== undefined
(process as any).type === 'renderer'
? require('./network-adapter.renderer')
: require(/* @vite-ignore */ './network-adapter.node')
) as typeof AdapterType;

View File

@@ -3,10 +3,8 @@ import Color from 'color';
import type { ThemeSettings } from '~/insomnia-data';
import { getAppDefaultTheme } from '~/insomnia-data/common';
import type { SerializableTheme } from './bridge-types';
import { plugins } from './renderer-bridge';
export type ColorScheme = 'default' | 'light' | 'dark';
import type { Theme } from './index';
import { type ColorScheme, getThemes } from './index';
export type HexColor = `#${string}`;
export type RGBColor = `rgb(${string})`;
@@ -333,7 +331,7 @@ export async function setTheme(themeName: string) {
return;
}
const themes: SerializableTheme[] = await plugins.getThemes();
const themes: Theme[] = await getThemes();
let selectedTheme = themes.find(t => t.theme.name === themeName);
if (!selectedTheme) {

View File

@@ -1,4 +1,5 @@
import type { PluginBridgeMetrics, PluginsBridgeAPI } from './bridge-types';
import { invokePluginMethod } from './invoke-method';
// Phase 1a rollback switch: set INSOMNIA_ENABLE_PLUGIN_BRIDGE=false to fall
// back to running plugins directly in the renderer (legacy behaviour).
@@ -6,17 +7,15 @@ import type { PluginBridgeMetrics, PluginsBridgeAPI } from './bridge-types';
// plugin-system deps it pulls in don't inflate the preload.
const bridgeEnabled = process.env.INSOMNIA_ENABLE_PLUGIN_BRIDGE !== 'false';
async function call<M extends keyof Omit<PluginsBridgeAPI, 'getBridgeMetrics'>>(
function call<M extends keyof Omit<PluginsBridgeAPI, 'getBridgeMetrics'>>(
method: M,
args?: Parameters<PluginsBridgeAPI[M]>[0],
): Promise<Awaited<ReturnType<PluginsBridgeAPI[M]>>> {
): ReturnType<PluginsBridgeAPI[M]> {
if (bridgeEnabled) {
const fn = (window.main.plugins[method] as (...a: any[]) => any);
return fn(args) as Promise<Awaited<ReturnType<PluginsBridgeAPI[M]>>>;
return fn(args) as ReturnType<PluginsBridgeAPI[M]>;
}
const { invokePluginMethod } = await import('./invoke-method');
return invokePluginMethod(method as any, args) as Promise<Awaited<ReturnType<PluginsBridgeAPI[M]>>>;
return invokePluginMethod(method as any, args) as ReturnType<PluginsBridgeAPI[M]>;
}
const emptyBridgeMetrics: PluginBridgeMetrics = {

View File

@@ -1,178 +0,0 @@
import type { Environment } from 'nunjucks';
import nunjucks from 'nunjucks';
import { localTemplateTags } from '~/templating/local-template-tags';
import type { TemplateTag } from '../plugins';
import BaseExtension from './base-extension';
import { extractUndefinedVariableKey, RenderError } from './render-error';
// Some constants
export const NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME = '_';
type NunjucksEnvironment = Environment & {
extensions: Record<string, any>;
};
// Cached globals
let nunjucksAll: NunjucksEnvironment | null = null;
/**
* Render text based on stuff
* @param {String} text - Nunjucks template in text form
* @param {Object} [config] - Config options for rendering
* @param {Object} [config.context] - Context to render with
* @param {Object} [config.path] - Path to include in the error message
*/
export function render(
text: string,
config: {
context?: Record<string, any>;
path?: string;
ignoreUndefinedEnvVariable?: boolean;
} = {},
) {
const hasNunjucksInterpolationSymbols = text.includes('{{') && text.includes('}}');
const hasNunjucksCustomTagSymbols = text.includes('{%') && text.includes('%}');
const hasNunjucksCommentSymbols = text.includes('{#') && text.includes('#}');
if (!hasNunjucksInterpolationSymbols && !hasNunjucksCustomTagSymbols && !hasNunjucksCommentSymbols) {
return text;
}
const context = config.context || {};
// context needs to exist on the root for the old templating syntax, and in _ for the new templating syntax
// old: {{ arr[0].prop }}
// new: {{ _['arr-name-with-dash'][0].prop }}
const templatingContext = { ...context, [NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME]: context };
const path = config.path || null;
return new Promise<string | null>(async (resolve, reject) => {
// NOTE: this is added as a breadcrumb because renderString sometimes hangs
const id = setTimeout(() => console.log('[templating] Warning: nunjucks failed to respond within 5 seconds'), 5000);
const nj = await getNunjucks(config.ignoreUndefinedEnvVariable);
nj?.renderString(text, templatingContext, (err: Error | null, result: any) => {
clearTimeout(id);
if (!err) {
return resolve(result);
}
console.warn('[templating] Error rendering template', err);
const sanitizedMsg = err.message
.replace(/\(unknown path\)\s/, '')
.replace(/\[Line \d+, Column \d*]/, '')
.replace(/^\s*Error:\s*/, '')
.trim();
const location = err.message.match(/\[Line (\d+), Column (\d+)*]/);
const line = location ? Number.parseInt(location[1]) : 1;
const column = location ? Number.parseInt(location[2]) : 1;
const reason = err.message.includes('attempted to output null or undefined value') ? 'undefined' : 'error';
const newError = new RenderError(sanitizedMsg);
newError.path = path || '';
newError.message = sanitizedMsg;
newError.location = {
line,
column,
};
newError.type = 'render';
newError.reason = reason;
// regard as environment variable missing
if (hasNunjucksInterpolationSymbols && reason === 'undefined') {
newError.extraInfo = {
subType: 'environmentVariable',
undefinedEnvironmentVariables: extractUndefinedVariableKey(text, templatingContext),
};
}
reject(newError);
});
});
}
/**
* Reload Nunjucks environments. Useful for if plugins change.
*/
export function reload() {
nunjucksAll = null;
}
/**
* Get definitions of template tags
*/
export async function getTagDefinitions() {
const env = await getNunjucks();
return Object.keys(env.extensions)
.map(k => env.extensions[k])
.filter(ext => !ext.isDeprecated())
.sort((a, b) => (a.getPriority() > b.getPriority() ? 1 : -1))
.map(ext => ({
name: ext.getTag() || '',
displayName: ext.getName() || '',
liveDisplayName: ext.getLiveDisplayName(),
description: ext.getDescription(),
disablePreview: ext.getDisablePreview(),
args: ext.getArgs(),
actions: ext.getActions(),
}));
}
async function getNunjucks(ignoreUndefinedEnvVariable?: boolean): Promise<NunjucksEnvironment> {
let throwOnUndefined = true;
if (ignoreUndefinedEnvVariable) {
throwOnUndefined = false;
} else if (nunjucksAll) {
return nunjucksAll;
}
// ~~~~~~~~~~~~ //
// Setup Config //
// ~~~~~~~~~~~~ //
const config = {
autoescape: false,
// Don't escape HTML
throwOnUndefined,
// Strict mode
tags: {
blockStart: '{%',
blockEnd: '%}',
variableStart: '{{',
variableEnd: '}}',
commentStart: '{#',
commentEnd: '#}',
},
};
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
// Create Env with Extensions //
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
const nunjucksEnvironment = nunjucks.configure(config) as NunjucksEnvironment;
nunjucksEnvironment.addGlobal('range', () => {});
nunjucksEnvironment.addGlobal('cycler', () => {});
nunjucksEnvironment.addGlobal('joiner', () => {});
const pluginTemplateTags: TemplateTag[] = [];
const allExtensions = [
...localTemplateTags,
// Spread after local tags to allow plugins to override them.
// TODO: Determine if this is in fact the behavior we've explicitly decided to support.
...pluginTemplateTags,
];
for (const extension of allExtensions) {
const { templateTag, plugin } = extension;
templateTag.priority = templateTag.priority || allExtensions.indexOf(extension);
const instance = new BaseExtension(templateTag, plugin);
nunjucksEnvironment.addExtension(instance.getTag() || '', instance);
// Hidden helper filter to debug complicated things
// eg. `{{ foo | urlencode | debug | upper }}`
nunjucksEnvironment.addFilter('debug', (o: any) => o);
}
// ~~~~~~~~~~~~~~~~~~~~ //
// Cache Env and Return (when ignoreUndefinedEnvVariable is false) //
// ~~~~~~~~~~~~~~~~~~~~ //
if (ignoreUndefinedEnvVariable) {
return nunjucksEnvironment;
}
nunjucksAll = nunjucksEnvironment;
return nunjucksEnvironment;
}

View File

@@ -1,6 +1,7 @@
import type { EditorFromTextArea, MarkerRange } from 'codemirror';
import { models, services } from '~/insomnia-data';
import { decryptSecretValue } from '~/utils/vault';
import type { NunjucksParsedTag, NunjucksParsedTagArg, RenderPurpose } from '../templating/types';
import { decryptVaultKeyFromSession } from '../utils/vault';
@@ -156,7 +157,6 @@ export async function maskOrDecryptVaultDataIfNecessary(vaultEnvironmentData: an
const { vaultKey, vaultSalt } = await services.userSession.get();
const isVaultEnabled = !!vaultSalt;
if (isVaultEnabled && vaultKey) {
const { decryptSecretValue } = await import('~/utils/vault-crypto');
const symmetricKey = (await decryptVaultKeyFromSession(vaultKey, true)) as JsonWebKey;
// decrypt all secret values under vaultEnvironmentPath property in context
Object.keys(vaultEnvironmentData).forEach(vaultContextKey => {

View File

@@ -10,14 +10,10 @@ declare global {
main: RendererToMainBridgeAPI;
bridge: HiddenBrowserWindowToMainBridgeAPI;
database: DatabaseBridgeAPI;
global: typeof globalThis;
// This is a temporary measure to provide access to services on the global window object. It will be removed in the future once all usages are updated to import services directly from the insomnia-data package.
_dataServices?: Services;
dialog: Pick<Electron.Dialog, 'showOpenDialog' | 'showSaveDialog'>;
app: Pick<Electron.App, 'getPath' | 'getAppPath'> & {
env: Record<string, string | undefined>;
process: { platform: NodeJS.Platform };
};
app: Pick<Electron.App, 'getPath' | 'getAppPath'> & { process: { platform: NodeJS.Platform } };
shell: Pick<Electron.Shell, 'showItemInFolder' | 'openPath'>;
clipboard: Pick<Electron.Clipboard, 'readText' | 'writeText' | 'clear'>;
webUtils: Pick<Electron.WebUtils, 'getPathForFile'>;