Skip to content

Commit 7cecfc6

Browse files
committed
feat: Improve wording for Security Whitelist Error Message [INS-1277]
1 parent a2b1060 commit 7cecfc6

File tree

8 files changed

+75
-22
lines changed

8 files changed

+75
-22
lines changed

packages/insomnia/src/common/validators.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import type { CaCertificate } from "../models/ca-certificate";
2-
import type { ClientCertificate } from "../models/client-certificate";
3-
import type { Settings } from "../models/settings";
4-
import type { RenderedRequest } from "../templating/types";
1+
import type { CaCertificate } from '../models/ca-certificate';
2+
import type { ClientCertificate } from '../models/client-certificate';
3+
import type { Settings } from '../models/settings';
4+
import type { RenderedRequest } from '../templating/types';
55

66
export function isFsAccessingAllowed(
77
renderedRequest: RenderedRequest,
@@ -14,13 +14,15 @@ export function isFsAccessingAllowed(
1414
if (fromCli) {
1515
throw `Insomnia cannot access the file ‘${fileName}’. You can specify paths with one or more "--dataFolders <directory>" or "-f <directory>" to allow accessing.`;
1616
} else {
17-
throw `Insomnia cannot access the file ‘${fileName}’. You can adjust this in Preferences → Security.`;
17+
throw `Insomnia cannot access the file ‘${fileName}’.`;
1818
}
19-
}
19+
};
2020

2121
// case1: check request body (set by scripts or request body editor)
2222
if (renderedRequest.body.fileName !== undefined && renderedRequest.body.fileName !== '') {
23-
const allowed = settings?.dataFolders.some(folder => folder !== '' && renderedRequest.body.fileName?.startsWith(folder));
23+
const allowed = settings?.dataFolders.some(
24+
folder => folder !== '' && renderedRequest.body.fileName?.startsWith(folder),
25+
);
2426
if (!allowed) {
2527
throwError(renderedRequest.body.fileName);
2628
}
@@ -29,7 +31,7 @@ export function isFsAccessingAllowed(
2931
// case2: check the body form data - "file" type params
3032
if (Array.isArray(renderedRequest.body.params)) {
3133
renderedRequest.body.params.forEach(param => {
32-
if (param.type === "file" && !param.disabled) {
34+
if (param.type === 'file' && !param.disabled) {
3335
const allowed = settings?.dataFolders.some(folder => folder !== '' && param.fileName?.startsWith(folder));
3436
if (!allowed) {
3537
throwError(param.fileName || param.value);
@@ -56,7 +58,9 @@ export function isFsAccessingAllowed(
5658

5759
[cert.key, cert.cert, cert.pfx].forEach(targetPath => {
5860
if (targetPath) {
59-
const allowed = settings?.dataFolders.some(folder => folder !== '' && targetPath !== "" && targetPath?.startsWith(folder));
61+
const allowed = settings?.dataFolders.some(
62+
folder => folder !== '' && targetPath !== '' && targetPath?.startsWith(folder),
63+
);
6064
if (!allowed) {
6165
throwError(targetPath);
6266
}

packages/insomnia/src/templating/base-extension-worker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export default class BaseExtension {
188188
?.getSettings()
189189
.dataFolders.some((folder: string) => folder !== '' && path.startsWith(folder));
190190
if (!allowed) {
191-
throw `Insomnia cannot access the file ‘${path}’. You can adjust this in Preferences → Security.`;
191+
throw `Insomnia cannot access the file ‘${path}’.`;
192192
}
193193
return fetchFromTemplateWorkerDatabase('readFile', { path, encoding });
194194
},

packages/insomnia/src/templating/base-extension.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export default class BaseExtension {
124124
?.getSettings()
125125
.dataFolders.some((folder: string) => folder !== '' && path.startsWith(folder));
126126
if (!allowed) {
127-
throw `Insomnia cannot access the file ‘${path}’. You can adjust this in Preferences → Security.`;
127+
throw `Insomnia cannot access the file ‘${path}’.`;
128128
}
129129

130130
const content = await fs.promises.readFile(path);

packages/insomnia/src/ui/components/modals/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export function showModal<
3434
TModalProps extends ModalProps &
3535
React.RefAttributes<{
3636
show: (options: any) => void;
37+
hide: () => void;
3738
}>,
3839
>(modalComponent: ModalComponent<TModalProps>, config?: ModalHandleShowOptions<GetRefHandleFromProps<TModalProps>>) {
3940
const name = modalComponent.name || modalComponent.displayName;
@@ -42,12 +43,18 @@ export function showModal<
4243

4344
const modalHandle = getModalComponentHandle(name) as unknown as GetRefHandleFromProps<TModalProps>;
4445

45-
return modalHandle.show(config);
46+
modalHandle.show(config);
47+
return () => {
48+
const modalHandle = getModalComponentHandle(name) as unknown as GetRefHandleFromProps<TModalProps>;
49+
if (modalHandle) {
50+
modalHandle.hide();
51+
}
52+
};
4653
}
4754

4855
export function showError(config: ErrorModalOptions) {
4956
try {
50-
return showModal(ErrorModal, config);
57+
showModal(ErrorModal, config);
5158
} catch (err) {
5259
console.log('[modal] Cannot show modal', err, config);
5360
}

packages/insomnia/src/ui/components/rendered-query-string.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import classNames from 'classnames';
22
import React, { type FC, useCallback, useEffect, useState } from 'react';
3+
import { Link } from 'react-aria-components';
4+
5+
import { showSettingsModal } from '~/ui/components/modals/settings-modal';
36

47
import { database as db } from '../../common/database';
58
import * as models from '../../models';
@@ -74,6 +77,7 @@ export const RenderedQueryString: FC<Props> = ({ request }) => {
7477
});
7578

7679
if (!result) {
80+
setTooLong(false);
7781
return;
7882
}
7983

@@ -136,11 +140,29 @@ export const RenderedQueryString: FC<Props> = ({ request }) => {
136140
}
137141
}, [tooLong]);
138142

143+
const showPreferneces = useCallback(() => {
144+
showSettingsModal({ tab: 'general' });
145+
}, []);
146+
139147
const className = previewString === defaultPreview ? 'super-duper-faint' : 'selectable force-wrap';
148+
// naive way to detect the access file error
149+
const settingTip = previewString.includes('Insomnia cannot access');
140150

141151
return (
142152
<div className="relative flex h-full w-full justify-between gap-[var(--padding-sm)] overflow-auto">
143-
<span className={classNames('my-auto', className)}>{previewString}</span>
153+
<span className={classNames('my-auto', className)}>
154+
{previewString}
155+
{settingTip && (
156+
<span>
157+
{' '}
158+
You must specify which directories Insomnia can access in{' '}
159+
<Link className="cursor-pointer text-[--color-surprise]" onPress={showPreferneces}>
160+
Insomnia’s Preferences → Security
161+
</Link>
162+
.
163+
</span>
164+
)}
165+
</span>
144166

145167
<CopyButton
146168
size="small"

packages/insomnia/src/ui/components/request-url-bar.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
2-
import { Button } from 'react-aria-components';
2+
import { Button, Link } from 'react-aria-components';
33
import { useParams, useSearchParams } from 'react-router';
44
import * as reactUse from 'react-use';
55

@@ -13,6 +13,7 @@ import {
1313
useDebugRequestSendActionFetcher,
1414
} from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.send';
1515
import { OneLineEditor, type OneLineEditorHandle } from '~/ui/components/.client/codemirror/one-line-editor';
16+
import { showSettingsModal } from '~/ui/components/modals/settings-modal';
1617

1718
import { database as db } from '../../common/database';
1819
import * as models from '../../models';
@@ -71,13 +72,33 @@ export const RequestUrlBar = forwardRef<RequestUrlBarHandle, Props>(
7172
setUndefinedEnvironmentVariables(searchParams.get('undefinedEnvironmentVariables')!);
7273
} else {
7374
// only for request render error
74-
showModal(AlertModal, {
75+
const errorMessage = searchParams.get('error') || '';
76+
const settingTip = errorMessage.includes('Insomnia cannot access');
77+
const close = showModal(AlertModal, {
7578
title: 'Unexpected Request Failure',
7679
message: (
7780
<div>
7881
<p>The request failed due to an unhandled error:</p>
7982
<code className="wide selectable">
80-
<pre className="w-full overflow-y-auto text-wrap" >{searchParams.get('error')}</pre>
83+
<p className="w-full overflow-y-auto text-wrap">
84+
{searchParams.get('error')}
85+
{settingTip && (
86+
<span>
87+
{' '}
88+
You must specify which directories Insomnia can access in{' '}
89+
<Link
90+
className="cursor-pointer text-[--color-surprise]"
91+
onPress={() => {
92+
close();
93+
showSettingsModal({ tab: 'general' });
94+
}}
95+
>
96+
Insomnia’s Preferences → Security
97+
</Link>
98+
.
99+
</span>
100+
)}
101+
</p>
81102
</code>
82103
</div>
83104
),

packages/insomnia/src/ui/components/settings/general.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,7 @@ export const General: FC = () => {
225225
help="If checked, clears the OAuth session every time Insomnia is relaunched."
226226
/>
227227
<button
228-
className="pointer h-[--line-height-xs] rounded-[--radius-md] border border-solid border-[--hl-lg] px-[--padding-md] hover:bg-[--hl-xs]"
229-
style={{
230-
padding: 0,
231-
}}
228+
className="pointer h-[--line-height-xs] rounded-[--radius-md] border border-solid border-[--hl-lg] px-[--padding-sm] hover:bg-[--hl-xs]"
232229
onClick={initNewOAuthSession}
233230
>
234231
Clear OAuth 2 session

packages/insomnia/src/ui/hooks/use-filtered-requests.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { useMemo } from 'react';
22

3+
import type { BaseModel } from '~/models';
4+
35
import { fuzzyMatchAll } from '../../common/misc';
46
import { isRequestGroup } from '../../models/request-group';
57

@@ -8,7 +10,7 @@ interface SearchableFields {
810
description: string;
911
url?: string;
1012
_id: string;
11-
type: string;
13+
type: BaseModel['type'];
1214
}
1315

1416
function isMatched(filter: string, doc: SearchableFields): boolean {

0 commit comments

Comments
 (0)