From 29ee151c135c6b36eef8e6233bd039da8cab13d3 Mon Sep 17 00:00:00 2001 From: sangeet-joy-tw <157606431+sangeet-joy-tw@users.noreply.github.com> Date: Thu, 1 Feb 2024 15:41:02 +0530 Subject: [PATCH] 579-axios changes in xeroClient file --- src/XeroClient.ts | 499 +++++++++++++++++++++++----------------------- 1 file changed, 249 insertions(+), 250 deletions(-) diff --git a/src/XeroClient.ts b/src/XeroClient.ts index dbe01dbe..b94703ee 100644 --- a/src/XeroClient.ts +++ b/src/XeroClient.ts @@ -1,292 +1,291 @@ import { Client, Issuer, TokenSet, TokenSetParameters, custom } from 'openid-client'; import * as xero from './gen/api'; import request = require('request'); +const axios = require('axios'); import http = require('http'); export { TokenSet, TokenSetParameters } from 'openid-client'; export interface IXeroClientConfig { - clientId: string, - clientSecret: string, - redirectUris?: string[], - grantType?: string; - scopes?: string[], - state?: string, - httpTimeout?: number, - clockTolerance?: number + clientId: string, + clientSecret: string, + redirectUris?: string[], + grantType?: string; + scopes?: string[], + state?: string, + httpTimeout?: number, + clockTolerance?: number }; export interface XeroIdToken { - nbf: number - exp: number - iss: string, - aud: string - iat: number - at_hash: string - sid: string - sub: string - auth_time: number - idp: string - xero_userid: string - global_session_id: string - preferred_username: string - email: string - given_name: string - family_name: string - amr: string[] + nbf: number + exp: number + iss: string, + aud: string + iat: number + at_hash: string + sid: string + sub: string + auth_time: number + idp: string + xero_userid: string + global_session_id: string + preferred_username: string + email: string + given_name: string + family_name: string + amr: string[] }; export interface XeroAccessToken { - nbf: number - exp: number - iss: string - aud: string - client_id: string - sub: string - auth_time: number - idp: string - xero_userid: string - global_session_id: string - jti: string - scope: string[] - amr: string[] + nbf: number + exp: number + iss: string + aud: string + client_id: string + sub: string + auth_time: number + idp: string + xero_userid: string + global_session_id: string + jti: string + scope: string[] + amr: string[] }; export class XeroClient { - constructor(readonly config?: IXeroClientConfig) { - this.accountingApi = new xero.AccountingApi(); - this.assetApi = new xero.AssetApi(); - this.filesApi = new xero.FilesApi(); - this.projectApi = new xero.ProjectApi(); - this.payrollAUApi = new xero.PayrollAuApi(); - this.bankFeedsApi = new xero.BankFeedsApi(); - this.payrollUKApi = new xero.PayrollUkApi(); - this.payrollNZApi = new xero.PayrollNzApi(); - this.appStoreApi = new xero.AppStoreApi(); - this.financeApi = new xero.FinanceApi(); - }; + constructor(readonly config?: IXeroClientConfig) { + this.accountingApi = new xero.AccountingApi(); + this.assetApi = new xero.AssetApi(); + this.filesApi = new xero.FilesApi(); + this.projectApi = new xero.ProjectApi(); + this.payrollAUApi = new xero.PayrollAuApi(); + this.bankFeedsApi = new xero.BankFeedsApi(); + this.payrollUKApi = new xero.PayrollUkApi(); + this.payrollNZApi = new xero.PayrollNzApi(); + this.appStoreApi = new xero.AppStoreApi(); + this.financeApi = new xero.FinanceApi(); + }; - private _tokenSet: TokenSet = new TokenSet; - private _tenants: any[] = []; + private _tokenSet: TokenSet = new TokenSet; + private _tenants: any[] = []; - readonly accountingApi: xero.AccountingApi; - readonly assetApi: xero.AssetApi; - readonly filesApi: xero.FilesApi; - readonly projectApi: xero.ProjectApi; - readonly payrollAUApi: xero.PayrollAuApi; - readonly bankFeedsApi: xero.BankFeedsApi; - readonly payrollUKApi: xero.PayrollUkApi; - readonly payrollNZApi: xero.PayrollNzApi; - readonly appStoreApi: xero.AppStoreApi; - readonly financeApi: xero.FinanceApi; + readonly accountingApi: xero.AccountingApi; + readonly assetApi: xero.AssetApi; + readonly filesApi: xero.FilesApi; + readonly projectApi: xero.ProjectApi; + readonly payrollAUApi: xero.PayrollAuApi; + readonly bankFeedsApi: xero.BankFeedsApi; + readonly payrollUKApi: xero.PayrollUkApi; + readonly payrollNZApi: xero.PayrollNzApi; + readonly appStoreApi: xero.AppStoreApi; + readonly financeApi: xero.FinanceApi; - openIdClient: Client; // from openid-client + openIdClient: Client; // from openid-client - get tenants(): any[] { - return this._tenants; - } + get tenants(): any[] { + return this._tenants; + } - public async initialize(): Promise { - if (this.config) { - custom.setHttpOptionsDefaults({ - retry: { - maxRetryAfter: this.config.httpTimeout || 3500 - }, - timeout: this.config.httpTimeout || 3500 - }) + public async initialize(): Promise { + if (this.config) { + custom.setHttpOptionsDefaults({ + retry: { + maxRetryAfter: this.config.httpTimeout || 3500 + }, + timeout: this.config.httpTimeout || 3500 + }) - const issuer = await Issuer.discover('https://identity.xero.com'); - this.openIdClient = new issuer.Client({ - client_id: this.config.clientId, - client_secret: this.config.clientSecret, - redirect_uris: this.config.redirectUris, - }); + const issuer = await Issuer.discover('https://identity.xero.com'); + this.openIdClient = new issuer.Client({ + client_id: this.config.clientId, + client_secret: this.config.clientSecret, + redirect_uris: this.config.redirectUris, + }); - this.openIdClient[custom.clock_tolerance] = this.config.clockTolerance || 5; - } - return this; - } + this.openIdClient[custom.clock_tolerance] = this.config.clockTolerance || 5; + } + return this; + } - public async buildConsentUrl(): Promise { - if (!this.openIdClient) { - await this.initialize(); - } - let url; - if (this.config) { - url = this.openIdClient.authorizationUrl({ - redirect_uri: this.config.redirectUris[0], - scope: this.config.scopes.join(' ') || 'openid email profile', - state: this.config.state - }); - } - return url; - } + public async buildConsentUrl(): Promise { + if (!this.openIdClient) { + await this.initialize(); + } + let url; + if (this.config) { + url = this.openIdClient.authorizationUrl({ + redirect_uri: this.config.redirectUris[0], + scope: this.config.scopes.join(' ') || 'openid email profile', + state: this.config.state + }); + } + return url; + } - public async apiCallback(callbackUrl: string): Promise { - if (!this.openIdClient) { - await this.initialize(); - } - const params = this.openIdClient.callbackParams(callbackUrl); - const check = { state: this.config.state }; - if (this.config.scopes.includes('openid')) { - this._tokenSet = await this.openIdClient.callback(this.config.redirectUris[0], params, check); - } else { - this._tokenSet = await this.openIdClient.oauthCallback(this.config.redirectUris[0], params, check); - } - this.setAccessToken(); - return this._tokenSet; - } + public async apiCallback(callbackUrl: string): Promise { + if (!this.openIdClient) { + await this.initialize(); + } + const params = this.openIdClient.callbackParams(callbackUrl); + const check = { state: this.config.state }; + if (this.config.scopes.includes('openid')) { + this._tokenSet = await this.openIdClient.callback(this.config.redirectUris[0], params, check); + } else { + this._tokenSet = await this.openIdClient.oauthCallback(this.config.redirectUris[0], params, check); + } + this.setAccessToken(); + return this._tokenSet; + } - public async disconnect(connectionId: string): Promise { - await this.queryApi('DELETE', `https://api.xero.com/connections/${connectionId}`); - this.setAccessToken(); - return this._tokenSet; - } + public async disconnect(connectionId: string): Promise { + await this.queryApi('DELETE', `https://api.xero.com/connections/${connectionId}`); + this.setAccessToken(); + return this._tokenSet; + } - public readTokenSet(): TokenSet { - return this._tokenSet; - } + public readTokenSet(): TokenSet { + return this._tokenSet; + } - public setTokenSet(tokenSet: TokenSetParameters | TokenSet): void { - this._tokenSet = new TokenSet(tokenSet); - this.setAccessToken(); - } + public setTokenSet(tokenSet: TokenSetParameters | TokenSet): void { + this._tokenSet = new TokenSet(tokenSet); + this.setAccessToken(); + } - public async refreshToken(): Promise { - if (!this._tokenSet) { - throw new Error('tokenSet is not defined'); - } - const refreshedTokenSet = await this.openIdClient.refresh(this._tokenSet.refresh_token); - this._tokenSet = new TokenSet(refreshedTokenSet); - this.setAccessToken(); - return this._tokenSet; - } + public async refreshToken(): Promise { + if (!this._tokenSet) { + throw new Error('tokenSet is not defined'); + } + const refreshedTokenSet = await this.openIdClient.refresh(this._tokenSet.refresh_token); + this._tokenSet = new TokenSet(refreshedTokenSet); + this.setAccessToken(); + return this._tokenSet; + } - public async revokeToken(): Promise { - if (!this._tokenSet) { - throw new Error('tokenSet is not defined'); - } - await this.openIdClient.revoke(this._tokenSet.refresh_token); - this._tokenSet = new TokenSet; - this._tenants = []; - return; - } + public async revokeToken(): Promise { + if (!this._tokenSet) { + throw new Error('tokenSet is not defined'); + } + await this.openIdClient.revoke(this._tokenSet.refresh_token); + this._tokenSet = new TokenSet; + this._tenants = []; + return; + } - private encodeBody(params): string { - var formBody: any = []; - for (var property in params) { - var encodedKey = encodeURIComponent(property); - var encodedValue = encodeURIComponent(params[property]); - formBody.push(encodedKey + "=" + encodedValue); - } - return formBody.join("&"); - } + private encodeBody(params): string { + var formBody: any = []; + for (var property in params) { + var encodedKey = encodeURIComponent(property); + var encodedValue = encodeURIComponent(params[property]); + formBody.push(encodedKey + "=" + encodedValue); + } + return formBody.join("&"); + } - public formatMsDate(dateString: string): string { - const epoch = Date.parse(dateString); - return "/Date(" + epoch + "+0000)/"; - } + public formatMsDate(dateString: string): string { + const epoch = Date.parse(dateString); + return "/Date(" + epoch + "+0000)/"; + } - public async refreshWithRefreshToken(clientId, clientSecret, refreshToken): Promise { - const result = await this.tokenRequest(clientId, clientSecret, { grant_type: 'refresh_token', refresh_token: refreshToken }); - const tokenSet = JSON.parse(result.body); - this._tokenSet = new TokenSet(tokenSet); - this.setAccessToken(); - return this._tokenSet; - } + public async refreshWithRefreshToken(clientId, clientSecret, refreshToken): Promise { + const result = await this.tokenRequest(clientId, clientSecret, { grant_type: 'refresh_token', refresh_token: refreshToken }); + const tokenSet = result.body; + this._tokenSet = new TokenSet(tokenSet); + this.setAccessToken(); + return this._tokenSet; + } - public async getClientCredentialsToken(): Promise { - const { clientId, clientSecret, grantType, scopes } = this.config; - const result = await this.tokenRequest(clientId, clientSecret, { grant_type: grantType, scopes }); - const tokenSet = JSON.parse(result.body); - this._tokenSet = new TokenSet(tokenSet); - this.setAccessToken(); - return this._tokenSet; - } + public async getClientCredentialsToken(): Promise { + const { clientId, clientSecret, grantType, scopes } = this.config; + const result = await this.tokenRequest(clientId, clientSecret, { grant_type: grantType, scopes }); + const tokenSet = result.body; + this._tokenSet = new TokenSet(tokenSet); + this.setAccessToken(); + return this._tokenSet; + } - private async tokenRequest(clientId, clientSecret, body): Promise<{ response: http.IncomingMessage; body: string }> { - return new Promise<{ response: http.IncomingMessage; body: string }>((resolve, reject) => { - request({ - method: 'POST', - uri: 'https://identity.xero.com/connect/token', - headers: { - authorization: "Basic " + Buffer.from(clientId + ":" + clientSecret).toString('base64'), - 'Content-Type': 'application/x-www-form-urlencoded' - }, - body: this.encodeBody(body) - }, (error, response, body) => { - if (error) { - reject(error); - } else { - if (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299) { - resolve({ response: response, body: body }); - } else { - reject({ response: response, body: body }); - } - } - }); - }); - } + private async tokenRequest(clientId, clientSecret, body): Promise<{ response: http.IncomingMessage; body: TokenSet }> { + return new Promise<{ response: http.IncomingMessage; body: TokenSet }>(async (resolve, reject) => { + try { + const response = await axios({ + method: 'POST', + url: 'https://identity.xero.com/connect/token', + headers: { + "Authorization": `Basic ${Buffer.from(clientId + ":" + clientSecret).toString('base64')}`, + "Content-Type": "application/x-www-form-urlencoded" + }, + data: this.encodeBody(body) + }) + if (response.status && response.status >= 200 && response.status <= 299) { + resolve({ response: response, body: response.data }); + } else { + reject({ response: response, body: response.data }); + } + } + catch (error) { + reject(error) + } + }); + } - public async updateTenants(fullOrgDetails: boolean = true): Promise { - const result = await this.queryApi('GET', 'https://api.xero.com/connections'); - let tenants = result.body.map(connection => connection); + public async updateTenants(fullOrgDetails: boolean = true): Promise { + const result = await this.queryApi('GET', 'https://api.xero.com/connections'); + let tenants = result.body.map(connection => connection); - if (fullOrgDetails) { - const getOrgsForAll = tenants.map(async tenant => { - const result = await this.accountingApi.getOrganisations(tenant.tenantId); - return result.body.organisations[0]; - }); - const orgData = await Promise.all(getOrgsForAll); + if (fullOrgDetails) { + const getOrgsForAll = tenants.map(async tenant => { + const result = await this.accountingApi.getOrganisations(tenant.tenantId); + return result.body.organisations[0]; + }); + const orgData = await Promise.all(getOrgsForAll); - tenants.map((tenant) => { // assign orgData nested under each tenant - tenant.orgData = orgData.filter((el) => el.organisationID == tenant.tenantId)[0]; - }); - } - // sorting tenants so the most connection / active tenant is at index 0 - tenants.sort((a: any, b: any) => new Date(b.updatedDateUtc) - new Date(a.updatedDateUtc)); - this._tenants = tenants; - return tenants; - } + tenants.map((tenant) => { // assign orgData nested under each tenant + tenant.orgData = orgData.filter((el) => el.organisationID == tenant.tenantId)[0]; + }); + } + // sorting tenants so the most connection / active tenant is at index 0 + tenants.sort((a: any, b: any) => new Date(b.updatedDateUtc) - new Date(a.updatedDateUtc)); + this._tenants = tenants; + return tenants; + } - private async queryApi(method, uri): Promise<{ response: http.IncomingMessage; body: Array<{ id: string, tenantId: string, tenantName: string, tenantType: string, orgData: any }> }> { - return new Promise<{ response: http.IncomingMessage; body: Array<{ id: string, tenantId: string, tenantName: string, tenantType: string, orgData: any }> }>((resolve, reject) => { - request({ - method, - uri, - auth: { - bearer: this._tokenSet.access_token - }, - json: true - }, (error, response, body) => { - if (error) { - reject(error); - } else { - if (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299) { - resolve({ response: response, body: body }); - } else { - reject({ response: response, body: body }); - } - } - }); - }); - } + private async queryApi(method, uri): Promise<{ response: http.IncomingMessage; body: Array<{ id: string, tenantId: string, tenantName: string, tenantType: string, orgData: any }> }> { + return new Promise<{ response: http.IncomingMessage; body: Array<{ id: string, tenantId: string, tenantName: string, tenantType: string, orgData: any }> }>(async (resolve, reject) => { + try { + const response = await axios({ + method, + url: uri, + headers: { "Authorization": `Bearer ${this._tokenSet.access_token}` }, + responseType: 'json' + }) + if (response.status && response.status >= 200 && response.status <= 299) { + resolve({ response: response, body: response.data }); + } else { + reject({ response: response, body: response.data }); + } + } + catch (error) { + reject(error) + } + }); + } - private setAccessToken(): void { - const accessToken = this._tokenSet.access_token; - if (typeof accessToken === 'undefined') { - throw new Error('Access token is undefined!'); - } + private setAccessToken(): void { + const accessToken = this._tokenSet.access_token; + if (typeof accessToken === 'undefined') { + throw new Error('Access token is undefined!'); + } - this.accountingApi.accessToken = accessToken; - this.assetApi.accessToken = accessToken; - this.filesApi.accessToken = accessToken; - this.projectApi.accessToken = accessToken; - this.payrollAUApi.accessToken = accessToken; - this.bankFeedsApi.accessToken = accessToken; - this.payrollUKApi.accessToken = accessToken; - this.payrollNZApi.accessToken = accessToken; - this.appStoreApi.accessToken = accessToken; - this.financeApi.accessToken = accessToken; - } -} \ No newline at end of file + this.accountingApi.accessToken = accessToken; + this.assetApi.accessToken = accessToken; + this.filesApi.accessToken = accessToken; + this.projectApi.accessToken = accessToken; + this.payrollAUApi.accessToken = accessToken; + this.bankFeedsApi.accessToken = accessToken; + this.payrollUKApi.accessToken = accessToken; + this.payrollNZApi.accessToken = accessToken; + this.appStoreApi.accessToken = accessToken; + this.financeApi.accessToken = accessToken; + } +}