Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ rootCA2.*
final.cpp
insomnia.ico
final.rc
.tmp*
7 changes: 0 additions & 7 deletions packages/insomnia-smoke-test/tests/smoke/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,6 @@ test('can send requests', async ({ page, insomnia }) => {
})
.toBe(true);

// No explicit timeout — inherits the global expect.timeout (40s on CI) so Playwright
// retries long enough for the Chromium PDF viewer to finish rendering.
await expect.soft(pdfIframe).toHaveScreenshot('dummy-pdf-preview.png', {
animations: 'disabled',
maxDiffPixelRatio: 0.15,
});

await page.getByTestId('response-pane').getByRole('tab', { name: 'Console' }).click();
await page.locator('pre').filter({ hasText: '< Content-Type: application/pdf' }).click();
await page.getByTestId('response-pane').getByRole('tab', { name: 'Preview' }).click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,15 @@ test('Setup external vault and used in request', async ({ app, page, insomnia })
// enable elevated access and execute again in renderer process
await page.getByTestId('settings-button').click();
await page.getByRole('tab', { name: 'Plugins' }).click();
await page.getByText('Allow elevated access for plugins').click();
const allowElevatedAccessForPlugins = page.getByRole('checkbox', {
name: 'Allow elevated access for plugins',
});
await expect.soft(allowElevatedAccessForPlugins).toBeVisible();
await allowElevatedAccessForPlugins.evaluate(element => {
if (element instanceof HTMLInputElement && !element.checked) {
element.click();
}
});
// close the settings
await page.locator('.app').press('Escape');
// send request and execute the tags in renderer process
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,16 @@ test('Critical Path For Template Tags Interactions', async ({ page, app, insomni
// elevate access for plugins
await page.getByTestId('settings-button').click();
await page.getByRole('tab', { name: 'Plugins' }).click();
await page.locator('text=Allow elevated access for plugins').click();
const allowElevatedAccessForPlugins = page.getByRole('checkbox', {
name: 'Allow elevated access for plugins',
});
await expect.soft(allowElevatedAccessForPlugins).toBeVisible();
await allowElevatedAccessForPlugins.evaluate(element => {
if (element instanceof HTMLInputElement && !element.checked) {
element.click();
}
});
await expect.soft(allowElevatedAccessForPlugins).toBeChecked();
await page.locator('.app').press('Escape');
await page.getByTestId('request-pane').getByRole('button', { name: 'Send' }).click();
await page.getByRole('dialog').locator('#prompt-input').fill('prompt-value');
Expand Down
11 changes: 6 additions & 5 deletions packages/insomnia/src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ import {
import appConfig from '../../config/config.json';
import { version } from '../../package.json';

// Vite is filtering out process.env variables that are not prefixed with VITE_.
// In the renderer (nodeIntegration disabled) env vars come from the preload via window.env.
// In the inso CLI and main process, fall back to process.env.
const ENV = 'env';

const env = process[ENV];
const env = typeof window !== 'undefined' && window.env ? window.env : process[ENV];

export const INSOMNIA_GITLAB_REDIRECT_URI = env.INSOMNIA_GITLAB_REDIRECT_URI;
export const INSOMNIA_GITLAB_CLIENT_ID = env.INSOMNIA_GITLAB_CLIENT_ID;
Expand All @@ -37,7 +38,7 @@ export const getProductName = () => appConfig.productName;
export const getAppSynopsis = () => appConfig.synopsis;
export const getAppId = () => appConfig.appId;
export const getAppBundlePlugins = () => appConfig.bundlePlugins;
export const getAppEnvironment = () => process.env.INSOMNIA_ENV || 'production';
export const getAppEnvironment = () => env.INSOMNIA_ENV || 'production';
export const isDevelopment = () => getAppEnvironment() === 'development';
export const getSegmentWriteKey = () =>
appConfig.segmentWriteKeys[isDevelopment() || env.PLAYWRIGHT_TEST ? 'development' : 'production'];
Expand All @@ -46,7 +47,7 @@ export const getCioWriteKey = () =>
appConfig.cio[isDevelopment() || env.PLAYWRIGHT_TEST ? 'development' : 'production'].writeKey;
export const getCioSiteId = () =>
appConfig.cio[isDevelopment() || env.PLAYWRIGHT_TEST ? 'development' : 'production'].siteId;
export const getAppBuildDate = () => new Date(process.env.BUILD_DATE ?? '').toLocaleDateString();
export const getAppBuildDate = () => new Date(env.BUILD_DATE ?? '').toLocaleDateString();

export const getBrowserUserAgent = () =>
encodeURIComponent(
Expand All @@ -62,7 +63,7 @@ export function updatesSupported() {
}

// Updates are not supported for Windows portable binaries
if (isWindows && process.env['PORTABLE_EXECUTABLE_DIR']) {
if (isWindows && env.PORTABLE_EXECUTABLE_DIR) {
return false;
}

Expand Down
49 changes: 49 additions & 0 deletions packages/insomnia/src/entry.preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ const main: Window['main'] = {
port.postMessage({ ...options, type: 'runPreRequestScript' });
}),
},
vault: {
encryptSecretValue: (rawValue, symmetricKey) =>
invokeWithNormalizedError('vault.encryptSecretValue', rawValue, symmetricKey),
decryptSecretValue: (encryptedValue, symmetricKey) =>
invokeWithNormalizedError('vault.decryptSecretValue', encryptedValue, symmetricKey),
},
extractJsonFileFromPostmanDataDumpArchive: archivePath =>
invokeWithNormalizedError('extractJsonFileFromPostmanDataDumpArchive', archivePath),
syncNewWorkspaceIfNeeded: options => invokeWithNormalizedError('syncNewWorkspaceIfNeeded', options),
Expand All @@ -364,6 +370,9 @@ const main: Window['main'] = {
useDynamicMockResponses,
mockServerAdditionalFiles,
),
generateCodeSnippet: (options: { har: object; target: string; client: string }) =>
invokeWithNormalizedError('generateCodeSnippet', options),
getCodeSnippetTargets: () => invokeWithNormalizedError('getCodeSnippetTargets'),
generateCommitsFromDiff: (input: { diff: string; recent_commits: string }) =>
invokeWithNormalizedError('generateCommitsFromDiff', input),
generateMcpSamplingResponse: (parameters: Parameters<GenerateMcpSamplingResponseFunction>[0]) =>
Expand Down Expand Up @@ -438,6 +447,44 @@ const database: Window['database'] = {
invoke: (fnName, ...args) => invokeWithNormalizedError('database.invoke', fnName, ...args),
};

const env: Window['env'] = {
// GitLab OAuth — redirect URI, client ID, and API URL allow dev/enterprise overrides
INSOMNIA_GITLAB_REDIRECT_URI: process.env.INSOMNIA_GITLAB_REDIRECT_URI,
Comment thread
jackkav marked this conversation as resolved.
INSOMNIA_GITLAB_CLIENT_ID: process.env.INSOMNIA_GITLAB_CLIENT_ID,
INSOMNIA_GITLAB_API_URL: process.env.INSOMNIA_GITLAB_API_URL,
// E2E sentinel: switches analytics to dev keys and forces vertical layout in settings
PLAYWRIGHT_TEST: process.env.PLAYWRIGHT_TEST,
// E2E fixtures: pre-seed auth state so tests bypass login/key-derivation UI
INSOMNIA_SKIP_ONBOARDING: process.env.INSOMNIA_SKIP_ONBOARDING,
INSOMNIA_SESSION: process.env.INSOMNIA_SESSION,
INSOMNIA_SECRET_KEY: process.env.INSOMNIA_SECRET_KEY,
INSOMNIA_PUBLIC_KEY: process.env.INSOMNIA_PUBLIC_KEY,
// E2E vault fixtures: pre-seed deterministic salt/key/SRP secret
INSOMNIA_VAULT_SALT: process.env.INSOMNIA_VAULT_SALT,
INSOMNIA_VAULT_KEY: process.env.INSOMNIA_VAULT_KEY,
INSOMNIA_VAULT_SRP_SECRET: process.env.INSOMNIA_VAULT_SRP_SECRET,
// App environment: gates dev features and selects analytics keys
INSOMNIA_ENV: process.env.INSOMNIA_ENV,
// Injected at build time; shown in the About screen
BUILD_DATE: process.env.BUILD_DATE,
// Windows portable binary sentinel: presence disables auto-updates
PORTABLE_EXECUTABLE_DIR: process.env.PORTABLE_EXECUTABLE_DIR,
// OAuth flow URL overrides for dev/staging environments
OAUTH_REDIRECT_URL: process.env.OAUTH_REDIRECT_URL,
OAUTH_RELAY_URL: process.env.OAUTH_RELAY_URL,
// Service URL overrides: allow dev/CI to target local or staging backends
INSOMNIA_API_URL: process.env.INSOMNIA_API_URL,
INSOMNIA_MOCK_API_URL: process.env.INSOMNIA_MOCK_API_URL,
INSOMNIA_AI_URL: process.env.INSOMNIA_AI_URL,
KONNECT_API_URL: process.env.KONNECT_API_URL,
INSOMNIA_APP_WEBSITE_URL: process.env.INSOMNIA_APP_WEBSITE_URL,
// GitHub API URL overrides for GitHub Enterprise targets
INSOMNIA_GITHUB_REST_API_URL: process.env.INSOMNIA_GITHUB_REST_API_URL,
INSOMNIA_GITHUB_API_URL: process.env.INSOMNIA_GITHUB_API_URL,
// Disables the renderer↔hidden-window plugin bridge when set to 'false'
INSOMNIA_ENABLE_PLUGIN_BRIDGE: process.env.INSOMNIA_ENABLE_PLUGIN_BRIDGE,
};

if (process.contextIsolated) {
contextBridge.exposeInMainWorld('main', main);
contextBridge.exposeInMainWorld('dialog', dialog);
Expand All @@ -448,6 +495,7 @@ if (process.contextIsolated) {
contextBridge.exposeInMainWorld('path', path);
contextBridge.exposeInMainWorld('database', database);
contextBridge.exposeInMainWorld('_dataServices', servicesProxy);
contextBridge.exposeInMainWorld('env', env);
} else {
window.main = main;
window.dialog = dialog;
Expand All @@ -458,4 +506,5 @@ if (process.contextIsolated) {
window.path = path;
window.database = database;
window._dataServices = servicesProxy;
window.env = env;
}
6 changes: 5 additions & 1 deletion packages/insomnia/src/main/ipc/electron.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export type HandleChannels =
| 'authorizeUserInWindow'
| 'backup'
| 'cancelAuthorizationInDefaultBrowser'
| 'generateCodeSnippet'
| 'getCodeSnippetTargets'
| 'generateMockRouteDataFromSpec'
| 'generateCommitsFromDiff'
| 'generateMcpSamplingResponse'
Expand Down Expand Up @@ -168,7 +170,9 @@ export type HandleChannels =
| 'timeline.getPath'
| 'writeFile'
| 'deleteRulesetFile'
| 'writeResponseBodyToFile';
| 'writeResponseBodyToFile'
| 'vault.encryptSecretValue'
| 'vault.decryptSecretValue';

export const ipcMainHandle = (
channel: HandleChannels,
Expand Down
25 changes: 25 additions & 0 deletions packages/insomnia/src/main/ipc/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import type {
import type { HiddenBrowserWindowBridgeAPI } from '../../entry.hidden-window';
import type { PluginsBridgeAPI } from '../../plugins/bridge-types';
import type { RenderedRequest } from '../../templating/types';
import { decryptSecretValue,encryptSecretValue } from '../../utils/vault';
import type { AnalyticsEvent } from '../analytics';
import { setCurrentOrganizationId, trackAnalyticsEvent, trackPageView } from '../analytics';
import {
Expand Down Expand Up @@ -273,6 +274,8 @@ export interface RendererToMainBridgeAPI {
useDynamicMockResponses: boolean,
mockServerAdditionalFiles: string[],
) => Promise<{ error: string; routes: MockRouteData[] }>;
generateCodeSnippet: (options: { har: object; target: string; client: string }) => Promise<string>;
getCodeSnippetTargets: () => Promise<{ key: string; title: string; clients: { key: string; title: string }[] }[]>;
generateCommitsFromDiff: (
input: Parameters<GenerateCommitsFromDiffFunction>[0],
) => Promise<
Expand All @@ -288,6 +291,10 @@ export interface RendererToMainBridgeAPI {
syncNewWorkspaceIfNeeded: typeof syncNewWorkspaceIfNeeded;
plugins: PluginsBridgeAPI;
notifyPluginPromptResult: (id: string, value: string | null) => void;
vault: {
encryptSecretValue: (rawValue: string, symmetricKey: JsonWebKey) => Promise<string>;
decryptSecretValue: (encryptedValue: string, symmetricKey: JsonWebKey) => Promise<string>;
};
timeline: {
getPath: (responseId: string) => Promise<string>;
appendToFile: (options: { timelinePath: string; data: string }) => Promise<void>;
Expand Down Expand Up @@ -489,6 +496,17 @@ export function registerMainHandlers() {
});
});

ipcMainHandle('generateCodeSnippet', async (_, options: { har: object; target: string; client: string }) => {
const { HTTPSnippet } = await import('httpsnippet');
const snippet = new HTTPSnippet(options.har as any);
return snippet.convert(options.target, options.client) || '';
});

ipcMainHandle('getCodeSnippetTargets', async () => {
const { availableTargets } = await import('httpsnippet');
return availableTargets();
});

ipcMainHandle('insecureReadFile', async (_, options: { path: string }) => {
return insecureReadFile(options.path);
});
Expand Down Expand Up @@ -795,5 +813,12 @@ export function registerMainHandlers() {
ipcMainHandle('timeline.getPath', getTimelinePath);
ipcMainHandle('timeline.appendToFile', appendToTimeline);

ipcMainHandle('vault.encryptSecretValue', (_, rawValue: string, symmetricKey: JsonWebKey) => {
return encryptSecretValue(rawValue, symmetricKey);
});
ipcMainHandle('vault.decryptSecretValue', (_, encryptedValue: string, symmetricKey: JsonWebKey) => {
return decryptSecretValue(encryptedValue, symmetricKey);
});

registerPluginIpcHandlers();
}
2 changes: 1 addition & 1 deletion packages/insomnia/src/main/window-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ import {
} from 'electron';

import { isLinux, isMac } from '~/insomnia-data/common';
import { AnalyticsEvent, trackAnalyticsEvent } from '~/main/analytics';

import { getAppBuildDate, getAppVersion, getProductName, isDevelopment, MNEMONIC_SYM } from '../common/constants';
import { docsBase } from '../common/documentation';
import { invariant } from '../utils/invariant';
import { AnalyticsEvent, trackAnalyticsEvent } from './analytics';
import { getElectronStorage } from './electron-storage';
import { ipcMainOn } from './ipc/electron';
import { getLogDirectory } from './log';
Expand Down
2 changes: 2 additions & 0 deletions packages/insomnia/src/path-shim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const extname = (p: string) => p.slice(p.lastIndexOf('.'));
export default { extname };
10 changes: 4 additions & 6 deletions packages/insomnia/src/routes/auth.clear-vault-key.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import electron from 'electron';
import { getVault } from 'insomnia-api';
import { href } from 'react-router';

import { services } from '~/insomnia-data';
import { showToast } from '~/ui/components/toast-notification';
import { createFetcherSubmitHook } from '~/utils/router';

import type { Route } from './+types/auth.clear-vault-key';
Expand All @@ -23,11 +23,9 @@ export async function clientAction({ request }: Route.ClientActionArgs) {
// Update vault salt and delete vault key from session
await services.userSession.update({ vaultSalt: newVaultSalt, vaultKey: '' });
// show notification
electron.ipcRenderer.emit('show-toast', null, {
content: {
title: 'Your vault key has been reset, all you local secrets have been deleted.',
status: 'info',
},
showToast({
title: 'Your vault key has been reset, all your local secrets have been deleted.',
status: 'info',
});
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,8 +373,12 @@ export async function clientAction({ request, params }: Route.ClientActionArgs)
const allPreScripts = docsWithScripts.map(doc => doc.preRequestScript).filter((s): s is string => !!s);
const allPostScripts = docsWithScripts.map(doc => doc.afterResponseScript).filter((s): s is string => !!s);

const requestType = activeRequest.body?.mimeType === CONTENT_TYPE_GRAPHQL ? 'GraphQL' :
models.request.isEventStreamRequest(activeRequest) ? 'Event Stream' : 'HTTP';
const requestType =
activeRequest.body?.mimeType === CONTENT_TYPE_GRAPHQL
? 'GraphQL'
: models.request.isEventStreamRequest(activeRequest)
? 'Event Stream'
: 'HTTP';
window.main.trackAnalyticsEvent({
event: AnalyticsEvent.requestExecuted,
properties: {
Expand Down
Loading
Loading