diff --git a/packages/insomnia/src/account/session.ts b/packages/insomnia/src/account/session.ts index 0ee95e55b0..e70c6333c0 100644 --- a/packages/insomnia/src/account/session.ts +++ b/packages/insomnia/src/account/session.ts @@ -103,7 +103,7 @@ export async function changePasswordWithToken(rawNewPassphrase: string, confirma return window.main.insomniaFetch({ method: 'POST', path: '/auth/change-password', - obj: { + data: { code: confirmationCode, newEmail: newEmail, encSymmetricKey: encSymmetricKey, @@ -252,7 +252,7 @@ function _getAuthSalts(email: string) { return window.main.insomniaFetch({ method: 'POST', path: '/auth/login-s', - obj: { email }, + data: { email }, sessionId: getCurrentSessionId(), }); } diff --git a/packages/insomnia/src/main/insomniaFetch.ts b/packages/insomnia/src/main/insomniaFetch.ts index 6b0fd09c0f..d024fd8822 100644 --- a/packages/insomnia/src/main/insomniaFetch.ts +++ b/packages/insomnia/src/main/insomniaFetch.ts @@ -1,75 +1,65 @@ -import { parse as urlParse } from 'url'; +import { BrowserWindow, net } from 'electron'; import { getApiBaseURL, getClientString } from '../common/constants'; import { delay } from '../common/misc'; -import { invariant } from '../utils/invariant'; -const _commandListeners: Function[] = []; -export function onCommand(callback: Function) { - _commandListeners.push(callback); -} - -let _userAgent = getClientString(); -let _baseUrl = getApiBaseURL(); - -export function setup(userAgent: string, baseUrl: string) { - _userAgent = userAgent; - _baseUrl = baseUrl; -} interface FetchConfig { method: 'POST' | 'PUT' | 'GET'; path: string; sessionId: string | null; - obj?: unknown; + data?: unknown; retries?: number; + origin?: string; } -export async function insomniaFetch({ method, path, obj, sessionId, retries = 0 }: FetchConfig): Promise { - const config: { - method: string; - headers: Record; - body?: string | Buffer; - } = { - method: method, +// internal request (insomniaFetch) +// should validate ssl certs on our server +// should only go to insomnia API +// should be able to listen for specific messages in headers +// should be able to retry on 502 + +// external request (axiosRequest) +// should respect settings for proxy and ssl validation +// should be for all third party APIs, github, gitlab, isometric-git + +const exponentialBackOff = async (url: string, init: RequestInit, retries = 0): Promise => { + try { + const response = await net.fetch(url, init); + if (response.status === 502 && retries < 5) { + retries++; + await delay(retries * 200); + return exponentialBackOff(url, init, retries); + } + if (!response.ok) { + const err = new Error(`Response ${response.status} for ${url}`); + err.message = await response.text(); + throw err; + } + return response; + } catch (err) { + throw new Error(`Failed to fetch ${url}: ${err.message}`); + } +}; + +export async function insomniaFetch({ method, path, data, sessionId, origin }: FetchConfig): Promise { + const config: RequestInit = { + method, headers: { + 'X-Insomnia-Client': getClientString(), ...(sessionId ? { 'X-Session-Id': sessionId } : {}), - ...(_userAgent ? { 'X-Insomnia-Client': _userAgent } : {}), - ...(obj ? { 'Content-Type': 'application/json' } : {}), - ...(obj ? { body: JSON.stringify(obj) } : {}), + ...(data ? { 'Content-Type': 'application/json' } : {}), }, + ...(data ? { body: JSON.stringify(data) } : {}), }; if (sessionId === undefined) { throw new Error(`No session ID provided to ${method}:${path}`); } - - invariant(_baseUrl, 'API base URL not configured!'); - const url = `${_baseUrl}${path}`; - let response: Response | undefined; - try { - response = await window.fetch(url, config); - - // Exponential backoff for 502 errors - if (response.status === 502 && retries < 5) { - retries++; - await delay(retries * 200); - return insomniaFetch({ method, path, obj, sessionId, retries }); - } - } catch (err) { - throw new Error(`Failed to fetch '${url}'`); - } - + const response = await exponentialBackOff(`${origin || getApiBaseURL()}${path}`, config); const uri = response.headers.get('x-insomnia-command'); if (uri) { - const parsed = urlParse(uri, true); - _commandListeners.map(fn => fn(`${parsed.hostname}${parsed.pathname}`, JSON.parse(JSON.stringify(parsed.query)))); + for (const window of BrowserWindow.getAllWindows()) { + window.webContents.send('shell:open', uri); + } } - if (!response.ok) { - const err = new Error(`Response ${response.status} for ${path}`); - err.message = await response.text(); - // @ts-expect-error -- TSCONVERSION - err.statusCode = response.status; - throw err; - } - const isJson = response.headers.get('content-type') === 'application/json' || path.match(/\.json$/); return isJson ? response.json() : response.text(); } diff --git a/packages/insomnia/src/sync/vcs/vcs.ts b/packages/insomnia/src/sync/vcs/vcs.ts index 54efd12279..1abf922187 100644 --- a/packages/insomnia/src/sync/vcs/vcs.ts +++ b/packages/insomnia/src/sync/vcs/vcs.ts @@ -712,7 +712,7 @@ export class VCS { const { data, errors } = await window.main.insomniaFetch({ method: 'POST', path: '/graphql?' + name, - obj: { query, variables }, + data: { query, variables }, sessionId, }); diff --git a/packages/insomnia/src/ui/components/toast.tsx b/packages/insomnia/src/ui/components/toast.tsx index c26387c226..1f61698de6 100644 --- a/packages/insomnia/src/ui/components/toast.tsx +++ b/packages/insomnia/src/ui/components/toast.tsx @@ -114,7 +114,7 @@ export const Toast: FC = () => { const notificationOrEmpty = await window.main.insomniaFetch({ method: 'POST', path: '/notification', - obj: data, + data, sessionId: session.getCurrentSessionId(), }); if (notificationOrEmpty && typeof notificationOrEmpty !== 'string') { diff --git a/packages/insomnia/src/ui/routes/actions.tsx b/packages/insomnia/src/ui/routes/actions.tsx index e432344de3..a4d18650ac 100644 --- a/packages/insomnia/src/ui/routes/actions.tsx +++ b/packages/insomnia/src/ui/routes/actions.tsx @@ -626,13 +626,11 @@ export const generateCollectionAndTestsAction: ActionFunction = async ({ params const methodInfo = resolveComponentSchemaRefs(spec, getMethodInfo(request)); - const response = await window.main.axiosRequest({ + const response = await window.main.insomniaFetch({ method: 'POST', - url: 'https://ai.insomnia.rest/v1/generate-test', - headers: { - 'Content-Type': 'application/json', - 'X-Session-Id': session.getCurrentSessionId(), - }, + origin: 'https://ai.insomnia.rest', + path: '/v1/generate-test', + sessionId: session.getCurrentSessionId(), data: { teamId: organizationId, request: requests.find(r => r._id === test.requestId), @@ -709,13 +707,11 @@ export const generateTestsAction: ActionFunction = async ({ params }) => { for (const test of tests) { async function generateTest() { try { - const response = await window.main.axiosRequest({ + const response = await window.main.insomniaFetch({ method: 'POST', - url: 'https://ai.insomnia.rest/v1/generate-test', - headers: { - 'Content-Type': 'application/json', - 'X-Session-Id': session.getCurrentSessionId(), - }, + origin: 'https://ai.insomnia.rest', + path: '/v1/generate-test', + sessionId: session.getCurrentSessionId(), data: { teamId: organizationId, request: requests.find(r => r._id === test.requestId), @@ -753,13 +749,11 @@ export const accessAIApiAction: ActionFunction = async ({ params }) => { invariant(typeof workspaceId === 'string', 'Workspace ID is required'); try { - const response = await window.main.axiosRequest({ + const response = await window.main.insomniaFetch({ method: 'POST', - url: 'https://ai.insomnia.rest/v1/access', - headers: { - 'Content-Type': 'application/json', - 'X-Session-Id': session.getCurrentSessionId(), - }, + origin: 'https://ai.insomnia.rest', + path: '/v1/access', + sessionId: session.getCurrentSessionId(), data: { teamId: organizationId, }, diff --git a/packages/insomnia/src/ui/routes/root.tsx b/packages/insomnia/src/ui/routes/root.tsx index 91183aa070..d90c810ab5 100644 --- a/packages/insomnia/src/ui/routes/root.tsx +++ b/packages/insomnia/src/ui/routes/root.tsx @@ -30,6 +30,7 @@ import { showError, showModal } from '../components/modals'; import { AlertModal } from '../components/modals/alert-modal'; import { AskModal } from '../components/modals/ask-modal'; import { ImportModal } from '../components/modals/import-modal'; +import { LoginModal } from '../components/modals/login-modal'; import { SettingsModal, TAB_INDEX_PLUGINS, @@ -133,6 +134,14 @@ const Root = () => { }); break; + case 'insomnia://app/auth/login': + showModal(LoginModal, { + title: params.title, + message: params.message, + reauth: true, + }); + break; + case 'insomnia://app/import': setImportUri(params.uri); break;