Skip to content

[INS-1805] Add Auth Header Tab #5115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from 4 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
15 changes: 14 additions & 1 deletion packages/insomnia/src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,20 @@ export const isDevelopment = () => getAppEnvironment() === 'development';
export const getSegmentWriteKey = () => appConfig.segmentWriteKeys[(isDevelopment() || env.PLAYWRIGHT) ? 'development' : 'production'];
export const getSentryDsn = () => appConfig.sentryDsn;
export const getAppBuildDate = () => new Date(process.env.BUILD_DATE ?? '').toLocaleDateString();

export type AuthType =
| 'none'
| 'oauth2'
| 'oauth1'
| 'basic'
| 'digest'
| 'bearer'
| 'ntlm'
| 'hawk'
| 'iam'
| 'netrc'
| 'asap'
| 'sha256'
| 'sha1';
export const getBrowserUserAgent = () => encodeURIComponent(
String(window.navigator.userAgent)
.replace(new RegExp(`${getAppId()}\\/\\d+\\.\\d+\\.\\d+ `), '')
Expand Down
4 changes: 3 additions & 1 deletion packages/insomnia/src/models/websocket-request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { database } from '../common/database';
import type { BaseModel } from '.';
import { RequestHeader } from './request';
import { RequestAuthentication, RequestHeader } from './request';

export const name = 'WebSocket Request';

Expand All @@ -18,6 +18,7 @@ export interface BaseWebSocketRequest {
url: string;
metaSortKey: number;
headers: RequestHeader[];
authentication: RequestAuthentication;
}

export type WebSocketRequest = BaseModel & BaseWebSocketRequest & { type: typeof type };
Expand All @@ -35,6 +36,7 @@ export const init = (): BaseWebSocketRequest => ({
url: '',
metaSortKey: -1 * Date.now(),
headers: [],
authentication: {},
});

export const migrate = (doc: WebSocketRequest) => doc;
Expand Down
183 changes: 137 additions & 46 deletions packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import React, { FC, useCallback } from 'react';
import React, { FC, ReactElement, useCallback } from 'react';
import { useSelector } from 'react-redux';

import {
AUTH_ASAP,
AUTH_AWS_IAM,
AUTH_BASIC,
AUTH_BEARER,
AUTH_DIGEST,
AUTH_HAWK,
AUTH_NETRC,
AUTH_NONE,
AUTH_NTLM,
AUTH_OAUTH_1,
AUTH_OAUTH_2,
AuthType,
getAuthTypeName,
HAWK_ALGORITHM_SHA256,
} from '../../../common/constants';
import * as models from '../../../models';
import { update } from '../../../models/helpers/request-operations';
import { isRequest } from '../../../models/request';
import { RequestAuthentication } from '../../../models/request';
import { SIGNATURE_METHOD_HMAC_SHA1 } from '../../../network/o-auth-1/constants';
import { GRANT_TYPE_AUTHORIZATION_CODE } from '../../../network/o-auth-2/constants';
import { selectActiveRequest } from '../../redux/selectors';
import { Dropdown } from '../base/dropdown/dropdown';
import { DropdownButton } from '../base/dropdown/dropdown-button';
Expand All @@ -26,11 +18,110 @@ import { DropdownItem } from '../base/dropdown/dropdown-item';
import { showModal } from '../modals';
import { AlertModal } from '../modals/alert-modal';

const defaultTypes: AuthType[] = [
'basic',
'digest',
'oauth1',
'oauth2',
'ntlm',
'iam',
'bearer',
'hawk',
'asap',
'netrc',
];

function makeNewAuth(type: string, oldAuth: RequestAuthentication = {}): RequestAuthentication {
switch (type) {
// No Auth
case 'none':
return {};

// HTTP Basic Authentication
case 'basic':
return {
type,
useISO88591: oldAuth.useISO88591 || false,
disabled: oldAuth.disabled || false,
username: oldAuth.username || '',
password: oldAuth.password || '',
};

case 'digest':
case 'ntlm':
return {
type,
disabled: oldAuth.disabled || false,
username: oldAuth.username || '',
password: oldAuth.password || '',
};

case 'oauth1':
return {
type,
disabled: false,
signatureMethod: SIGNATURE_METHOD_HMAC_SHA1,
consumerKey: '',
consumerSecret: '',
tokenKey: '',
tokenSecret: '',
privateKey: '',
version: '1.0',
nonce: '',
timestamp: '',
callback: '',
};

// OAuth 2.0
case 'oauth2':
return {
type,
grantType: GRANT_TYPE_AUTHORIZATION_CODE,
};

// Aws IAM
case 'iam':
return {
type,
disabled: oldAuth.disabled || false,
accessKeyId: oldAuth.accessKeyId || '',
secretAccessKey: oldAuth.secretAccessKey || '',
sessionToken: oldAuth.sessionToken || '',
};

// Hawk
case 'hawk':
return {
type,
algorithm: HAWK_ALGORITHM_SHA256,
};

// Atlassian ASAP
case 'asap':
return {
type,
issuer: '',
subject: '',
audience: '',
additionalClaims: '',
keyId: '',
privateKey: '',
};

// Types needing no defaults
case 'netrc':
default:
return {
type,
};
}
}

const AuthItem: FC<{
type: string;
type: AuthType;
nameOverride?: string;
isCurrent: (type: string) => boolean;
onClick: (type: string) => void;
isCurrent: (type: AuthType) => boolean;
onClick: (type: AuthType) => void;
}> = ({ type, nameOverride, isCurrent, onClick }) => (
<DropdownItem onClick={onClick} value={type}>
{<i className={`fa fa-${isCurrent(type) ? 'check' : 'empty'}`} />}{' '}
Expand All @@ -39,15 +130,15 @@ const AuthItem: FC<{
);
AuthItem.displayName = DropdownItem.name;

export const AuthDropdown: FC = () => {
interface Props {
authTypes?: AuthType[];
disabled?: boolean;
}
export const AuthDropdown: FC<Props> = ({ authTypes = defaultTypes, disabled = false }) => {
const activeRequest = useSelector(selectActiveRequest);

const onClick = useCallback(async (type: string) => {
if (!activeRequest) {
return;
}

if (!isRequest(activeRequest)) {
const onClick = useCallback(async (type: AuthType) => {
if (!activeRequest || !('authentication' in activeRequest)) {
return;
}

Expand All @@ -58,8 +149,8 @@ export const AuthDropdown: FC = () => {
return;
}

const newAuthentication = models.request.newAuth(type, authentication);
const defaultAuthentication = models.request.newAuth(authentication.type);
const newAuthentication = makeNewAuth(type, authentication);
const defaultAuthentication = makeNewAuth(authentication.type);

// Prompt the user if fields will change between new and old
for (const key of Object.keys(authentication)) {
Expand All @@ -80,16 +171,13 @@ export const AuthDropdown: FC = () => {
break;
}
}
update(activeRequest, { authentication:newAuthentication });
update(activeRequest, { authentication: newAuthentication });
}, [activeRequest]);
const isCurrent = useCallback((type: string) => {
if (!activeRequest) {
return false;
}
if (!isRequest(activeRequest)) {
const isCurrent = useCallback((type: AuthType) => {
if (!activeRequest || !('authentication' in activeRequest)) {
return false;
}
return type === (activeRequest.authentication.type || AUTH_NONE);
return type === (activeRequest.authentication.type || 'none');
}, [activeRequest]);

if (!activeRequest) {
Expand All @@ -101,22 +189,25 @@ export const AuthDropdown: FC = () => {
return (
<Dropdown beside>
<DropdownDivider>Auth Types</DropdownDivider>
<DropdownButton className="tall">
<DropdownButton className="tall" disabled={disabled}>
{'authentication' in activeRequest ? getAuthTypeName(activeRequest.authentication.type) || 'Auth' : 'Auth'}
<i className="fa fa-caret-down space-left" />
</DropdownButton>
<AuthItem type={AUTH_BASIC} {...itemProps} />
<AuthItem type={AUTH_DIGEST} {...itemProps} />
<AuthItem type={AUTH_OAUTH_1} {...itemProps} />
<AuthItem type={AUTH_OAUTH_2} {...itemProps} />
<AuthItem type={AUTH_NTLM} {...itemProps} />
<AuthItem type={AUTH_AWS_IAM} {...itemProps} />
<AuthItem type={AUTH_BEARER} {...itemProps} />
<AuthItem type={AUTH_HAWK} {...itemProps} />
<AuthItem type={AUTH_ASAP} {...itemProps} />
<AuthItem type={AUTH_NETRC} {...itemProps} />
<DropdownDivider>Other</DropdownDivider>
<AuthItem type={AUTH_NONE} nameOverride="No Authentication" {...itemProps} />
{authTypes.map(authType =>
<AuthItem
key={authType}
type={authType}
{...itemProps}
/>)}
<DropdownDivider key="divider-other">
Other
</DropdownDivider>
<AuthItem
key="none"
type="none"
nameOverride="No Authentication"
{...itemProps}
/>
</Dropdown>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import React, { FC } from 'react';
import { AuthInputRow } from './components/auth-input-row';
import { AuthPrivateKeyRow } from './components/auth-private-key-row';
import { AuthTableBody } from './components/auth-table-body';
import { AuthToggleRow } from './components/auth-toggle-row';

export const AsapAuth: FC = () => (
<AuthTableBody>
<AuthToggleRow label="Enabled" property="disabled" invert />
<AuthInputRow label='Issuer (iss)' property='issuer' />
<AuthInputRow label='Subject (sub)' property='subject' />
<AuthInputRow label='Audience (aud)' property='audience' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
AUTH_OAUTH_1,
AUTH_OAUTH_2,
} from '../../../../common/constants';
import { isRequest } from '../../../../models/request';
import { selectActiveRequest } from '../../../redux/selectors';
import { AsapAuth } from './asap-auth';
import { AWSAuth } from './aws-auth';
Expand All @@ -26,10 +25,10 @@ import { NTLMAuth } from './ntlm-auth';
import { OAuth1Auth } from './o-auth-1-auth';
import { OAuth2Auth } from './o-auth-2-auth';

export const AuthWrapper: FC = () => {
export const AuthWrapper: FC<{ disabled?: boolean }> = ({ disabled = false }) => {
const request = useSelector(selectActiveRequest);

if (!request || !isRequest(request)) {
if (!request || !('authentication' in request)) {
return null;
}

Expand All @@ -38,19 +37,19 @@ export const AuthWrapper: FC = () => {
let authBody: ReactNode = null;

if (type === AUTH_BASIC) {
authBody = <BasicAuth />;
authBody = <BasicAuth disabled={disabled} />;
} else if (type === AUTH_OAUTH_2) {
authBody = <OAuth2Auth />;
} else if (type === AUTH_HAWK) {
authBody = <HawkAuth />;
} else if (type === AUTH_OAUTH_1) {
authBody = <OAuth1Auth />;
} else if (type === AUTH_DIGEST) {
authBody = <DigestAuth />;
authBody = <DigestAuth disabled={disabled} />;
} else if (type === AUTH_NTLM) {
authBody = <NTLMAuth />;
} else if (type === AUTH_BEARER) {
authBody = <BearerAuth />;
authBody = <BearerAuth disabled={disabled} />;
} else if (type === AUTH_AWS_IAM) {
authBody = <AWSAuth />;
} else if (type === AUTH_NETRC) {
Expand Down
2 changes: 2 additions & 0 deletions packages/insomnia/src/ui/components/editors/auth/aws-auth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import React, { FC } from 'react';

import { AuthInputRow } from './components/auth-input-row';
import { AuthTableBody } from './components/auth-table-body';
import { AuthToggleRow } from './components/auth-toggle-row';

export const AWSAuth: FC = () => (
<AuthTableBody>
<AuthToggleRow label="Enabled" property="disabled" invert />
<AuthInputRow
label="Access Key ID"
property="accessKeyId"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { AuthInputRow } from './components/auth-input-row';
import { AuthTableBody } from './components/auth-table-body';
import { AuthToggleRow } from './components/auth-toggle-row';

export const BasicAuth: FC = () => (
export const BasicAuth: FC<{ disabled?: boolean }> = ({ disabled = false }) => (
<AuthTableBody>
<AuthInputRow label="Username" property="username" />
<AuthInputRow label="Password" property="password" mask />
<AuthToggleRow label="Enabled" property="disabled" invert disabled={disabled} />
<AuthInputRow label="Username" property="username" disabled={disabled} />
<AuthInputRow label="Password" property="password" mask disabled={disabled} />
<AuthToggleRow
label="Use ISO 8859-1"
help="Check this to use ISO-8859-1 encoding instead of default UTF-8"
property='useISO88591'
disabled={disabled}
/>
</AuthTableBody>
);
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import React, { FC } from 'react';

import { AuthInputRow } from './components/auth-input-row';
import { AuthTableBody } from './components/auth-table-body';
import { AuthToggleRow } from './components/auth-toggle-row';

export const BearerAuth: FC = () => (
export const BearerAuth: FC<{ disabled?: boolean }> = ({ disabled = false }) => (
<AuthTableBody>
<AuthInputRow label='Token' property='token' />
<AuthInputRow label='Prefix' property='prefix' />
<AuthToggleRow label="Enabled" property="disabled" invert disabled={disabled} />
<AuthInputRow label='Token' property='token' disabled={disabled} />
<AuthInputRow label='Prefix' property='prefix' disabled={disabled} />
</AuthTableBody>
);
Loading