From 05c4229cd70e03b6cc83e34aed5e71f93602ade1 Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Tue, 6 Jun 2023 19:19:24 +0300 Subject: [PATCH] refactor(core): Google service account remove duplicated functions (no-changelog) (#6368) --- .../Google/BigQuery/v1/GenericFunctions.ts | 56 +--------- .../Google/BigQuery/v2/transport/index.ts | 53 +-------- .../nodes/Google/Books/GenericFunctions.ts | 67 +---------- .../nodes/Google/Chat/GenericFunctions.ts | 70 +----------- .../nodes/Google/Docs/GenericFunctions.ts | 69 +----------- .../nodes/Google/Drive/GenericFunctions.ts | 70 +----------- .../nodes/Google/GenericFunctions.ts | 105 ++++++++++++++++++ .../nodes/Google/Gmail/GenericFunctions.ts | 64 +---------- .../nodes/Google/Sheet/v1/GenericFunctions.ts | 68 +----------- .../Google/Sheet/v1/GoogleSheetsV1.node.ts | 10 +- .../Google/Sheet/v2/methods/credentialTest.ts | 8 +- .../nodes/Google/Sheet/v2/transport/index.ts | 74 +----------- .../nodes/Google/Slides/GenericFunctions.ts | 68 +----------- .../Google/Translate/GenericFunctions.ts | 71 +----------- 14 files changed, 134 insertions(+), 719 deletions(-) create mode 100644 packages/nodes-base/nodes/Google/GenericFunctions.ts diff --git a/packages/nodes-base/nodes/Google/BigQuery/v1/GenericFunctions.ts b/packages/nodes-base/nodes/Google/BigQuery/v1/GenericFunctions.ts index db1d20c4a3..12a8773ba0 100644 --- a/packages/nodes-base/nodes/Google/BigQuery/v1/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/BigQuery/v1/GenericFunctions.ts @@ -8,64 +8,12 @@ import type { JsonObject, } from 'n8n-workflow'; import { NodeApiError, NodeOperationError } from 'n8n-workflow'; - -import moment from 'moment-timezone'; - -import * as jwt from 'jsonwebtoken'; - -async function getAccessToken( - this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, - credentials: IDataObject, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const privateKey = (credentials.privateKey as string).replace(/\\n/g, '\n').trim(); - - const scopes = ['https://www.googleapis.com/auth/bigquery']; - - const now = moment().unix(); - - const signature = jwt.sign( - { - iss: credentials.email as string, - sub: credentials.delegatedEmail || (credentials.email as string), - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, - body: any = {}, qs: IDataObject = {}, uri?: string, @@ -102,7 +50,7 @@ export async function googleApiRequest( throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } - const { access_token } = await getAccessToken.call(this, credentials as IDataObject); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'bigquery'); options.headers!.Authorization = `Bearer ${access_token}`; return await this.helpers.request(options); diff --git a/packages/nodes-base/nodes/Google/BigQuery/v2/transport/index.ts b/packages/nodes-base/nodes/Google/BigQuery/v2/transport/index.ts index 8b61e324fd..b616917b17 100644 --- a/packages/nodes-base/nodes/Google/BigQuery/v2/transport/index.ts +++ b/packages/nodes-base/nodes/Google/BigQuery/v2/transport/index.ts @@ -1,58 +1,9 @@ import type { OptionsWithUri } from 'request'; -import moment from 'moment-timezone'; -import * as jwt from 'jsonwebtoken'; import type { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core'; import type { IDataObject, JsonObject } from 'n8n-workflow'; import { NodeApiError, NodeOperationError } from 'n8n-workflow'; - -async function getAccessToken( - this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, - credentials: IDataObject, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const privateKey = (credentials.privateKey as string).replace(/\\n/g, '\n').trim(); - - const scopes = ['https://www.googleapis.com/auth/bigquery']; - - const now = moment().unix(); - - const signature = jwt.sign( - { - iss: credentials.email as string, - sub: credentials.delegatedEmail || (credentials.email as string), - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../../../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, @@ -94,7 +45,7 @@ export async function googleApiRequest( throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); } - const { access_token } = await getAccessToken.call(this, credentials as IDataObject); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'bigquery'); options.headers!.Authorization = `Bearer ${access_token}`; return await this.helpers.request(options); diff --git a/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts index ed42ba9c6a..a4528bd216 100644 --- a/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Books/GenericFunctions.ts @@ -8,72 +8,12 @@ import type { JsonObject, } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; - -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; - -interface IGoogleAuthCredentials { - delegatedEmail?: string; - email: string; - inpersonate: boolean; - privateKey: string; -} - -async function getAccessToken( - this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, - credentials: IGoogleAuthCredentials, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = ['https://www.googleapis.com/auth/books']; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.delegatedEmail || credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, resource: string, - body: any = {}, qs: IDataObject = {}, uri?: string, @@ -108,10 +48,7 @@ export async function googleApiRequest( privateKey: string; }; - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'books'); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts index bd60ce1cc3..41d2599201 100644 --- a/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Chat/GenericFunctions.ts @@ -1,7 +1,6 @@ import type { OptionsWithUri } from 'request'; import type { - ICredentialTestFunctions, IDataObject, IExecuteFunctions, IExecuteSingleFunctions, @@ -11,69 +10,7 @@ import type { } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; - -interface IGoogleAuthCredentials { - delegatedEmail?: string; - email: string; - inpersonate: boolean; - privateKey: string; -} - -export async function getAccessToken( - this: - | IExecuteFunctions - | IExecuteSingleFunctions - | ILoadOptionsFunctions - | ICredentialTestFunctions, - credentials: IGoogleAuthCredentials, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = ['https://www.googleapis.com/auth/chat.bot']; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.delegatedEmail || credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, @@ -112,10 +49,7 @@ export async function googleApiRequest( } else { const credentials = await this.getCredentials('googleApi'); - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'chat'); options.headers!.Authorization = `Bearer ${access_token}`; responseData = await this.helpers.request(options); } diff --git a/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts index a082254e73..01f707891b 100644 --- a/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Docs/GenericFunctions.ts @@ -8,69 +8,7 @@ import type { } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; - -interface IGoogleAuthCredentials { - delegatedEmail?: string; - email: string; - inpersonate: boolean; - privateKey: string; -} - -async function getAccessToken( - this: IExecuteFunctions | ILoadOptionsFunctions, - credentials: IGoogleAuthCredentials, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = [ - 'https://www.googleapis.com/auth/documents', - 'https://www.googleapis.com/auth/drive', - 'https://www.googleapis.com/auth/drive.file', - ]; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.delegatedEmail || credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | ILoadOptionsFunctions, @@ -104,10 +42,7 @@ export async function googleApiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'docs'); options.headers!.Authorization = `Bearer ${access_token}`; return await this.helpers.request(options); diff --git a/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts index 4daee7ee9f..e9c213f486 100644 --- a/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Drive/GenericFunctions.ts @@ -10,75 +10,12 @@ import type { } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; - -interface IGoogleAuthCredentials { - delegatedEmail?: string; - email: string; - inpersonate: boolean; - privateKey: string; -} - -async function getAccessToken( - this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, - credentials: IGoogleAuthCredentials, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = [ - 'https://www.googleapis.com/auth/drive', - 'https://www.googleapis.com/auth/drive.appdata', - 'https://www.googleapis.com/auth/drive.photos.readonly', - ]; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.delegatedEmail || credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, resource: string, - body: any = {}, qs: IDataObject = {}, uri?: string, @@ -111,10 +48,7 @@ export async function googleApiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'drive'); options.headers!.Authorization = `Bearer ${access_token}`; return await this.helpers.request(options); diff --git a/packages/nodes-base/nodes/Google/GenericFunctions.ts b/packages/nodes-base/nodes/Google/GenericFunctions.ts new file mode 100644 index 0000000000..4ee5f0dc4c --- /dev/null +++ b/packages/nodes-base/nodes/Google/GenericFunctions.ts @@ -0,0 +1,105 @@ +import type { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core'; +import type { ICredentialTestFunctions, IDataObject, IPollFunctions } from 'n8n-workflow'; + +import type { OptionsWithUri } from 'request'; +import moment from 'moment-timezone'; +import * as jwt from 'jsonwebtoken'; + +const googleServiceAccountScopes = { + bigquery: ['https://www.googleapis.com/auth/bigquery'], + books: ['https://www.googleapis.com/auth/books'], + chat: ['https://www.googleapis.com/auth/chat.bot'], + docs: [ + 'https://www.googleapis.com/auth/documents', + 'https://www.googleapis.com/auth/drive', + 'https://www.googleapis.com/auth/drive.file', + ], + drive: [ + 'https://www.googleapis.com/auth/drive', + 'https://www.googleapis.com/auth/drive.appdata', + 'https://www.googleapis.com/auth/drive.photos.readonly', + ], + gmail: [ + 'https://www.googleapis.com/auth/gmail.labels', + 'https://www.googleapis.com/auth/gmail.addons.current.action.compose', + 'https://www.googleapis.com/auth/gmail.addons.current.message.action', + 'https://mail.google.com/', + 'https://www.googleapis.com/auth/gmail.modify', + 'https://www.googleapis.com/auth/gmail.compose', + ], + sheetV1: [ + 'https://www.googleapis.com/auth/drive', + 'https://www.googleapis.com/auth/drive.file', + 'https://www.googleapis.com/auth/spreadsheets', + ], + sheetV2: [ + 'https://www.googleapis.com/auth/drive.file', + 'https://www.googleapis.com/auth/spreadsheets', + 'https://www.googleapis.com/auth/drive.metadata', + ], + slides: [ + 'https://www.googleapis.com/auth/drive.file', + 'https://www.googleapis.com/auth/presentations', + ], + translate: [ + 'https://www.googleapis.com/auth/cloud-translation', + 'https://www.googleapis.com/auth/cloud-platform', + ], +}; + +type GoogleServiceAccount = keyof typeof googleServiceAccountScopes; + +export async function getGoogleAccessToken( + this: + | IExecuteFunctions + | IExecuteSingleFunctions + | ILoadOptionsFunctions + | ICredentialTestFunctions + | IPollFunctions, + credentials: IDataObject, + service: GoogleServiceAccount, +): Promise { + //https://developers.google.com/identity/protocols/oauth2/service-account#httprest + + const scopes = googleServiceAccountScopes[service]; + + const privateKey = (credentials.privateKey as string).replace(/\\n/g, '\n').trim(); + credentials.email = ((credentials.email as string) || '').trim(); + + const now = moment().unix(); + + const signature = jwt.sign( + { + iss: credentials.email, + sub: credentials.delegatedEmail || credentials.email, + scope: scopes.join(' '), + aud: 'https://oauth2.googleapis.com/token', + iat: now, + exp: now + 3600, + }, + privateKey, + { + algorithm: 'RS256', + header: { + kid: privateKey, + typ: 'JWT', + alg: 'RS256', + }, + }, + ); + + const options: OptionsWithUri = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + method: 'POST', + form: { + grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', + assertion: signature, + }, + uri: 'https://oauth2.googleapis.com/token', + json: true, + }; + + return this.helpers.request(options); +} diff --git a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts index e1fd977b2d..86ffb2eda9 100644 --- a/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Gmail/GenericFunctions.ts @@ -4,7 +4,6 @@ import { simpleParser } from 'mailparser'; import type { IBinaryKeyData, - ICredentialDataDecryptedObject, IDataObject, IExecuteFunctions, IExecuteSingleFunctions, @@ -16,10 +15,6 @@ import type { } from 'n8n-workflow'; import { NodeApiError, NodeOperationError } from 'n8n-workflow'; -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; - import { DateTime } from 'luxon'; import isEmpty from 'lodash.isempty'; @@ -44,62 +39,7 @@ export interface IAttachments { } import MailComposer from 'nodemailer/lib/mail-composer'; - -async function getAccessToken( - this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, - credentials: ICredentialDataDecryptedObject, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = [ - 'https://www.googleapis.com/auth/gmail.labels', - 'https://www.googleapis.com/auth/gmail.addons.current.action.compose', - 'https://www.googleapis.com/auth/gmail.addons.current.message.action', - 'https://mail.google.com/', - 'https://www.googleapis.com/auth/gmail.modify', - 'https://www.googleapis.com/auth/gmail.compose', - ]; - - const now = moment().unix(); - - credentials.email = (credentials.email as string).trim(); - const privateKey = (credentials.privateKey as string).replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.delegatedEmail || credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, @@ -139,7 +79,7 @@ export async function googleApiRequest( const credentials = await this.getCredentials('googleApi'); credentialType = 'googleApi'; - const { access_token } = await getAccessToken.call(this, credentials); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'gmail'); (options.headers as IDataObject).Authorization = `Bearer ${access_token}`; } diff --git a/packages/nodes-base/nodes/Google/Sheet/v1/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Sheet/v1/GenericFunctions.ts index 95f0421b07..cea4f84057 100644 --- a/packages/nodes-base/nodes/Google/Sheet/v1/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Sheet/v1/GenericFunctions.ts @@ -1,7 +1,6 @@ import type { OptionsWithUri } from 'request'; import type { - ICredentialTestFunctions, IDataObject, IExecuteFunctions, IExecuteSingleFunctions, @@ -9,10 +8,7 @@ import type { JsonObject, } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; - -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; +import { getGoogleAccessToken } from '../../GenericFunctions'; export interface IGoogleAuthCredentials { delegatedEmail?: string; @@ -21,63 +17,6 @@ export interface IGoogleAuthCredentials { privateKey: string; } -export async function getAccessToken( - this: - | IExecuteFunctions - | IExecuteSingleFunctions - | ILoadOptionsFunctions - | ICredentialTestFunctions, - credentials: IGoogleAuthCredentials, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = [ - 'https://www.googleapis.com/auth/drive', - 'https://www.googleapis.com/auth/drive.file', - 'https://www.googleapis.com/auth/spreadsheets', - ]; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.delegatedEmail || credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} - export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, @@ -114,10 +53,7 @@ export async function googleApiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'sheetV1'); options.headers!.Authorization = `Bearer ${access_token}`; return await this.helpers.request(options); diff --git a/packages/nodes-base/nodes/Google/Sheet/v1/GoogleSheetsV1.node.ts b/packages/nodes-base/nodes/Google/Sheet/v1/GoogleSheetsV1.node.ts index 9cdf31e1c2..4ad70703f0 100644 --- a/packages/nodes-base/nodes/Google/Sheet/v1/GoogleSheetsV1.node.ts +++ b/packages/nodes-base/nodes/Google/Sheet/v1/GoogleSheetsV1.node.ts @@ -22,10 +22,10 @@ import type { } from './GoogleSheet'; import { GoogleSheet } from './GoogleSheet'; -import type { IGoogleAuthCredentials } from './GenericFunctions'; -import { getAccessToken, googleApiRequest, hexToRgb } from './GenericFunctions'; +import { googleApiRequest, hexToRgb } from './GenericFunctions'; import { versionDescription } from './versionDescription'; +import { getGoogleAccessToken } from '../../GenericFunctions'; export class GoogleSheetsV1 implements INodeType { description: INodeTypeDescription; @@ -71,10 +71,8 @@ export class GoogleSheetsV1 implements INodeType { credential: ICredentialsDecrypted, ): Promise { try { - const tokenRequest = await getAccessToken.call( - this, - credential.data! as unknown as IGoogleAuthCredentials, - ); + const tokenRequest = await getGoogleAccessToken.call(this, credential.data!, 'sheetV1'); + if (!tokenRequest.access_token) { return { status: 'Error', diff --git a/packages/nodes-base/nodes/Google/Sheet/v2/methods/credentialTest.ts b/packages/nodes-base/nodes/Google/Sheet/v2/methods/credentialTest.ts index 5d344ebe37..50792091f0 100644 --- a/packages/nodes-base/nodes/Google/Sheet/v2/methods/credentialTest.ts +++ b/packages/nodes-base/nodes/Google/Sheet/v2/methods/credentialTest.ts @@ -4,18 +4,14 @@ import type { INodeCredentialTestResult, } from 'n8n-workflow'; -import type { IGoogleAuthCredentials } from '../transport'; -import { getAccessToken } from '../transport'; +import { getGoogleAccessToken } from '../../../GenericFunctions'; export async function googleApiCredentialTest( this: ICredentialTestFunctions, credential: ICredentialsDecrypted, ): Promise { try { - const tokenRequest = await getAccessToken.call( - this, - credential.data! as unknown as IGoogleAuthCredentials, - ); + const tokenRequest = await getGoogleAccessToken.call(this, credential.data!, 'sheetV2'); if (!tokenRequest.access_token) { return { status: 'Error', diff --git a/packages/nodes-base/nodes/Google/Sheet/v2/transport/index.ts b/packages/nodes-base/nodes/Google/Sheet/v2/transport/index.ts index 226d2256b4..024b95bbe4 100644 --- a/packages/nodes-base/nodes/Google/Sheet/v2/transport/index.ts +++ b/packages/nodes-base/nodes/Google/Sheet/v2/transport/index.ts @@ -1,6 +1,5 @@ import type { OptionsWithUri } from 'request'; import type { - ICredentialTestFunctions, IDataObject, IExecuteFunctions, IExecuteSingleFunctions, @@ -9,73 +8,7 @@ import type { JsonObject, } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; -import moment from 'moment-timezone'; -import jwt from 'jsonwebtoken'; - -export interface IGoogleAuthCredentials { - delegatedEmail?: string; - email: string; - inpersonate: boolean; - privateKey: string; -} - -export async function getAccessToken( - this: - | IExecuteFunctions - | IExecuteSingleFunctions - | ILoadOptionsFunctions - | ICredentialTestFunctions - | IPollFunctions, - credentials: IGoogleAuthCredentials, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = [ - 'https://www.googleapis.com/auth/drive.file', - 'https://www.googleapis.com/auth/spreadsheets', - 'https://www.googleapis.com/auth/drive.metadata', - ]; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.delegatedEmail || credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../../../GenericFunctions'; export async function apiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IPollFunctions, @@ -114,10 +47,7 @@ export async function apiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'sheetV2'); options.headers!.Authorization = `Bearer ${access_token}`; diff --git a/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts index e9b2aa548b..ca669df2f7 100644 --- a/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Slides/GenericFunctions.ts @@ -8,68 +8,7 @@ import type { } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; - -interface IGoogleAuthCredentials { - delegatedEmail?: string; - email: string; - inpersonate: boolean; - privateKey: string; -} - -async function getAccessToken( - this: IExecuteFunctions | ILoadOptionsFunctions, - credentials: IGoogleAuthCredentials, -) { - // https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = [ - 'https://www.googleapis.com/auth/drive.file', - 'https://www.googleapis.com/auth/presentations', - ]; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | ILoadOptionsFunctions, @@ -106,10 +45,7 @@ export async function googleApiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'slides'); options.headers.Authorization = `Bearer ${access_token}`; return await this.helpers.request(options); } else { diff --git a/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts index b65cef0c12..f4274b7535 100644 --- a/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Translate/GenericFunctions.ts @@ -9,68 +9,7 @@ import type { } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow'; -import moment from 'moment-timezone'; - -import jwt from 'jsonwebtoken'; - -interface IGoogleAuthCredentials { - delegatedEmail?: string; - email: string; - inpersonate: boolean; - privateKey: string; -} - -async function getAccessToken( - this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, - credentials: IGoogleAuthCredentials, -): Promise { - //https://developers.google.com/identity/protocols/oauth2/service-account#httprest - - const scopes = [ - 'https://www.googleapis.com/auth/cloud-translation', - 'https://www.googleapis.com/auth/cloud-platform', - ]; - - const now = moment().unix(); - - credentials.email = credentials.email.trim(); - const privateKey = credentials.privateKey.replace(/\\n/g, '\n').trim(); - - const signature = jwt.sign( - { - iss: credentials.email, - sub: credentials.email, - scope: scopes.join(' '), - aud: 'https://oauth2.googleapis.com/token', - iat: now, - exp: now + 3600, - }, - privateKey, - { - algorithm: 'RS256', - header: { - kid: privateKey, - typ: 'JWT', - alg: 'RS256', - }, - }, - ); - - const options: OptionsWithUri = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - form: { - grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', - assertion: signature, - }, - uri: 'https://oauth2.googleapis.com/token', - json: true, - }; - - return this.helpers.request(options); -} +import { getGoogleAccessToken } from '../GenericFunctions'; export async function googleApiRequest( this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, @@ -108,16 +47,12 @@ export async function googleApiRequest( if (authenticationMethod === 'serviceAccount') { const credentials = await this.getCredentials('googleApi'); - const { access_token } = await getAccessToken.call( - this, - credentials as unknown as IGoogleAuthCredentials, - ); + const { access_token } = await getGoogleAccessToken.call(this, credentials, 'translate'); options.headers!.Authorization = `Bearer ${access_token}`; - //@ts-ignore + return await this.helpers.request(options); } else { - //@ts-ignore return await this.helpers.requestOAuth2.call(this, 'googleTranslateOAuth2Api', options); } } catch (error) {