Skip to content

Commit 87f73a6

Browse files
authored
feat: auth for socket.io-[INS-1270] (#9066)
* feat: auth for socket.io * fix: type check * fix: ts issue * feat: add auth indicator
1 parent 0e8e20a commit 87f73a6

File tree

10 files changed

+114
-29
lines changed

10 files changed

+114
-29
lines changed

packages/insomnia-scripting-environment/src/objects/auth.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,10 @@ export function toPreRequestAuth(auth: RequestAuthentication | {}): AuthOptions
805805
// TODO: not supported yet
806806
throw new Error('netrc auth is not supported in scripting yet');
807807
}
808+
case 'singleToken': {
809+
// TODO: not supported yet
810+
throw new Error('singleToken auth is not supported in scripting yet');
811+
}
808812
default: {
809813
// @ts-expect-error - user can input any string
810814
throw new Error(`unknown auth type: ${auth.type}`);

packages/insomnia/src/common/constants.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ export type AuthTypes =
294294
| 'hawk'
295295
| 'iam'
296296
| 'netrc'
297-
| 'asap';
297+
| 'asap'
298+
| 'singleToken';
298299

299300
export const HAWK_ALGORITHM_SHA256 = 'sha256';
300301
export const HAWK_ALGORITHM_SHA1 = 'sha1';

packages/insomnia/src/common/import-v5-parser.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ const NoneAuthenticationSchema = z.object({
248248
disabled: z.boolean().optional(),
249249
});
250250

251+
const SingleTokenAuthenticationSchema = z.object({
252+
type: z.literal('singleToken'),
253+
disabled: z.boolean().optional(),
254+
token: z.string().optional(),
255+
});
256+
251257
const AuthenticationSchema = z.union([
252258
z.discriminatedUnion('type', [
253259
BasicAuthenticationSchema,
@@ -262,6 +268,7 @@ const AuthenticationSchema = z.union([
262268
NetrcAuthenticationSchema,
263269
ASAPAuthenticationSchema,
264270
NoneAuthenticationSchema,
271+
SingleTokenAuthenticationSchema,
265272
]),
266273
z.object({}),
267274
]);

packages/insomnia/src/main/network/socket-io.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { generateId } from '../../common/misc';
1313
import * as models from '../../models';
1414
import { socketIORequest } from '../../models';
1515
import type { CookieJar } from '../../models/cookie-jar';
16-
import { type RequestHeader } from '../../models/request';
16+
import { type RequestAuthentication, type RequestHeader } from '../../models/request';
1717
import type { BaseSocketIORequest } from '../../models/socket-io-request';
1818
import type { SocketIOResponse } from '../../models/socket-io-response.ts';
1919
import { filterClientCertificates } from '../../network/certificate';
@@ -99,6 +99,7 @@ interface OpenSocketIORequestOptions {
9999
url: string;
100100
query: Record<string, string>;
101101
headers: RequestHeader[];
102+
authentication: RequestAuthentication;
102103
cookieJar: CookieJar;
103104
initialPayload?: string;
104105
}
@@ -272,6 +273,12 @@ const openSocketIOConnection = async (
272273
socketIOoptions.key = pemCertificateKeys.join('\n');
273274
}
274275

276+
if (options.authentication && options.authentication.type === 'singleToken' && !options.authentication.disabled) {
277+
socketIOoptions.auth = {
278+
token: options.authentication.token || '',
279+
};
280+
}
281+
275282
const socket = SocketIOClient(url, socketIOoptions);
276283
SocketIOConnections.set(options.requestId, socket);
277284
const openedEvents = request.eventListeners.filter(event => event.isOpen && event.eventName);

packages/insomnia/src/models/request.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ export interface AuthTypeNone {
128128
type: 'none';
129129
disabled?: boolean;
130130
}
131+
132+
export interface AuthTypeSingleToken {
133+
type: 'singleToken';
134+
token?: string;
135+
disabled?: boolean;
136+
}
137+
131138
export type RequestAuthentication =
132139
| AuthTypeOAuth2
133140
| AuthTypeBasic
@@ -140,7 +147,8 @@ export type RequestAuthentication =
140147
| AuthTypeAsap
141148
| AuthTypeNone
142149
| AuthTypeAPIKey
143-
| AuthTypeNTLM;
150+
| AuthTypeNTLM
151+
| AuthTypeSingleToken;
144152

145153
export type OAuth2ResponseType = 'code' | 'id_token' | 'id_token token' | 'none' | 'token';
146154

packages/insomnia/src/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId.connect.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ export async function clientAction({ params, request }: Route.ClientActionArgs)
8787
url: rendered.url,
8888
headers: rendered.headers,
8989
cookieJar: rendered.cookieJar,
90+
authentication: rendered.authentication,
9091
query: rendered.query || {},
9192
});
9293
}

packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,15 @@ interface Props {
144144
authentication?: RequestAuthentication | {};
145145
authTypes?: AuthTypes[];
146146
disabled?: boolean;
147+
hideOthers?: boolean;
147148
}
148149

149-
export const AuthDropdown: FC<Props> = ({ authentication, authTypes = defaultTypes, disabled = false }) => {
150+
export const AuthDropdown: FC<Props> = ({
151+
authentication,
152+
authTypes = defaultTypes,
153+
disabled = false,
154+
hideOthers = false,
155+
}) => {
150156
const { requestId, requestGroupId } = useParams() as {
151157
organizationId: string;
152158
projectId: string;
@@ -220,39 +226,49 @@ export const AuthDropdown: FC<Props> = ({ authentication, authTypes = defaultTyp
220226
id: 'netrc',
221227
name: 'Netrc',
222228
},
229+
{
230+
id: 'singleToken',
231+
name: 'token',
232+
},
223233
];
224234

225-
const authTypeSections: {
235+
interface Section {
226236
id: string;
227237
icon: IconName;
228238
name: string;
229239
items: {
230240
id: AuthTypes | 'inherit';
231241
name: string;
232242
}[];
233-
}[] = [
234-
{
235-
id: 'Other',
236-
name: 'Other',
237-
icon: 'ellipsis-h',
238-
items: [
239-
{
240-
id: 'inherit',
241-
name: 'Inherit from parent',
242-
},
243+
}
244+
245+
const commonSections: Section = {
246+
id: 'Auth Types',
247+
name: 'Auth Types',
248+
icon: 'lock',
249+
items: authTypesItems.filter(item => authTypes.includes(item.id)),
250+
};
251+
252+
const authTypeSections: Section[] = hideOthers
253+
? [commonSections]
254+
: [
243255
{
244-
id: 'none',
245-
name: 'None',
256+
id: 'Other',
257+
name: 'Other',
258+
icon: 'ellipsis-h',
259+
items: [
260+
{
261+
id: 'inherit',
262+
name: 'Inherit from parent',
263+
},
264+
{
265+
id: 'none',
266+
name: 'None',
267+
},
268+
],
246269
},
247-
],
248-
},
249-
{
250-
id: 'Auth Types',
251-
name: 'Auth Types',
252-
icon: 'lock',
253-
items: authTypesItems.filter(item => authTypes.includes(item.id)),
254-
},
255-
];
270+
commonSections,
271+
];
256272

257273
return (
258274
<Select
@@ -272,7 +288,7 @@ export const AuthDropdown: FC<Props> = ({ authentication, authTypes = defaultTyp
272288
</SelectValue>
273289
<Icon icon="caret-down" />
274290
</Button>
275-
<Popover className="flex min-w-max flex-col overflow-y-hidden">
291+
<Popover className="flex min-w-[17ch] flex-col overflow-y-hidden">
276292
<ListBox
277293
items={authTypeSections}
278294
className="min-w-max select-none overflow-y-auto rounded-md border border-solid border-[--hl-sm] bg-[--color-bg] py-2 text-sm shadow-lg focus:outline-none"

packages/insomnia/src/ui/components/editors/auth/auth-wrapper.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { type FC, type ReactNode } from 'react';
22
import { Toolbar } from 'react-aria-components';
33

44
import type { AuthTypes } from '~/common/constants';
5+
import { SingleTokenAuth } from '~/ui/components/editors/auth/single-token-auth';
56

67
import type { RequestAuthentication } from '../../../../models/request';
78
import { getAuthObjectOrNull } from '../../../../network/authentication';
@@ -22,7 +23,8 @@ export const AuthWrapper: FC<{
2223
authentication?: RequestAuthentication | {};
2324
disabled?: boolean;
2425
authTypes?: AuthTypes[];
25-
}> = ({ authentication, disabled = false, authTypes }) => {
26+
hideOthers?: boolean;
27+
}> = ({ authentication, disabled = false, authTypes, hideOthers }) => {
2628
const type = getAuthObjectOrNull(authentication)?.type || '';
2729
let authBody: ReactNode = null;
2830

@@ -48,6 +50,8 @@ export const AuthWrapper: FC<{
4850
authBody = <NetrcAuth />;
4951
} else if (type === 'asap') {
5052
authBody = <AsapAuth />;
53+
} else if (type === 'singleToken') {
54+
authBody = <SingleTokenAuth disabled={disabled} />;
5155
} else {
5256
authBody = (
5357
<div className="flex h-full w-full select-none items-center justify-center">
@@ -70,7 +74,7 @@ export const AuthWrapper: FC<{
7074
return (
7175
<>
7276
<Toolbar className="flex h-[--line-height-sm] w-full flex-shrink-0 items-center border-b border-solid border-[--hl-md] px-2">
73-
<AuthDropdown authentication={authentication} authTypes={authTypes} />
77+
<AuthDropdown authentication={authentication} authTypes={authTypes} hideOthers={hideOthers} />
7478
</Toolbar>
7579
<div className="flex-1 overflow-y-auto">{authBody}</div>
7680
</>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React, { type FC } from 'react';
2+
3+
import { AuthInputRow } from './components/auth-input-row';
4+
import { AuthTableBody } from './components/auth-table-body';
5+
import { AuthToggleRow } from './components/auth-toggle-row';
6+
7+
export const SingleTokenAuth: FC<{ disabled?: boolean }> = ({ disabled = false }) => (
8+
<AuthTableBody>
9+
<AuthToggleRow label="Enabled" property="disabled" invert disabled={disabled} />
10+
<AuthInputRow label="Token" property="token" mask disabled={disabled} />
11+
</AuthTableBody>
12+
);

packages/insomnia/src/ui/components/socket-io/request-pane.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
44
import { useParams } from 'react-router';
55
import * as reactUse from 'react-use';
66

7+
import { getAuthObjectOrNull } from '~/network/authentication';
78
import { useRootLoaderData } from '~/root';
89
import { useWorkspaceLoaderData } from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId';
910
import { OneLineEditor } from '~/ui/components/.client/codemirror/one-line-editor';
11+
import { AuthWrapper } from '~/ui/components/editors/auth/auth-wrapper';
1012

1113
import type { Environment } from '../../../models/environment';
1214
import { getCombinedPathParametersFromUrl, type RequestPathParameter } from '../../../models/request';
@@ -105,6 +107,9 @@ export const SocketIORequestPane: FC<Props> = ({ environment }) => {
105107
const disabled = readyState;
106108
const eventsCount = activeRequest?.eventListeners?.length || 0;
107109

110+
const requestAuth = getAuthObjectOrNull(activeRequest.authentication);
111+
const isAuthEnable = requestAuth?.type === 'singleToken' && !requestAuth.disabled;
112+
108113
return (
109114
<Pane type="request">
110115
<header className="pane__header theme--pane__header !items-stretch">
@@ -153,6 +158,17 @@ export const SocketIORequestPane: FC<Props> = ({ environment }) => {
153158
</span>
154159
)}
155160
</Tab>
161+
<Tab
162+
className="flex h-full flex-shrink-0 cursor-pointer select-none items-center justify-between gap-2 px-3 py-1 text-[--hl] outline-none transition-colors duration-300 hover:bg-[--hl-sm] hover:text-[--color-font] focus:bg-[--hl-sm] aria-selected:bg-[--hl-xs] aria-selected:text-[--color-font] aria-selected:hover:bg-[--hl-sm] aria-selected:focus:bg-[--hl-sm]"
163+
id="auth"
164+
>
165+
<span>Auth</span>
166+
{isAuthEnable && (
167+
<span className="flex h-6 min-w-6 items-center justify-center rounded-lg border border-solid border-[--hl] p-1 text-xs">
168+
<span className="h-2 w-2 rounded-full bg-green-500" />
169+
</span>
170+
)}
171+
</Tab>
156172
<Tab
157173
className="flex h-full flex-shrink-0 cursor-pointer select-none items-center justify-between gap-2 px-3 py-1 text-[--hl] outline-none transition-colors duration-300 hover:bg-[--hl-sm] hover:text-[--color-font] focus:bg-[--hl-sm] aria-selected:bg-[--hl-xs] aria-selected:text-[--color-font] aria-selected:hover:bg-[--hl-sm] aria-selected:focus:bg-[--hl-sm]"
158174
id="headers"
@@ -280,6 +296,15 @@ export const SocketIORequestPane: FC<Props> = ({ environment }) => {
280296
<TabPanel className="w-full flex-1 overflow-y-auto" id="events">
281297
<SocketIOEventTabPane request={activeRequest} eventListeners={activeRequest.eventListeners} />
282298
</TabPanel>
299+
<TabPanel className="w-full flex-1 overflow-y-auto" id="auth">
300+
<AuthWrapper
301+
key={uniqueKey}
302+
authentication={activeRequest.authentication}
303+
disabled={readyState}
304+
authTypes={['singleToken']}
305+
hideOthers
306+
/>
307+
</TabPanel>
283308
<TabPanel className="w-full flex-1 overflow-y-auto" id="headers">
284309
{disabled && <PaneReadOnlyBanner />}
285310
<RequestHeadersEditor

0 commit comments

Comments
 (0)