Skip to content

Commit

Permalink
[INS-1805] Add Auth Header Tab (#5115)
Browse files Browse the repository at this point in the history
* add minimal change to the auth flow

* add disable state

* adding dropdown disable

* simplify reducer

* fix lint

Co-authored-by: jackkav <jackkav@gmail.com>
  • Loading branch information
marckong and jackkav committed Sep 9, 2022
1 parent 06ef212 commit bbb61f5
Show file tree
Hide file tree
Showing 18 changed files with 217 additions and 81 deletions.
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
181 changes: 136 additions & 45 deletions packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@ import React, { FC, 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

0 comments on commit bbb61f5

Please sign in to comment.