From 0632743275e1c8773853762f4341caca4db8c273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Wed, 17 May 2023 10:27:55 +0200 Subject: [PATCH] Revert "feat(core): Replace client-oauth2 with an in-repo package (#6056)" This reverts commit 77ac953eafe64b96ccfd677cd5f417380702cf8d. --- .github/workflows/ci-master.yml | 2 +- .github/workflows/ci-pull-requests.yml | 2 +- packages/@n8n/client-oauth2/.eslintrc.js | 14 -- packages/@n8n/client-oauth2/jest.config.js | 2 - packages/@n8n/client-oauth2/package.json | 25 --- .../@n8n/client-oauth2/src/ClientOAuth2.ts | 109 ---------- .../client-oauth2/src/ClientOAuth2Token.ts | 100 --------- packages/@n8n/client-oauth2/src/CodeFlow.ts | 121 ----------- .../@n8n/client-oauth2/src/CredentialsFlow.ts | 52 ----- packages/@n8n/client-oauth2/src/constants.ts | 63 ------ packages/@n8n/client-oauth2/src/index.ts | 2 - packages/@n8n/client-oauth2/src/types.ts | 2 - packages/@n8n/client-oauth2/src/utils.ts | 83 -------- .../@n8n/client-oauth2/test/CodeFlow.test.ts | 189 ------------------ .../test/CredentialsFlow.test.ts | 116 ----------- packages/@n8n/client-oauth2/test/config.ts | 15 -- .../@n8n/client-oauth2/tsconfig.build.json | 12 -- packages/@n8n/client-oauth2/tsconfig.json | 15 -- packages/cli/package.json | 2 +- .../src/credentials/oauth2Credential.api.ts | 15 +- packages/cli/tsconfig.json | 3 +- packages/core/package.json | 2 +- packages/core/src/NodeExecuteFunctions.ts | 48 ++--- packages/core/src/OAuth2Helper.ts | 10 +- packages/core/tsconfig.json | 5 +- pnpm-lock.yaml | 139 +++++++++++-- pnpm-workspace.yaml | 1 - 27 files changed, 163 insertions(+), 986 deletions(-) delete mode 100644 packages/@n8n/client-oauth2/.eslintrc.js delete mode 100644 packages/@n8n/client-oauth2/jest.config.js delete mode 100644 packages/@n8n/client-oauth2/package.json delete mode 100644 packages/@n8n/client-oauth2/src/ClientOAuth2.ts delete mode 100644 packages/@n8n/client-oauth2/src/ClientOAuth2Token.ts delete mode 100644 packages/@n8n/client-oauth2/src/CodeFlow.ts delete mode 100644 packages/@n8n/client-oauth2/src/CredentialsFlow.ts delete mode 100644 packages/@n8n/client-oauth2/src/constants.ts delete mode 100644 packages/@n8n/client-oauth2/src/index.ts delete mode 100644 packages/@n8n/client-oauth2/src/types.ts delete mode 100644 packages/@n8n/client-oauth2/src/utils.ts delete mode 100644 packages/@n8n/client-oauth2/test/CodeFlow.test.ts delete mode 100644 packages/@n8n/client-oauth2/test/CredentialsFlow.test.ts delete mode 100644 packages/@n8n/client-oauth2/test/config.ts delete mode 100644 packages/@n8n/client-oauth2/tsconfig.build.json delete mode 100644 packages/@n8n/client-oauth2/tsconfig.json diff --git a/.github/workflows/ci-master.yml b/.github/workflows/ci-master.yml index 53ea34eb91ae8..f7a0f8f21aa5e 100644 --- a/.github/workflows/ci-master.yml +++ b/.github/workflows/ci-master.yml @@ -38,7 +38,7 @@ jobs: - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: - files: packages/@n8n/client-oauth2/coverage/cobertura-coverage.xml,packages/cli/coverage/cobertura-coverage.xml,packages/core/coverage/cobertura-coverage.xml,packages/design-system/coverage/cobertura-coverage.xml,packages/editor-ui/coverage/cobertura-coverage.xml,packages/nodes-base/coverage/cobertura-coverage.xml,packages/workflow/coverage/cobertura-coverage.xml + files: packages/cli/coverage/cobertura-coverage.xml,packages/core/coverage/cobertura-coverage.xml,packages/design-system/coverage/cobertura-coverage.xml,packages/editor-ui/coverage/cobertura-coverage.xml,packages/nodes-base/coverage/cobertura-coverage.xml,packages/workflow/coverage/cobertura-coverage.xml - name: Lint env: diff --git a/.github/workflows/ci-pull-requests.yml b/.github/workflows/ci-pull-requests.yml index 01e913b010580..e6d4cdabd741c 100644 --- a/.github/workflows/ci-pull-requests.yml +++ b/.github/workflows/ci-pull-requests.yml @@ -70,7 +70,7 @@ jobs: - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: - files: packages/@n8n/client-oauth2/coverage/cobertura-coverage.xml,packages/cli/coverage/cobertura-coverage.xml,packages/core/coverage/cobertura-coverage.xml,packages/design-system/coverage/cobertura-coverage.xml,packages/editor-ui/coverage/cobertura-coverage.xml,packages/nodes-base/coverage/cobertura-coverage.xml,packages/workflow/coverage/cobertura-coverage.xml + files: packages/cli/coverage/cobertura-coverage.xml,packages/core/coverage/cobertura-coverage.xml,packages/design-system/coverage/cobertura-coverage.xml,packages/editor-ui/coverage/cobertura-coverage.xml,packages/nodes-base/coverage/cobertura-coverage.xml,packages/workflow/coverage/cobertura-coverage.xml lint: name: Lint changes diff --git a/packages/@n8n/client-oauth2/.eslintrc.js b/packages/@n8n/client-oauth2/.eslintrc.js deleted file mode 100644 index fe7469cf3c7af..0000000000000 --- a/packages/@n8n/client-oauth2/.eslintrc.js +++ /dev/null @@ -1,14 +0,0 @@ -const { sharedOptions } = require('@n8n_io/eslint-config/shared'); - -/** - * @type {import('@types/eslint').ESLint.ConfigData} - */ -module.exports = { - extends: ['@n8n_io/eslint-config/base'], - - ...sharedOptions(__dirname), - - rules: { - '@typescript-eslint/consistent-type-imports': 'error', - }, -}; diff --git a/packages/@n8n/client-oauth2/jest.config.js b/packages/@n8n/client-oauth2/jest.config.js deleted file mode 100644 index d6c48554a79a4..0000000000000 --- a/packages/@n8n/client-oauth2/jest.config.js +++ /dev/null @@ -1,2 +0,0 @@ -/** @type {import('jest').Config} */ -module.exports = require('../../../jest.config'); diff --git a/packages/@n8n/client-oauth2/package.json b/packages/@n8n/client-oauth2/package.json deleted file mode 100644 index 6acda89b76742..0000000000000 --- a/packages/@n8n/client-oauth2/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "@n8n/client-oauth2", - "version": "0.1.0", - "scripts": { - "clean": "rimraf dist .turbo", - "dev": "pnpm watch", - "typecheck": "tsc", - "build": "tsc -p tsconfig.build.json", - "format": "prettier --write . --ignore-path ../../../.prettierignore", - "lint": "eslint --quiet .", - "lintfix": "eslint . --fix", - "watch": "tsc -p tsconfig.build.json --watch", - "test": "jest", - "test:dev": "jest --watch" - }, - "main": "dist/index.js", - "module": "src/index.ts", - "types": "dist/index.d.ts", - "files": [ - "dist/**/*" - ], - "dependencies": { - "axios": "^0.21.1" - } -} diff --git a/packages/@n8n/client-oauth2/src/ClientOAuth2.ts b/packages/@n8n/client-oauth2/src/ClientOAuth2.ts deleted file mode 100644 index 8900666a84159..0000000000000 --- a/packages/@n8n/client-oauth2/src/ClientOAuth2.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/restrict-plus-operands */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import * as qs from 'querystring'; -import axios from 'axios'; -import { getAuthError } from './utils'; -import type { ClientOAuth2TokenData } from './ClientOAuth2Token'; -import { ClientOAuth2Token } from './ClientOAuth2Token'; -import { CodeFlow } from './CodeFlow'; -import { CredentialsFlow } from './CredentialsFlow'; -import type { Headers, Query } from './types'; - -export interface ClientOAuth2RequestObject { - url: string; - method: 'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT'; - body?: Record; - query?: Query; - headers?: Headers; -} - -export interface ClientOAuth2Options { - clientId: string; - clientSecret: string; - accessTokenUri: string; - authorizationUri?: string; - redirectUri?: string; - scopes?: string[]; - authorizationGrants?: string[]; - state?: string; - body?: Record; - query?: Query; - headers?: Headers; -} - -class ResponseError extends Error { - constructor(readonly status: number, readonly body: object, readonly code = 'ESTATUS') { - super(`HTTP status ${status}`); - } -} - -/** - * Construct an object that can handle the multiple OAuth 2.0 flows. - */ -export class ClientOAuth2 { - code: CodeFlow; - - credentials: CredentialsFlow; - - constructor(readonly options: ClientOAuth2Options) { - this.code = new CodeFlow(this); - this.credentials = new CredentialsFlow(this); - } - - /** - * Create a new token from existing data. - */ - createToken(data: ClientOAuth2TokenData, type?: string): ClientOAuth2Token { - return new ClientOAuth2Token(this, { - ...data, - ...(typeof type === 'string' ? { token_type: type } : type), - }); - } - - /** - * Attempt to parse response body as JSON, fall back to parsing as a query string. - */ - private parseResponseBody(body: string): T { - try { - return JSON.parse(body); - } catch (e) { - return qs.parse(body) as T; - } - } - - /** - * Using the built-in request method, we'll automatically attempt to parse - * the response. - */ - async request(options: ClientOAuth2RequestObject): Promise { - let url = options.url; - const query = qs.stringify(options.query); - - if (query) { - url += (url.indexOf('?') === -1 ? '?' : '&') + query; - } - - const response = await axios.request({ - url, - method: options.method, - data: qs.stringify(options.body), - headers: options.headers, - transformResponse: (res) => res, - }); - - const body = this.parseResponseBody(response.data); - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const authErr = getAuthError(body); - if (authErr) throw authErr; - - if (response.status < 200 || response.status >= 399) - throw new ResponseError(response.status, response.data); - - return body; - } -} diff --git a/packages/@n8n/client-oauth2/src/ClientOAuth2Token.ts b/packages/@n8n/client-oauth2/src/ClientOAuth2Token.ts deleted file mode 100644 index 5c749a9009074..0000000000000 --- a/packages/@n8n/client-oauth2/src/ClientOAuth2Token.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/naming-convention */ -import type { ClientOAuth2, ClientOAuth2Options, ClientOAuth2RequestObject } from './ClientOAuth2'; -import { auth, getRequestOptions } from './utils'; -import { DEFAULT_HEADERS } from './constants'; - -export interface ClientOAuth2TokenData extends Record { - token_type?: string | undefined; - access_token: string; - refresh_token: string; - expires_in?: string; - scope?: string | undefined; -} -/** - * General purpose client token generator. - */ -export class ClientOAuth2Token { - readonly tokenType?: string; - - readonly accessToken: string; - - readonly refreshToken: string; - - private expires: Date; - - constructor(readonly client: ClientOAuth2, readonly data: ClientOAuth2TokenData) { - this.tokenType = data.token_type?.toLowerCase() ?? 'bearer'; - this.accessToken = data.access_token; - this.refreshToken = data.refresh_token; - - this.expires = new Date(); - this.expires.setSeconds(this.expires.getSeconds() + Number(data.expires_in)); - } - - /** - * Sign a standardized request object with user authentication information. - */ - sign(requestObject: ClientOAuth2RequestObject): ClientOAuth2RequestObject { - if (!this.accessToken) { - throw new Error('Unable to sign without access token'); - } - - requestObject.headers = requestObject.headers ?? {}; - - if (this.tokenType === 'bearer') { - requestObject.headers.Authorization = 'Bearer ' + this.accessToken; - } else { - const parts = requestObject.url.split('#'); - const token = 'access_token=' + this.accessToken; - const url = parts[0].replace(/[?&]access_token=[^&#]/, ''); - const fragment = parts[1] ? '#' + parts[1] : ''; - - // Prepend the correct query string parameter to the url. - requestObject.url = url + (url.indexOf('?') > -1 ? '&' : '?') + token + fragment; - - // Attempt to avoid storing the url in proxies, since the access token - // is exposed in the query parameters. - requestObject.headers.Pragma = 'no-store'; - requestObject.headers['Cache-Control'] = 'no-store'; - } - - return requestObject; - } - - /** - * Refresh a user access token with the supplied token. - */ - async refresh(opts?: ClientOAuth2Options): Promise { - const options = { ...this.client.options, ...opts }; - - if (!this.refreshToken) throw new Error('No refresh token'); - - const requestOptions = getRequestOptions( - { - url: options.accessTokenUri, - method: 'POST', - headers: { - ...DEFAULT_HEADERS, - Authorization: auth(options.clientId, options.clientSecret), - }, - body: { - refresh_token: this.refreshToken, - grant_type: 'refresh_token', - }, - }, - options, - ); - - const responseData = await this.client.request(requestOptions); - return this.client.createToken({ ...this.data, ...responseData }); - } - - /** - * Check whether the token has expired. - */ - expired(): boolean { - return Date.now() > this.expires.getTime(); - } -} diff --git a/packages/@n8n/client-oauth2/src/CodeFlow.ts b/packages/@n8n/client-oauth2/src/CodeFlow.ts deleted file mode 100644 index f25feb574c33c..0000000000000 --- a/packages/@n8n/client-oauth2/src/CodeFlow.ts +++ /dev/null @@ -1,121 +0,0 @@ -import * as qs from 'querystring'; -import type { ClientOAuth2, ClientOAuth2Options } from './ClientOAuth2'; -import type { ClientOAuth2Token, ClientOAuth2TokenData } from './ClientOAuth2Token'; -import { DEFAULT_HEADERS, DEFAULT_URL_BASE } from './constants'; -import { auth, expects, getAuthError, getRequestOptions, sanitizeScope } from './utils'; - -interface CodeFlowBody { - code: string | string[]; - grant_type: 'authorization_code'; - redirect_uri?: string; - client_id?: string; -} - -/** - * Support authorization code OAuth 2.0 grant. - * - * Reference: http://tools.ietf.org/html/rfc6749#section-4.1 - */ -export class CodeFlow { - constructor(private client: ClientOAuth2) {} - - /** - * Generate the uri for doing the first redirect. - */ - getUri(opts?: ClientOAuth2Options): string { - const options = { ...this.client.options, ...opts }; - - // Check the required parameters are set. - expects(options, 'clientId', 'authorizationUri'); - - const query: Record = { - client_id: options.clientId, - redirect_uri: options.redirectUri, - response_type: 'code', - state: options.state, - }; - if (options.scopes !== undefined) { - query.scope = sanitizeScope(options.scopes); - } - - if (options.authorizationUri) { - const sep = options.authorizationUri.includes('?') ? '&' : '?'; - return options.authorizationUri + sep + qs.stringify({ ...query, ...options.query }); - } - throw new TypeError('Missing authorization uri, unable to get redirect uri'); - } - - /** - * Get the code token from the redirected uri and make another request for - * the user access token. - */ - async getToken( - uri: string | URL, - opts?: Partial, - ): Promise { - const options = { ...this.client.options, ...opts }; - - expects(options, 'clientId', 'accessTokenUri'); - - const url = uri instanceof URL ? uri : new URL(uri, DEFAULT_URL_BASE); - if ( - typeof options.redirectUri === 'string' && - typeof url.pathname === 'string' && - url.pathname !== new URL(options.redirectUri, DEFAULT_URL_BASE).pathname - ) { - throw new TypeError('Redirected path should match configured path, but got: ' + url.pathname); - } - - if (!url.search?.substring(1)) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new TypeError(`Unable to process uri: ${uri.toString()}`); - } - - const data = - typeof url.search === 'string' ? qs.parse(url.search.substring(1)) : url.search || {}; - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - const error = getAuthError(data); - if (error) throw error; - - if (options.state && data.state !== options.state) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new TypeError(`Invalid state: ${data.state}`); - } - - // Check whether the response code is set. - if (!data.code) { - throw new TypeError('Missing code, unable to request token'); - } - - const headers = { ...DEFAULT_HEADERS }; - const body: CodeFlowBody = { - code: data.code, - grant_type: 'authorization_code', - redirect_uri: options.redirectUri, - }; - - // `client_id`: REQUIRED, if the client is not authenticating with the - // authorization server as described in Section 3.2.1. - // Reference: https://tools.ietf.org/html/rfc6749#section-3.2.1 - if (options.clientSecret) { - headers.Authorization = auth(options.clientId, options.clientSecret); - } else { - body.client_id = options.clientId; - } - - const requestOptions = getRequestOptions( - { - url: options.accessTokenUri, - method: 'POST', - headers, - body, - }, - options, - ); - - const responseData = await this.client.request(requestOptions); - return this.client.createToken(responseData); - } -} diff --git a/packages/@n8n/client-oauth2/src/CredentialsFlow.ts b/packages/@n8n/client-oauth2/src/CredentialsFlow.ts deleted file mode 100644 index 3bc7c2ac3aca3..0000000000000 --- a/packages/@n8n/client-oauth2/src/CredentialsFlow.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { ClientOAuth2, ClientOAuth2Options } from './ClientOAuth2'; -import type { ClientOAuth2Token, ClientOAuth2TokenData } from './ClientOAuth2Token'; -import { DEFAULT_HEADERS } from './constants'; -import { auth, expects, getRequestOptions, sanitizeScope } from './utils'; - -interface CredentialsFlowBody { - grant_type: 'client_credentials'; - scope?: string; -} - -/** - * Support client credentials OAuth 2.0 grant. - * - * Reference: http://tools.ietf.org/html/rfc6749#section-4.4 - */ -export class CredentialsFlow { - constructor(private client: ClientOAuth2) {} - - /** - * Request an access token using the client credentials. - */ - async getToken(opts?: Partial): Promise { - const options = { ...this.client.options, ...opts }; - - expects(options, 'clientId', 'clientSecret', 'accessTokenUri'); - - const body: CredentialsFlowBody = { - grant_type: 'client_credentials', - }; - - if (options.scopes !== undefined) { - body.scope = sanitizeScope(options.scopes); - } - - const requestOptions = getRequestOptions( - { - url: options.accessTokenUri, - method: 'POST', - headers: { - ...DEFAULT_HEADERS, - // eslint-disable-next-line @typescript-eslint/naming-convention - Authorization: auth(options.clientId, options.clientSecret), - }, - body, - }, - options, - ); - - const responseData = await this.client.request(requestOptions); - return this.client.createToken(responseData); - } -} diff --git a/packages/@n8n/client-oauth2/src/constants.ts b/packages/@n8n/client-oauth2/src/constants.ts deleted file mode 100644 index e4895aa470a15..0000000000000 --- a/packages/@n8n/client-oauth2/src/constants.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import type { Headers } from './types'; - -export const DEFAULT_URL_BASE = 'https://example.org/'; - -/** - * Default headers for executing OAuth 2.0 flows. - */ -export const DEFAULT_HEADERS: Headers = { - Accept: 'application/json, application/x-www-form-urlencoded', - 'Content-Type': 'application/x-www-form-urlencoded', -}; - -/** - * Format error response types to regular strings for displaying to clients. - * - * Reference: http://tools.ietf.org/html/rfc6749#section-4.1.2.1 - */ -export const ERROR_RESPONSES: Record = { - invalid_request: [ - 'The request is missing a required parameter, includes an', - 'invalid parameter value, includes a parameter more than', - 'once, or is otherwise malformed.', - ].join(' '), - invalid_client: [ - 'Client authentication failed (e.g., unknown client, no', - 'client authentication included, or unsupported', - 'authentication method).', - ].join(' '), - invalid_grant: [ - 'The provided authorization grant (e.g., authorization', - 'code, resource owner credentials) or refresh token is', - 'invalid, expired, revoked, does not match the redirection', - 'URI used in the authorization request, or was issued to', - 'another client.', - ].join(' '), - unauthorized_client: [ - 'The client is not authorized to request an authorization', - 'code using this method.', - ].join(' '), - unsupported_grant_type: [ - 'The authorization grant type is not supported by the', - 'authorization server.', - ].join(' '), - access_denied: ['The resource owner or authorization server denied the request.'].join(' '), - unsupported_response_type: [ - 'The authorization server does not support obtaining', - 'an authorization code using this method.', - ].join(' '), - invalid_scope: ['The requested scope is invalid, unknown, or malformed.'].join(' '), - server_error: [ - 'The authorization server encountered an unexpected', - 'condition that prevented it from fulfilling the request.', - '(This error code is needed because a 500 Internal Server', - 'Error HTTP status code cannot be returned to the client', - 'via an HTTP redirect.)', - ].join(' '), - temporarily_unavailable: [ - 'The authorization server is currently unable to handle', - 'the request due to a temporary overloading or maintenance', - 'of the server.', - ].join(' '), -}; diff --git a/packages/@n8n/client-oauth2/src/index.ts b/packages/@n8n/client-oauth2/src/index.ts deleted file mode 100644 index 376c10f1eec51..0000000000000 --- a/packages/@n8n/client-oauth2/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { ClientOAuth2, ClientOAuth2Options, ClientOAuth2RequestObject } from './ClientOAuth2'; -export { ClientOAuth2Token, ClientOAuth2TokenData } from './ClientOAuth2Token'; diff --git a/packages/@n8n/client-oauth2/src/types.ts b/packages/@n8n/client-oauth2/src/types.ts deleted file mode 100644 index 906efcc43e0fd..0000000000000 --- a/packages/@n8n/client-oauth2/src/types.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type Headers = Record; -export type Query = Record; diff --git a/packages/@n8n/client-oauth2/src/utils.ts b/packages/@n8n/client-oauth2/src/utils.ts deleted file mode 100644 index e3433e5cf1c99..0000000000000 --- a/packages/@n8n/client-oauth2/src/utils.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/restrict-plus-operands */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import type { ClientOAuth2RequestObject } from './ClientOAuth2'; -import { ERROR_RESPONSES } from './constants'; - -/** - * Check if properties exist on an object and throw when they aren't. - */ -export function expects(obj: any, ...args: any[]) { - for (let i = 1; i < args.length; i++) { - const prop = args[i]; - if (obj[prop] === null) { - throw new TypeError('Expected "' + prop + '" to exist'); - } - } -} - -export class AuthError extends Error { - constructor(message: string, readonly body: any, readonly code = 'EAUTH') { - super(message); - } -} - -/** - * Pull an authentication error from the response data. - */ -export function getAuthError(body: { - error: string; - error_description?: string; -}): Error | undefined { - const message: string | undefined = - ERROR_RESPONSES[body.error] ?? body.error_description ?? body.error; - - if (message) { - return new AuthError(message, body); - } - - return undefined; -} - -/** - * Ensure a value is a string. - */ -function toString(str: string | null | undefined) { - return str === null ? '' : String(str); -} - -/** - * Sanitize the scopes option to be a string. - */ -export function sanitizeScope(scopes: string[] | string): string { - return Array.isArray(scopes) ? scopes.join(' ') : toString(scopes); -} - -/** - * Create basic auth header. - */ -export function auth(username: string, password: string): string { - return 'Basic ' + Buffer.from(toString(username) + ':' + toString(password)).toString('base64'); -} - -/** - * Merge request options from an options object. - */ -export function getRequestOptions( - { url, method, body, query, headers }: ClientOAuth2RequestObject, - options: any, -): ClientOAuth2RequestObject { - const rOptions = { - url, - method, - body: { ...body, ...options.body }, - query: { ...query, ...options.query }, - headers: { ...headers, ...options.headers }, - }; - // if request authorization was overridden delete it from header - if (rOptions.headers.Authorization === '') { - delete rOptions.headers.Authorization; - } - return rOptions; -} diff --git a/packages/@n8n/client-oauth2/test/CodeFlow.test.ts b/packages/@n8n/client-oauth2/test/CodeFlow.test.ts deleted file mode 100644 index 7b62e5ba141ca..0000000000000 --- a/packages/@n8n/client-oauth2/test/CodeFlow.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -import nock from 'nock'; -import { ClientOAuth2, ClientOAuth2Token } from '../src'; -import * as config from './config'; -import { AuthError } from '@/utils'; - -describe('CodeFlow', () => { - beforeAll(async () => { - nock.disableNetConnect(); - }); - - afterAll(() => { - nock.restore(); - }); - - const uri = `/auth/callback?code=${config.code}&state=${config.state}`; - - const githubAuth = new ClientOAuth2({ - clientId: config.clientId, - clientSecret: config.clientSecret, - accessTokenUri: config.accessTokenUri, - authorizationUri: config.authorizationUri, - authorizationGrants: ['code'], - redirectUri: config.redirectUri, - scopes: ['notifications'], - }); - - describe('#getUri', () => { - it('should return a valid uri', () => { - expect(githubAuth.code.getUri()).toEqual( - `${config.authorizationUri}?client_id=abc&` + - `redirect_uri=${encodeURIComponent(config.redirectUri)}&` + - 'response_type=code&state=&scope=notifications', - ); - }); - - describe('when scopes are undefined', () => { - it('should not include scope in the uri', () => { - const authWithoutScopes = new ClientOAuth2({ - clientId: config.clientId, - clientSecret: config.clientSecret, - accessTokenUri: config.accessTokenUri, - authorizationUri: config.authorizationUri, - authorizationGrants: ['code'], - redirectUri: config.redirectUri, - }); - expect(authWithoutScopes.code.getUri()).toEqual( - `${config.authorizationUri}?client_id=abc&` + - `redirect_uri=${encodeURIComponent(config.redirectUri)}&` + - 'response_type=code&state=', - ); - }); - }); - - it('should include empty scopes array as an empty string', () => { - const authWithEmptyScopes = new ClientOAuth2({ - clientId: config.clientId, - clientSecret: config.clientSecret, - accessTokenUri: config.accessTokenUri, - authorizationUri: config.authorizationUri, - authorizationGrants: ['code'], - redirectUri: config.redirectUri, - scopes: [], - }); - expect(authWithEmptyScopes.code.getUri()).toEqual( - `${config.authorizationUri}?client_id=abc&` + - `redirect_uri=${encodeURIComponent(config.redirectUri)}&` + - 'response_type=code&state=&scope=', - ); - }); - - it('should include empty scopes string as an empty string', () => { - const authWithEmptyScopes = new ClientOAuth2({ - clientId: config.clientId, - clientSecret: config.clientSecret, - accessTokenUri: config.accessTokenUri, - authorizationUri: config.authorizationUri, - authorizationGrants: ['code'], - redirectUri: config.redirectUri, - scopes: [], - }); - expect(authWithEmptyScopes.code.getUri()).toEqual( - `${config.authorizationUri}?client_id=abc&` + - `redirect_uri=${encodeURIComponent(config.redirectUri)}&` + - 'response_type=code&state=&scope=', - ); - }); - - describe('when authorizationUri contains query parameters', () => { - it('should preserve query string parameters', () => { - const authWithParams = new ClientOAuth2({ - clientId: config.clientId, - clientSecret: config.clientSecret, - accessTokenUri: config.accessTokenUri, - authorizationUri: `${config.authorizationUri}?bar=qux`, - authorizationGrants: ['code'], - redirectUri: config.redirectUri, - scopes: ['notifications'], - }); - expect(authWithParams.code.getUri()).toEqual( - `${config.authorizationUri}?bar=qux&client_id=abc&` + - `redirect_uri=${encodeURIComponent(config.redirectUri)}&` + - 'response_type=code&state=&scope=notifications', - ); - }); - }); - }); - - describe('#getToken', () => { - const mockTokenCall = () => - nock(config.baseUrl) - .post( - '/login/oauth/access_token', - ({ code, grant_type, redirect_uri }) => - code === config.code && - grant_type === 'authorization_code' && - redirect_uri === config.redirectUri, - ) - .once() - .reply(200, { - access_token: config.accessToken, - refresh_token: config.refreshToken, - }); - - it('should request the token', async () => { - mockTokenCall(); - const user = await githubAuth.code.getToken(uri); - - expect(user).toBeInstanceOf(ClientOAuth2Token); - expect(user.accessToken).toEqual(config.accessToken); - expect(user.tokenType).toEqual('bearer'); - }); - - it('should reject with auth errors', async () => { - let errored = false; - - try { - await githubAuth.code.getToken(`${config.redirectUri}?error=invalid_request`); - } catch (err) { - errored = true; - expect(err).toBeInstanceOf(AuthError); - if (err instanceof AuthError) { - expect(err.code).toEqual('EAUTH'); - expect(err.body.error).toEqual('invalid_request'); - } - } - expect(errored).toEqual(true); - }); - - describe('#sign', () => { - it('should be able to sign a standard request object', async () => { - mockTokenCall(); - const token = await githubAuth.code.getToken(uri); - const requestOptions = token.sign({ - method: 'GET', - url: 'http://api.github.com/user', - }); - expect(requestOptions.headers?.Authorization).toEqual(`Bearer ${config.accessToken}`); - }); - }); - - describe('#refresh', () => { - const mockRefreshCall = () => - nock(config.baseUrl) - .post( - '/login/oauth/access_token', - ({ refresh_token, grant_type }) => - refresh_token === config.refreshToken && grant_type === 'refresh_token', - ) - .once() - .reply(200, { - access_token: config.refreshedAccessToken, - refresh_token: config.refreshedRefreshToken, - }); - - it('should make a request to get a new access token', async () => { - mockTokenCall(); - const token = await githubAuth.code.getToken(uri, { state: config.state }); - expect(token.refreshToken).toEqual(config.refreshToken); - - mockRefreshCall(); - const token1 = await token.refresh(); - expect(token1).toBeInstanceOf(ClientOAuth2Token); - expect(token1.accessToken).toEqual(config.refreshedAccessToken); - expect(token1.refreshToken).toEqual(config.refreshedRefreshToken); - expect(token1.tokenType).toEqual('bearer'); - }); - }); - }); -}); diff --git a/packages/@n8n/client-oauth2/test/CredentialsFlow.test.ts b/packages/@n8n/client-oauth2/test/CredentialsFlow.test.ts deleted file mode 100644 index 7aee647b251b2..0000000000000 --- a/packages/@n8n/client-oauth2/test/CredentialsFlow.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import nock from 'nock'; -import { ClientOAuth2, ClientOAuth2Token } from '../src'; -import * as config from './config'; - -describe('CredentialsFlow', () => { - beforeAll(async () => { - nock.disableNetConnect(); - }); - - afterAll(() => { - nock.restore(); - }); - - describe('#getToken', () => { - const createAuthClient = (scopes?: string[]) => - new ClientOAuth2({ - clientId: config.clientId, - clientSecret: config.clientSecret, - accessTokenUri: config.accessTokenUri, - authorizationGrants: ['credentials'], - scopes, - }); - - const mockTokenCall = (requestedScope?: string) => - nock(config.baseUrl) - .post( - '/login/oauth/access_token', - ({ scope, grant_type }) => - scope === requestedScope && grant_type === 'client_credentials', - ) - .once() - .reply(200, { - access_token: config.accessToken, - refresh_token: config.refreshToken, - scope: requestedScope, - }); - - it('should request the token', async () => { - const authClient = createAuthClient(['notifications']); - mockTokenCall('notifications'); - - const user = await authClient.credentials.getToken(); - - expect(user).toBeInstanceOf(ClientOAuth2Token); - expect(user.accessToken).toEqual(config.accessToken); - expect(user.tokenType).toEqual('bearer'); - expect(user.data.scope).toEqual('notifications'); - }); - - it('when scopes are undefined, it should not send scopes to an auth server', async () => { - const authClient = createAuthClient(); - mockTokenCall(); - - const user = await authClient.credentials.getToken(); - expect(user).toBeInstanceOf(ClientOAuth2Token); - expect(user.accessToken).toEqual(config.accessToken); - expect(user.tokenType).toEqual('bearer'); - expect(user.data.scope).toEqual(undefined); - }); - - it('when scopes is an empty array, it should send empty scope string to an auth server', async () => { - const authClient = createAuthClient([]); - mockTokenCall(''); - - const user = await authClient.credentials.getToken(); - expect(user).toBeInstanceOf(ClientOAuth2Token); - expect(user.accessToken).toEqual(config.accessToken); - expect(user.tokenType).toEqual('bearer'); - expect(user.data.scope).toEqual(''); - }); - - describe('#sign', () => { - it('should be able to sign a standard request object', async () => { - const authClient = createAuthClient(['notifications']); - mockTokenCall('notifications'); - - const token = await authClient.credentials.getToken(); - const requestOptions = token.sign({ - method: 'GET', - url: `${config.baseUrl}/test`, - }); - - expect(requestOptions.headers?.Authorization).toEqual(`Bearer ${config.accessToken}`); - }); - }); - - describe('#refresh', () => { - const mockRefreshCall = () => - nock(config.baseUrl) - .post( - '/login/oauth/access_token', - ({ refresh_token, grant_type }) => - refresh_token === config.refreshToken && grant_type === 'refresh_token', - ) - .once() - .reply(200, { - access_token: config.refreshedAccessToken, - refresh_token: config.refreshedRefreshToken, - }); - - it('should make a request to get a new access token', async () => { - const authClient = createAuthClient(['notifications']); - mockTokenCall('notifications'); - - const token = await authClient.credentials.getToken(); - expect(token.accessToken).toEqual(config.accessToken); - - mockRefreshCall(); - const token1 = await token.refresh(); - expect(token1).toBeInstanceOf(ClientOAuth2Token); - expect(token1.accessToken).toEqual(config.refreshedAccessToken); - expect(token1.tokenType).toEqual('bearer'); - }); - }); - }); -}); diff --git a/packages/@n8n/client-oauth2/test/config.ts b/packages/@n8n/client-oauth2/test/config.ts deleted file mode 100644 index a6dd28a3ef95d..0000000000000 --- a/packages/@n8n/client-oauth2/test/config.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const baseUrl = 'https://mock.auth.service'; -export const accessTokenUri = baseUrl + '/login/oauth/access_token'; -export const authorizationUri = baseUrl + '/login/oauth/authorize'; -export const redirectUri = 'http://example.com/auth/callback'; - -export const accessToken = '4430eb1615fb6127cbf828a8e403'; -export const refreshToken = 'def456token'; -export const refreshedAccessToken = 'f456okeendt'; -export const refreshedRefreshToken = 'f4f6577c0f3af456okeendt'; - -export const clientId = 'abc'; -export const clientSecret = '123'; - -export const code = 'fbe55d970377e0686746'; -export const state = '7076840850058943'; diff --git a/packages/@n8n/client-oauth2/tsconfig.build.json b/packages/@n8n/client-oauth2/tsconfig.build.json deleted file mode 100644 index c8f44354c7ac4..0000000000000 --- a/packages/@n8n/client-oauth2/tsconfig.build.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "types": ["node"], - "noEmit": false, - "tsBuildInfoFile": "dist/build.tsbuildinfo" - }, - "include": ["src/**/*.ts"], - "exclude": ["test/**"] -} diff --git a/packages/@n8n/client-oauth2/tsconfig.json b/packages/@n8n/client-oauth2/tsconfig.json deleted file mode 100644 index a693815582818..0000000000000 --- a/packages/@n8n/client-oauth2/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - "compilerOptions": { - "rootDir": ".", - "types": ["node", "jest"], - "composite": true, - "noEmit": true, - "baseUrl": "src", - "paths": { - "@/*": ["./*"] - }, - "tsBuildInfoFile": "dist/typecheck.tsbuildinfo" - }, - "include": ["src/**/*.ts", "test/**/*.ts"] -} diff --git a/packages/cli/package.json b/packages/cli/package.json index c679d5ae23376..70c5664b9d51e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -117,7 +117,6 @@ }, "dependencies": { "@n8n_io/license-sdk": "~2.4.0", - "@n8n/client-oauth2": "workspace:*", "@oclif/command": "^1.8.16", "@oclif/core": "^1.16.4", "@oclif/errors": "^1.3.6", @@ -134,6 +133,7 @@ "change-case": "^4.1.1", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", + "client-oauth2": "^4.2.5", "compression": "^1.7.4", "connect-history-api-fallback": "^1.6.0", "convict": "^6.2.4", diff --git a/packages/cli/src/credentials/oauth2Credential.api.ts b/packages/cli/src/credentials/oauth2Credential.api.ts index b394dfefb523b..e286ae116a1a0 100644 --- a/packages/cli/src/credentials/oauth2Credential.api.ts +++ b/packages/cli/src/credentials/oauth2Credential.api.ts @@ -1,5 +1,4 @@ -import type { ClientOAuth2Options } from '@n8n/client-oauth2'; -import { ClientOAuth2 } from '@n8n/client-oauth2'; +import ClientOAuth2 from 'client-oauth2'; import Csrf from 'csrf'; import express from 'express'; import get from 'lodash.get'; @@ -120,7 +119,7 @@ oauth2CredentialController.get( }; const stateEncodedStr = Buffer.from(JSON.stringify(state)).toString('base64'); - const oAuthOptions: ClientOAuth2Options = { + const oAuthOptions: ClientOAuth2.Options = { clientId: get(oauthCredentials, 'clientId') as string, clientSecret: get(oauthCredentials, 'clientSecret', '') as string, accessTokenUri: get(oauthCredentials, 'accessTokenUrl', '') as string, @@ -251,11 +250,11 @@ oauth2CredentialController.get( return renderCallbackError(res, errorMessage); } - let options: Partial = {}; + let options = {}; - const oAuth2Parameters: ClientOAuth2Options = { + const oAuth2Parameters = { clientId: get(oauthCredentials, 'clientId') as string, - clientSecret: get(oauthCredentials, 'clientSecret', '') as string, + clientSecret: get(oauthCredentials, 'clientSecret', '') as string | undefined, accessTokenUri: get(oauthCredentials, 'accessTokenUrl', '') as string, authorizationUri: get(oauthCredentials, 'authUrl', '') as string, redirectUri: `${getInstanceBaseUrl()}/${restEndpoint}/oauth2-credential/callback`, @@ -269,7 +268,6 @@ oauth2CredentialController.get( client_secret: get(oauthCredentials, 'clientSecret', '') as string, }, }; - // @ts-ignore delete oAuth2Parameters.clientSecret; } @@ -280,8 +278,7 @@ oauth2CredentialController.get( const queryParameters = req.originalUrl.split('?').splice(1, 1).join(''); const oauthToken = await oAuthObj.code.getToken( - `${oAuth2Parameters.redirectUri as string}?${queryParameters}`, - // @ts-ignore + `${oAuth2Parameters.redirectUri}?${queryParameters}`, options, ); diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json index 461b082baa4c1..5326caf458dca 100644 --- a/packages/cli/tsconfig.json +++ b/packages/cli/tsconfig.json @@ -21,7 +21,6 @@ "include": ["src/**/*.ts", "test/**/*.ts", "src/sso/saml/saml-schema-metadata-2.0.xsd"], "references": [ { "path": "../workflow/tsconfig.build.json" }, - { "path": "../core/tsconfig.build.json" }, - { "path": "../@n8n/client-oauth2/tsconfig.build.json" } + { "path": "../core/tsconfig.build.json" } ] } diff --git a/packages/core/package.json b/packages/core/package.json index af6d0b2a9b15d..5df23866e6fce 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -46,7 +46,7 @@ }, "dependencies": { "axios": "^0.21.1", - "@n8n/client-oauth2": "workspace:*", + "client-oauth2": "^4.2.5", "concat-stream": "^2.0.0", "cron": "~1.7.2", "crypto-js": "~4.1.1", diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 6bd3f5433b08a..b32a67f32d139 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -82,12 +82,7 @@ import { IncomingMessage } from 'http'; import { stringify } from 'qs'; import type { Token } from 'oauth-1.0a'; import clientOAuth1 from 'oauth-1.0a'; -import type { - ClientOAuth2Options, - ClientOAuth2RequestObject, - ClientOAuth2TokenData, -} from '@n8n/client-oauth2'; -import { ClientOAuth2 } from '@n8n/client-oauth2'; +import clientOAuth2 from 'client-oauth2'; import crypto, { createHmac } from 'crypto'; import get from 'lodash.get'; import type { Request, Response } from 'express'; @@ -1086,14 +1081,14 @@ export async function requestOAuth2( throw new Error('OAuth credentials not connected!'); } - const oAuthClient = new ClientOAuth2({ + const oAuthClient = new clientOAuth2({ clientId: credentials.clientId as string, clientSecret: credentials.clientSecret as string, accessTokenUri: credentials.accessTokenUrl as string, scopes: (credentials.scope as string).split(' '), }); - let oauthTokenData = credentials.oauthTokenData as ClientOAuth2TokenData; + let oauthTokenData = credentials.oauthTokenData as clientOAuth2.Data; // if it's the first time using the credentials, get the access token and save it into the DB. if ( @@ -1121,20 +1116,15 @@ export async function requestOAuth2( oauthTokenData = data; } - const accessToken = - get(oauthTokenData, oAuth2Options?.property as string) || oauthTokenData.accessToken; - const refreshToken = oauthTokenData.refreshToken; const token = oAuthClient.createToken( - { - ...oauthTokenData, - ...(accessToken ? { access_token: accessToken } : {}), - ...(refreshToken ? { refresh_token: refreshToken } : {}), - }, + get(oauthTokenData, oAuth2Options?.property as string) || oauthTokenData.accessToken, + oauthTokenData.refreshToken, oAuth2Options?.tokenType || oauthTokenData.tokenType, + oauthTokenData, ); // Signs the request by adding authorization headers or query parameters depending // on the token-type used. - const newRequestOptions = token.sign(requestOptions as ClientOAuth2RequestObject); + const newRequestOptions = token.sign(requestOptions as clientOAuth2.RequestObject); const newRequestHeaders = (newRequestOptions.headers = newRequestOptions.headers ?? {}); // If keep bearer is false remove the it from the authorization header if (oAuth2Options?.keepBearer === false && typeof newRequestHeaders.Authorization === 'string') { @@ -1174,7 +1164,7 @@ export async function requestOAuth2( if (OAuth2GrantType.clientCredentials === credentials.grantType) { newToken = await getClientCredentialsToken(token.client, credentials); } else { - newToken = await token.refresh(tokenRefreshOptions as unknown as ClientOAuth2Options); + newToken = await token.refresh(tokenRefreshOptions); } Logger.debug( @@ -1194,7 +1184,7 @@ export async function requestOAuth2( credentialsType, credentials, ); - const refreshedRequestOption = newToken.sign(requestOptions as ClientOAuth2RequestObject); + const refreshedRequestOption = newToken.sign(requestOptions as clientOAuth2.RequestObject); if (oAuth2Options?.keyToIncludeInAccessTokenHeader) { Object.assign(newRequestHeaders, { @@ -1207,11 +1197,6 @@ export async function requestOAuth2( throw error; }); } - const tokenExpiredStatusCode = - oAuth2Options?.tokenExpiredStatusCode === undefined - ? 401 - : oAuth2Options?.tokenExpiredStatusCode; - return this.helpers .request(newRequestOptions) .then((response) => { @@ -1219,14 +1204,21 @@ export async function requestOAuth2( if ( requestOptions.resolveWithFullResponse === true && requestOptions.simple === false && - response.statusCode === tokenExpiredStatusCode + response.statusCode === + (oAuth2Options?.tokenExpiredStatusCode === undefined + ? 401 + : oAuth2Options?.tokenExpiredStatusCode) ) { throw response; } return response; }) .catch(async (error: IResponseError) => { - if (error.statusCode === tokenExpiredStatusCode) { + const statusCodeReturned = + oAuth2Options?.tokenExpiredStatusCode === undefined + ? 401 + : oAuth2Options?.tokenExpiredStatusCode; + if (error.statusCode === statusCodeReturned) { // Token is probably not valid anymore. So try refresh it. const tokenRefreshOptions: IDataObject = {}; if (oAuth2Options?.includeCredentialsOnRefreshOnBody) { @@ -1251,7 +1243,7 @@ export async function requestOAuth2( if (OAuth2GrantType.clientCredentials === credentials.grantType) { newToken = await getClientCredentialsToken(token.client, credentials); } else { - newToken = await token.refresh(tokenRefreshOptions as unknown as ClientOAuth2Options); + newToken = await token.refresh(tokenRefreshOptions); } Logger.debug( `OAuth2 token for "${credentialsType}" used by node "${node.name}" has been renewed.`, @@ -1279,7 +1271,7 @@ export async function requestOAuth2( ); // Make the request again with the new token - const newRequestOptions = newToken.sign(requestOptions as ClientOAuth2RequestObject); + const newRequestOptions = newToken.sign(requestOptions as clientOAuth2.RequestObject); newRequestOptions.headers = newRequestOptions.headers ?? {}; if (oAuth2Options?.keyToIncludeInAccessTokenHeader) { diff --git a/packages/core/src/OAuth2Helper.ts b/packages/core/src/OAuth2Helper.ts index dacb8d44a0c58..a66763505c501 100644 --- a/packages/core/src/OAuth2Helper.ts +++ b/packages/core/src/OAuth2Helper.ts @@ -1,15 +1,15 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import type { ICredentialDataDecryptedObject } from 'n8n-workflow'; -import type { ClientOAuth2, ClientOAuth2Options, ClientOAuth2Token } from '@n8n/client-oauth2'; +import type clientOAuth2 from 'client-oauth2'; export const getClientCredentialsToken = async ( - oAuth2Client: ClientOAuth2, + oAuth2Client: clientOAuth2, credentials: ICredentialDataDecryptedObject, -): Promise => { +): Promise => { const options = {}; if (credentials.authentication === 'body') { Object.assign(options, { headers: { - // eslint-disable-next-line @typescript-eslint/naming-convention Authorization: '', }, body: { @@ -18,5 +18,5 @@ export const getClientCredentialsToken = async ( }, }); } - return oAuth2Client.credentials.getToken(options as ClientOAuth2Options); + return oAuth2Client.credentials.getToken(options); }; diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index ed61b927dd395..69536da44842a 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -14,8 +14,5 @@ "useUnknownInCatchVariables": false }, "include": ["src/**/*.ts", "test/**/*.ts"], - "references": [ - { "path": "../workflow/tsconfig.build.json" }, - { "path": "../@n8n/client-oauth2/tsconfig.build.json" } - ] + "references": [{ "path": "../workflow/tsconfig.build.json" }] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f122dc473b14..34f063fb3cc22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -137,12 +137,6 @@ importers: specifier: ^1.0.24 version: 1.0.24(typescript@5.0.3) - packages/@n8n/client-oauth2: - dependencies: - axios: - specifier: ^0.21.1 - version: 0.21.4(debug@4.3.2) - packages/@n8n_io/eslint-config: devDependencies: '@types/eslint': @@ -193,9 +187,6 @@ importers: packages/cli: dependencies: - '@n8n/client-oauth2': - specifier: workspace:* - version: link:../@n8n/client-oauth2 '@n8n_io/license-sdk': specifier: ~2.4.0 version: 2.4.0 @@ -247,6 +238,9 @@ importers: class-validator: specifier: ^0.14.0 version: 0.14.0 + client-oauth2: + specifier: ^4.2.5 + version: 4.3.3 compression: specifier: ^1.7.4 version: 1.7.4 @@ -632,12 +626,12 @@ importers: packages/core: dependencies: - '@n8n/client-oauth2': - specifier: workspace:* - version: link:../@n8n/client-oauth2 axios: specifier: ^0.21.1 version: 0.21.4(debug@4.3.2) + client-oauth2: + specifier: ^4.2.5 + version: 4.3.3 concat-stream: specifier: ^2.0.0 version: 2.0.0 @@ -5976,6 +5970,10 @@ packages: - supports-color dev: true + /@servie/events@1.0.0: + resolution: {integrity: sha512-sBSO19KzdrJCM3gdx6eIxV8M9Gxfgg6iDQmH5TIAGaUu+X9VDdsINXJOnoiZ1Kx3TrHdH4bt5UVglkjsEGBcvw==} + dev: false + /@sideway/address@4.1.4: resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} dependencies: @@ -8167,6 +8165,10 @@ packages: resolution: {integrity: sha512-dDZH/tXzwjutnuk4UacGgFRwV+JSLaXL1ikvidfJprkb7L9Nx1njcRHHmi3Dsvt7pgqqTEeucQuOrWHPFgzVHA==} dev: true + /@types/tough-cookie@2.3.8: + resolution: {integrity: sha512-7axfYN8SW9pWg78NgenHasSproWQee5rzyPVLC9HpaQSDgNArsnKJD88EaMfi4Pl48AyciO3agYCFqpHS1gLpg==} + dev: false + /@types/tough-cookie@4.0.2: resolution: {integrity: sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==} dev: true @@ -10095,6 +10097,10 @@ packages: streamsearch: 1.1.0 dev: false + /byte-length@1.0.2: + resolution: {integrity: sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==} + dev: false + /bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} @@ -10537,6 +10543,14 @@ packages: engines: {node: '>= 10'} dev: false + /client-oauth2@4.3.3: + resolution: {integrity: sha512-k8AvUYJon0vv75ufoVo4nALYb/qwFFicO3I0+39C6xEdflqVtr+f9cy+0ZxAduoVSTfhP5DX2tY2XICAd5hy6Q==} + engines: {node: '>=4.2.0'} + dependencies: + popsicle: 12.1.0 + safe-buffer: 5.2.1 + dev: false + /cliui@3.2.0: resolution: {integrity: sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==} dependencies: @@ -14550,6 +14564,11 @@ packages: - supports-color dev: false + /ip-regex@2.1.0: + resolution: {integrity: sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==} + engines: {node: '>=4'} + dev: false + /ip@1.1.8: resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} dev: false @@ -16767,9 +16786,14 @@ packages: dependencies: semver: 6.3.0 + /make-error-cause@2.3.0: + resolution: {integrity: sha512-etgt+n4LlOkGSJbBTV9VROHA5R7ekIPS4vfh+bCAoJgRrJWdqJCBbpS3osRJ/HrT7R68MzMiY3L3sDJ/Fd8aBg==} + dependencies: + make-error: 1.3.6 + dev: false + /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true /make-fetch-happen@9.1.0: resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} @@ -18571,6 +18595,70 @@ packages: '@babel/runtime': 7.20.7 dev: true + /popsicle-content-encoding@1.0.0(servie@4.3.3): + resolution: {integrity: sha512-4Df+vTfM8wCCJVTzPujiI6eOl3SiWQkcZg0AMrOkD1enMXsF3glIkFUZGvour1Sj7jOWCsNSEhBxpbbhclHhzw==} + peerDependencies: + servie: ^4.0.0 + dependencies: + servie: 4.3.3 + dev: false + + /popsicle-cookie-jar@1.0.0(servie@4.3.3): + resolution: {integrity: sha512-vrlOGvNVELko0+J8NpGC5lHWDGrk8LQJq9nwAMIVEVBfN1Lib3BLxAaLRGDTuUnvl45j5N9dT2H85PULz6IjjQ==} + peerDependencies: + servie: ^4.0.0 + dependencies: + '@types/tough-cookie': 2.3.8 + servie: 4.3.3 + tough-cookie: 3.0.1 + dev: false + + /popsicle-redirects@1.1.1(servie@4.3.3): + resolution: {integrity: sha512-mC2HrKjdTAWDalOjGxlXw9j6Qxrz/Yd2ui6bPxpi2IQDYWpF4gUAMxbA8EpSWJhLi0PuWKDwTHHPrUPGutAoIA==} + peerDependencies: + servie: ^4.1.0 + dependencies: + servie: 4.3.3 + dev: false + + /popsicle-transport-http@1.2.1(servie@4.3.3): + resolution: {integrity: sha512-i5r3IGHkGiBDm1oPFvOfEeSGWR0lQJcsdTqwvvDjXqcTHYJJi4iSi3ecXIttDiTBoBtRAFAE9nF91fspQr63FQ==} + peerDependencies: + servie: ^4.2.0 + dependencies: + make-error-cause: 2.3.0 + servie: 4.3.3 + dev: false + + /popsicle-transport-xhr@2.0.0(servie@4.3.3): + resolution: {integrity: sha512-5Sbud4Widngf1dodJE5cjEYXkzEUIl8CzyYRYR57t6vpy9a9KPGQX6KBKdPjmBZlR5A06pOBXuJnVr23l27rtA==} + peerDependencies: + servie: ^4.2.0 + dependencies: + servie: 4.3.3 + dev: false + + /popsicle-user-agent@1.0.0(servie@4.3.3): + resolution: {integrity: sha512-epKaq3TTfTzXcxBxjpoKYMcTTcAX8Rykus6QZu77XNhJuRHSRxMd+JJrbX/3PFI0opFGSN0BabbAYCbGxbu0mA==} + peerDependencies: + servie: ^4.0.0 + dependencies: + servie: 4.3.3 + dev: false + + /popsicle@12.1.0: + resolution: {integrity: sha512-muNC/cIrWhfR6HqqhHazkxjob3eyECBe8uZYSQ/N5vixNAgssacVleerXnE8Are5fspR0a+d2qWaBR1g7RYlmw==} + dependencies: + popsicle-content-encoding: 1.0.0(servie@4.3.3) + popsicle-cookie-jar: 1.0.0(servie@4.3.3) + popsicle-redirects: 1.1.1(servie@4.3.3) + popsicle-transport-http: 1.2.1(servie@4.3.3) + popsicle-transport-xhr: 2.0.0(servie@4.3.3) + popsicle-user-agent: 1.0.0(servie@4.3.3) + servie: 4.3.3 + throwback: 4.1.0 + dev: false + /posix-character-classes@0.1.1: resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} engines: {node: '>=0.10.0'} @@ -20146,6 +20234,14 @@ packages: transitivePeerDependencies: - supports-color + /servie@4.3.3: + resolution: {integrity: sha512-b0IrY3b1gVMsWvJppCf19g1p3JSnS0hQi6xu4Hi40CIhf0Lx8pQHcvBL+xunShpmOiQzg1NOia812NAWdSaShw==} + dependencies: + '@servie/events': 1.0.0 + byte-length: 1.0.2 + ts-expect: 1.3.0 + dev: false + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -21286,6 +21382,10 @@ packages: /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + /throwback@4.1.0: + resolution: {integrity: sha512-dLFe8bU8SeH0xeqeKL7BNo8XoPC/o91nz9/ooeplZPiso+DZukhoyZcSz9TFnUNScm+cA9qjU1m1853M6sPOng==} + dev: false + /time-stamp@1.1.0: resolution: {integrity: sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==} engines: {node: '>=0.10.0'} @@ -21447,6 +21547,15 @@ packages: psl: 1.9.0 punycode: 2.2.0 + /tough-cookie@3.0.1: + resolution: {integrity: sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==} + engines: {node: '>=6'} + dependencies: + ip-regex: 2.1.0 + psl: 1.9.0 + punycode: 2.2.0 + dev: false + /tough-cookie@4.1.2: resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} engines: {node: '>=6'} @@ -21495,6 +21604,10 @@ packages: typescript: 5.0.3 dev: true + /ts-expect@1.3.0: + resolution: {integrity: sha512-e4g0EJtAjk64xgnFPD6kTBUtpnMVzDrMb12N1YZV0VvSlhnVT3SGxiYTLdGy8Q5cYHOIC/FAHmZ10eGrAguicQ==} + dev: false + /ts-jest@29.1.0(@babel/core@7.21.8)(jest@29.5.0)(typescript@5.0.3): resolution: {integrity: sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ce18506b3820a..4a89a5858c0a8 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,3 @@ packages: - packages/* - - packages/@n8n/* - packages/@n8n_io/*