Skip to content
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

Refactor/oauth2 #5571

Merged
merged 53 commits into from
Jan 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b24acb4
get-token
jackkav Dec 18, 2022
19b031d
named export
jackkav Dec 18, 2022
b5412e3
another pass
jackkav Dec 18, 2022
7311426
exporting const breaks types in a good way
jackkav Dec 18, 2022
4eee870
flatten optional params
jackkav Dec 18, 2022
7102a21
remove silly db functions
jackkav Dec 18, 2022
5e37d79
remove junk function in db models
jackkav Dec 18, 2022
7b0a693
flatten grant auth code
jackkav Dec 18, 2022
824ab43
simplify responseToObject
jackkav Dec 18, 2022
9321e51
improve response to object typing
jackkav Dec 19, 2022
a2c2cc5
use union type for auth keys
jackkav Dec 19, 2022
7c28dbf
remove authkey constants
jackkav Dec 19, 2022
34ec8af
some hacking
jackkav Dec 20, 2022
2f4b0b9
another pass
jackkav Dec 20, 2022
e8eed15
unpacking
jackkav Dec 20, 2022
a660667
obscure auth object
jackkav Dec 20, 2022
e0b5762
fix auth code types
jackkav Dec 30, 2022
01002b3
fix grant implicit types
jackkav Dec 30, 2022
5bc3d8f
remove oauth2 token from redux store
jackkav Dec 30, 2022
762ee98
fix oauth method args
jackkav Dec 30, 2022
f90ce65
extract network from grant auth code
jackkav Dec 30, 2022
b25320c
extract send from grant password
jackkav Dec 30, 2022
67d8a12
extract grant implicit
jackkav Dec 30, 2022
d6125ec
extract client creds
jackkav Dec 30, 2022
3985816
flatten param generator
jackkav Dec 30, 2022
03b72d5
extract nuller
jackkav Dec 30, 2022
8d26dd3
flatten refresh token
jackkav Dec 30, 2022
c2c9157
flatten refresh token
jackkav Dec 30, 2022
f2a18ab
fix types
jackkav Dec 30, 2022
b960832
remove tests
jackkav Dec 30, 2022
1d5df15
fix test flake
jackkav Dec 31, 2022
bc042af
fix gql body test import
jackkav Jan 1, 2023
770d9e4
fix typos
jackkav Jan 1, 2023
d84cc7e
fix grant auth
jackkav Jan 3, 2023
adb856a
fix token clear
jackkav Jan 3, 2023
866ed5f
fix token state
jackkav Jan 3, 2023
d1d9e62
fix auth header logic
jackkav Jan 3, 2023
bdadeda
fix types
jackkav Jan 3, 2023
700fc77
fix
jackkav Jan 3, 2023
208e33e
simplification pass
jackkav Jan 3, 2023
de2c0c2
fix code verifier
jackkav Jan 3, 2023
8fa72e7
flatten implicit grant type
jackkav Jan 3, 2023
18144c8
fix typo
jackkav Jan 3, 2023
7e0feb3
use consistent url parsers
jackkav Jan 3, 2023
91f23cd
flatten grant auth code
jackkav Jan 4, 2023
d1b7fa7
fix typo
jackkav Jan 4, 2023
807e4cc
type oauth2
jackkav Jan 5, 2023
7a6d5f9
improve helper and tidy
jackkav Jan 5, 2023
8eacdd6
fix type
jackkav Jan 5, 2023
48e1b86
tidy
jackkav Jan 5, 2023
5cbe194
tidy
jackkav Jan 5, 2023
2830b95
tidy up
jackkav Jan 5, 2023
d6d19d3
remove some constants
jackkav Jan 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/insomnia/src/common/har.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Cookie as ToughCookie } from 'tough-cookie';

import * as models from '../models';
import type { Request } from '../models/request';
import { newBodyRaw } from '../models/request';
import type { Response } from '../models/response';
import { isWorkspace } from '../models/workspace';
import { getAuthHeader } from '../network/authentication';
Expand Down Expand Up @@ -423,7 +422,7 @@ function getResponseCookies(response: Response) {

try {
cookie = ToughCookie.parse(harCookie.value || '');
} catch (error) {}
} catch (error) { }

if (cookie === null || cookie === undefined) {
return accumulator;
Expand Down Expand Up @@ -520,10 +519,11 @@ function getRequestQueryString(renderedRequest: RenderedRequest): HarQueryString

function getRequestPostData(renderedRequest: RenderedRequest): HarPostData | undefined {
let body;

if (renderedRequest.body.fileName) {
try {
body = newBodyRaw(fs.readFileSync(renderedRequest.body.fileName, 'base64'));
body = {
text: fs.readFileSync(renderedRequest.body.fileName, 'base64'),
};
} catch (error) {
console.warn('[code gen] Failed to read file', error);
return;
Expand Down
14 changes: 7 additions & 7 deletions packages/insomnia/src/models/__tests__/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { beforeEach, describe, expect, it, jest } from '@jest/globals';

import { globalBeforeEach } from '../../__jest__/before-each';
import { CONTENT_TYPE_GRAPHQL } from '../../common/constants';
import { newBodyGraphQL, updateMimeType } from '../../ui/components/panes/request-pane';
import * as models from '../index';
import { newBodyGraphQL } from '../request';

describe('init()', () => {
beforeEach(globalBeforeEach);
Expand Down Expand Up @@ -87,7 +87,7 @@ describe('updateMimeType()', () => {
parentId: 'fld_1',
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, 'text/html');
const newRequest = await updateMimeType(request, 'text/html');
expect(newRequest.headers).toEqual([
{
name: 'Content-Type',
Expand Down Expand Up @@ -116,7 +116,7 @@ describe('updateMimeType()', () => {
],
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, 'text/html');
const newRequest = await updateMimeType(request, 'text/html');
expect(newRequest.headers).toEqual([
{
name: 'content-tYPE',
Expand Down Expand Up @@ -145,7 +145,7 @@ describe('updateMimeType()', () => {
],
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, 'text/html');
const newRequest = await updateMimeType(request, 'text/html');
expect(newRequest.headers).toEqual([
{
name: 'content-tYPE',
Expand All @@ -166,7 +166,7 @@ describe('updateMimeType()', () => {
],
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, null);
const newRequest = await updateMimeType(request, null);
expect(newRequest.body).toEqual({});
expect(newRequest.headers).toEqual([]);
});
Expand All @@ -180,7 +180,7 @@ describe('updateMimeType()', () => {
},
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, 'application/json', false, {
const newRequest = await updateMimeType(request, 'application/json', false, {
text: 'Saved Data',
});
expect(newRequest.body.text).toEqual('Saved Data');
Expand All @@ -195,7 +195,7 @@ describe('updateMimeType()', () => {
},
});
expect(request).not.toBeNull();
const newRequest = await models.request.updateMimeType(request, 'application/json', false, {});
const newRequest = await updateMimeType(request, 'application/json', false, {});
expect(newRequest.body.text).toEqual('My Data');
});
});
Expand Down
205 changes: 35 additions & 170 deletions packages/insomnia/src/models/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,12 @@ import {
AUTH_NTLM,
AUTH_OAUTH_1,
AUTH_OAUTH_2,
CONTENT_TYPE_FILE,
CONTENT_TYPE_FORM_DATA,
CONTENT_TYPE_FORM_URLENCODED,
CONTENT_TYPE_GRAPHQL,
CONTENT_TYPE_JSON,
CONTENT_TYPE_OTHER,
getContentTypeFromHeaders,
HAWK_ALGORITHM_SHA256,
METHOD_GET,
METHOD_POST,
} from '../common/constants';
import { database as db } from '../common/database';
import { getContentTypeHeader } from '../common/misc';
import { SIGNATURE_METHOD_HMAC_SHA1 } from '../network/o-auth-1/constants';
import { GRANT_TYPE_AUTHORIZATION_CODE } from '../network/o-auth-2/constants';
import { deconstructQueryStringToParams } from '../utils/url/querystring';
Expand All @@ -38,7 +31,30 @@ export const canDuplicate = true;
export const canSync = true;

export type RequestAuthentication = Record<string, any>;

export interface AuthTypeOAuth2 {
type: 'oauth2';
grantType: 'authorization_code' | 'client_credentials' | 'password' | 'implicit' | 'refresh_token';
accessTokenUrl?: string;
authorizationUrl?: string;
clientId?: string;
clientSecret?: string;
audience?: string;
scope?: string;
resource?: string;
username?: string;
password?: string;
redirectUrl?: string;
credentialsInBody?: boolean;
state?: string;
code?: string;
accessToken?: string;
refreshToken?: string;
tokenPrefix?: string;
usePkce?: boolean;
pkceMethod?: string;
responseType?: string;
origin?: string;
}
export interface RequestHeader {
name: string;
value: string;
Expand Down Expand Up @@ -206,65 +222,6 @@ export function newAuth(type: string, oldAuth: RequestAuthentication = {}): Requ
}
}

export function newBodyNone(): RequestBody {
return {};
}

export function newBodyRaw(rawBody: string, contentType?: string): RequestBody {
if (typeof contentType !== 'string') {
return {
text: rawBody,
};
}

const mimeType = contentType.split(';')[0];
return {
mimeType,
text: rawBody,
};
}

export function newBodyGraphQL(rawBody: string): RequestBody {
try {
// Only strip the newlines if rawBody is a parsable JSON
JSON.parse(rawBody);
return {
mimeType: CONTENT_TYPE_GRAPHQL,
text: rawBody.replace(/\\\\n/g, ''),
};
} catch (error) {
if (error instanceof SyntaxError) {
return {
mimeType: CONTENT_TYPE_GRAPHQL,
text: rawBody,
};
} else {
throw error;
}
}
}

export function newBodyFormUrlEncoded(parameters: RequestBodyParameter[] | null): RequestBody {
return {
mimeType: CONTENT_TYPE_FORM_URLENCODED,
params: parameters || [],
};
}

export function newBodyFile(path: string): RequestBody {
return {
mimeType: CONTENT_TYPE_FILE,
fileName: path,
};
}

export function newBodyForm(parameters: RequestBodyParameter[]): RequestBody {
return {
mimeType: CONTENT_TYPE_FORM_DATA,
params: parameters || [],
};
}

export function migrate(doc: Request): Request {
doc = migrateBody(doc);
doc = migrateWeirdUrls(doc);
Expand Down Expand Up @@ -292,105 +249,6 @@ export function update(request: Request, patch: Partial<Request>) {
return db.docUpdate<Request>(request, patch);
}

export function updateMimeType(
request: Request,
mimeType: string,
doCreate = false,
savedBody: RequestBody = {},
) {
let headers = request.headers ? [...request.headers] : [];
const contentTypeHeader = getContentTypeHeader(headers);
// GraphQL uses JSON content-type
const contentTypeHeaderValue = mimeType === CONTENT_TYPE_GRAPHQL ? CONTENT_TYPE_JSON : mimeType;

// GraphQL must be POST
if (mimeType === CONTENT_TYPE_GRAPHQL) {
request.method = METHOD_POST;
}

// Check if we are converting to/from variants of XML or JSON
let leaveContentTypeAlone = false;

if (contentTypeHeader && mimeType) {
const current = contentTypeHeader.value;

if (current.includes('xml') && mimeType.includes('xml')) {
leaveContentTypeAlone = true;
} else if (current.includes('json') && mimeType.includes('json')) {
leaveContentTypeAlone = true;
}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
// 1. Update Content-Type header //
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //
const hasBody = typeof mimeType === 'string';

if (!hasBody) {
headers = headers.filter(h => h !== contentTypeHeader);
} else if (mimeType === CONTENT_TYPE_OTHER) {
// Leave headers alone
} else if (mimeType && contentTypeHeader && !leaveContentTypeAlone) {
contentTypeHeader.value = contentTypeHeaderValue;
} else if (mimeType && !contentTypeHeader) {
headers.push({
name: 'Content-Type',
value: contentTypeHeaderValue,
});
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
// 2. Make a new request body //
// ~~~~~~~~~~~~~~~~~~~~~~~~~~ //
let body;
const oldBody = Object.keys(savedBody).length === 0 ? request.body : savedBody;

if (mimeType === CONTENT_TYPE_FORM_URLENCODED) {
// Urlencoded
body = oldBody.params
? newBodyFormUrlEncoded(oldBody.params)
// @ts-expect-error -- TSCONVERSION
: newBodyFormUrlEncoded(deconstructQueryStringToParams(oldBody.text));
} else if (mimeType === CONTENT_TYPE_FORM_DATA) {
// Form Data
body = oldBody.params
? newBodyForm(oldBody.params)
// @ts-expect-error -- TSCONVERSION
: newBodyForm(deconstructQueryStringToParams(oldBody.text));
} else if (mimeType === CONTENT_TYPE_FILE) {
// File
body = newBodyFile('');
} else if (mimeType === CONTENT_TYPE_GRAPHQL) {
if (contentTypeHeader) {
contentTypeHeader.value = CONTENT_TYPE_JSON;
}

body = newBodyGraphQL(oldBody.text || '');
} else if (typeof mimeType !== 'string') {
// No body
body = newBodyNone();
} else {
// Raw Content-Type (ex: application/json)
body = newBodyRaw(oldBody.text || '', mimeType);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~ //
// 2. create/update request //
// ~~~~~~~~~~~~~~~~~~~~~~~~ //
if (doCreate) {
const newRequest: Request = Object.assign({}, request, {
headers,
body,
});
return create(newRequest);
} else {
return update(request, {
headers,
body,
});
}
}

export async function duplicate(request: Request, patch: Partial<Request> = {}) {
// Only set name and "(Copy)" if the patch does
// not define it and the request itself has a name.
Expand Down Expand Up @@ -450,13 +308,20 @@ function migrateBody(request: Request) {

if (wasFormUrlEncoded) {
// Convert old-style form-encoded request bodies to new style
const body = typeof request.body === 'string' ? request.body : '';
request.body = newBodyFormUrlEncoded(deconstructQueryStringToParams(body, false));
request.body = {
mimeType: CONTENT_TYPE_FORM_URLENCODED,
params: deconstructQueryStringToParams(typeof request.body === 'string' ? request.body : '', false),
};
} else if (!request.body && !contentType) {
request.body = {};
} else {
const body: string = typeof request.body === 'string' ? request.body : '';
request.body = newBodyRaw(body, contentType);
const rawBody: string = typeof request.body === 'string' ? request.body : '';
request.body = typeof contentType !== 'string' ? {
text: rawBody,
} : {
mimeType: contentType.split(';')[0],
text: rawBody,
};
}

return request;
Expand Down
13 changes: 4 additions & 9 deletions packages/insomnia/src/models/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export async function getLatestForRequest(
return response || null;
}

export async function create(patch: Record<string, any> = {}, maxResponses = 20) {
export async function create(patch: Partial<Response> = {}, maxResponses = 20): Promise<Response> {
if (!patch.parentId) {
throw new Error('New Response missing `parentId`');
}
Expand All @@ -168,17 +168,12 @@ export async function create(patch: Record<string, any> = {}, maxResponses = 20)
const requestVersion = request ? await models.requestVersion.create(request) : null;
patch.requestVersionId = requestVersion ? requestVersion._id : null;
// Filter responses by environment if setting is enabled
const query: Record<string, any> = {
const shouldQueryByEnvId = (await models.settings.getOrCreate()).filterResponsesByEnv && patch.hasOwnProperty('environmentId');
const query = {
parentId,
...(shouldQueryByEnvId ? { environmentId: patch.environmentId } : {}),
};

if (
(await models.settings.getOrCreate()).filterResponsesByEnv &&
patch.hasOwnProperty('environmentId')
) {
query.environmentId = patch.environmentId;
}

// Delete all other responses before creating the new one
const allResponses = await db.findMostRecentlyModified<Response>(type, query, Math.max(1, maxResponses));
const recentIds = allResponses.map(r => r._id);
Expand Down
6 changes: 3 additions & 3 deletions packages/insomnia/src/network/authentication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import {
AUTH_OAUTH_2,
} from '../common/constants';
import type { RenderedRequest } from '../common/render';
import { RequestAuthentication, RequestParameter } from '../models/request';
import { AuthTypeOAuth2, RequestAuthentication, RequestParameter } from '../models/request';
import { COOKIE, HEADER, QUERY_PARAMS } from './api-key/constants';
import { getBasicAuthHeader } from './basic-auth/get-header';
import { getBearerAuthHeader } from './bearer-auth/get-header';
import getOAuth1Token from './o-auth-1/get-token';
import getOAuth2Token from './o-auth-2/get-token';
import { getOAuth2Token } from './o-auth-2/get-token';

interface Header {
name: string;
Expand Down Expand Up @@ -64,7 +64,7 @@ export async function getAuthHeader(renderedRequest: RenderedRequest, url: strin
// pretending we are fetching a token for the original request. This makes sure
// the same tokens are used for schema fetching. See issue #835 on GitHub.
const tokenId = requestId.match(/\.graphql$/) ? requestId.replace(/\.graphql$/, '') : requestId;
const oAuth2Token = await getOAuth2Token(tokenId, authentication);
const oAuth2Token = await getOAuth2Token(tokenId, authentication as AuthTypeOAuth2);

if (oAuth2Token) {
const token = oAuth2Token.accessToken;
Expand Down