sixth pass

This commit is contained in:
jackkav
2026-05-29 06:08:17 +02:00
parent 5ee092d24a
commit 0c4504eecf
5 changed files with 79 additions and 37 deletions

View File

@@ -1,7 +1,6 @@
import type * as Har from 'har-format';
import { Cookie as ToughCookie } from 'tough-cookie';
import type { BaseModel, Environment, Request, RequestGroup, Response, Workspace } from '~/insomnia-data';
import type { BaseModel, Cookie, Environment, Request, RequestGroup, Response, Workspace } from '~/insomnia-data';
import { models, services } from '~/insomnia-data';
import { applyRequestHooks } from '~/network/network-adapter';
@@ -10,7 +9,6 @@ import type { RenderedRequest } from '../templating/types';
import { parseGraphQLReqeustBody } from '../utils/graph-ql';
import { smartEncodeUrl } from '../utils/url/querystring';
import { getAppVersion } from './constants';
import { jarFromCookies } from './cookies';
import { database } from './database';
import { filterHeaders, getSetCookieHeaders, hasAuthHeader } from './misc';
import { getRenderedRequestAndContext } from './render';
@@ -207,7 +205,7 @@ export async function exportHarResponse(response?: Response) {
status: response.statusCode,
statusText: response.statusMessage,
httpVersion: 'HTTP/1.1',
cookies: getResponseCookies(response),
cookies: await getResponseCookies(response),
headers: getResponseHeaders(response),
content: await getResponseContent(response),
redirectURL: '',
@@ -299,7 +297,7 @@ export async function exportHarWithRenderedRequest(renderedRequest: RenderedRequ
method: renderedRequest.method,
url,
httpVersion: 'HTTP/1.1',
cookies: getRequestCookies(renderedRequest),
cookies: await getRequestCookies(renderedRequest),
headers: getRequestHeaders(renderedRequest),
queryString: getRequestQueryString(renderedRequest),
postData: await getRequestPostData(renderedRequest),
@@ -309,36 +307,56 @@ export async function exportHarWithRenderedRequest(renderedRequest: RenderedRequ
return harRequest;
}
function getRequestCookies(renderedRequest: RenderedRequest) {
// filter out invalid cookies to avoid getCookiesSync complaining
async function getRequestCookies(renderedRequest: RenderedRequest): Promise<Har.Cookie[]> {
if (!renderedRequest.url) {
return [];
}
if (typeof window !== 'undefined' && window.main?.cookies) {
const domainCookies = await window.main.cookies.getCookiesForUrl({
cookies: renderedRequest.cookieJar.cookies,
url: renderedRequest.url,
});
return domainCookies.map(mapCookieToHar);
}
// Fallback for non-renderer contexts (tests, plugin window)
const { jarFromCookies } = await import('./cookies');
const jar = jarFromCookies(renderedRequest.cookieJar.cookies);
const domainCookies = renderedRequest.url ? jar.getCookiesSync(renderedRequest.url) : [];
const harCookies: Har.Cookie[] = domainCookies.map(mapCookie);
return harCookies;
const domainCookies = jar.getCookiesSync(renderedRequest.url);
return domainCookies.map(c => mapCookieToHar(c.toJSON() as Cookie));
}
export function getResponseCookiesFromHeaders(headers: Har.Cookie[]) {
return getSetCookieHeaders(headers).reduce((accumulator, harCookie) => {
let cookie: null | undefined | ToughCookie = null;
export async function getResponseCookiesFromHeaders(headers: Har.Cookie[]): Promise<Har.Cookie[]> {
const setCookieHeaders = getSetCookieHeaders(headers);
if (typeof window !== 'undefined' && window.main?.cookies) {
const results: Har.Cookie[] = [];
for (const harCookie of setCookieHeaders) {
const cookie = await window.main.cookies.parse(harCookie.value || '');
if (cookie) {
results.push(mapCookieToHar(cookie));
}
}
return results;
}
// Fallback for non-renderer contexts (tests, plugin window)
const { Cookie: ToughCookie } = await import('tough-cookie');
return setCookieHeaders.reduce((accumulator, harCookie) => {
let cookie = null;
try {
cookie = ToughCookie.parse(harCookie.value || '', { loose: true });
} catch {}
if (cookie === null || cookie === undefined) {
if (!cookie) {
return accumulator;
}
return [...accumulator, mapCookie(cookie)];
return [...accumulator, mapCookieToHar(cookie.toJSON() as Cookie)];
}, [] as Har.Cookie[]);
}
function getResponseCookies(response: Response) {
async function getResponseCookies(response: Response): Promise<Har.Cookie[]> {
const headers = response.headers.filter(Boolean);
return getResponseCookiesFromHeaders(headers);
}
function mapCookie(cookie: ToughCookie) {
function mapCookieToHar(cookie: Cookie): Har.Cookie {
const harCookie: Har.Cookie = {
name: cookie.key,
value: cookie.value,

View File

@@ -132,6 +132,7 @@ 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 = {

View File

@@ -1,4 +1,4 @@
import { Cookie as ToughCookie } from 'tough-cookie';
import { Cookie as ToughCookie, CookieJar } from 'tough-cookie';
import type { Cookie } from '~/insomnia-data';
@@ -26,10 +26,26 @@ const cookieToString = (cookie: CookieInput) => {
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() {
@@ -42,4 +58,7 @@ export function registerCookieHandlers() {
ipcMainHandle('cookies.toString', (_, cookie: CookieInput) => {
return cookieToString(cookie);
});
ipcMainHandle('cookies.getCookiesForUrl', (_, { cookies, url }: { cookies: Cookie[]; url: string }) => {
return getCookiesForUrl(cookies, url);
});
}

View File

@@ -27,6 +27,7 @@ export type HandleChannels =
| 'curl.open'
| 'curl.readyState'
| 'cookies.fromJSON'
| 'cookies.getCookiesForUrl'
| 'cookies.parse'
| 'cookies.toString'
| 'createPlugin'

View File

@@ -100,22 +100,25 @@ export const mockRouteToHar = ({
body: string;
}): Promise<Har.Response> => {
const validHeaders = headersArray.filter(({ name }) => !!name);
return import('~/common/har').then(({ getResponseCookiesFromHeaders }) => ({
status: +statusCode,
statusText: statusText || RESPONSE_CODE_REASONS[+statusCode] || '',
httpVersion: 'HTTP/1.1',
headers: validHeaders,
cookies: getResponseCookiesFromHeaders(validHeaders),
content: {
size: Buffer.byteLength(body),
mimeType,
text: body,
compression: 0,
},
headersSize: -1,
bodySize: -1,
redirectURL: '',
}));
return (async () => {
const { getResponseCookiesFromHeaders } = await import('~/common/har');
return {
status: +statusCode,
statusText: statusText || RESPONSE_CODE_REASONS[+statusCode] || '',
httpVersion: 'HTTP/1.1',
headers: validHeaders,
cookies: await getResponseCookiesFromHeaders(validHeaders),
content: {
size: Buffer.byteLength(body),
mimeType,
text: body,
compression: 0,
},
headersSize: -1,
bodySize: -1,
redirectURL: '',
};
})();
};
export const useMockRoutePatcher = () => {