From 42a9a8c4027d5f3867c2b5f714fd12489a142f52 Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Mon, 20 Nov 2023 11:29:36 -0300 Subject: [PATCH] fix(core.gbapp): #387 adding /setupSecurity multiple tokens. Refresh token fix. @othonlima. --- packages/admin.gbapp/dialogs/AdminDialog.ts | 4 +- .../admin.gbapp/services/GBAdminService.ts | 102 +++++++++++++----- packages/basic.gblib/services/GBVMService.ts | 11 +- packages/core.gbapp/services/GBMinService.ts | 5 +- 4 files changed, 89 insertions(+), 33 deletions(-) diff --git a/packages/admin.gbapp/dialogs/AdminDialog.ts b/packages/admin.gbapp/dialogs/AdminDialog.ts index dcd32a4d..8caa755b 100644 --- a/packages/admin.gbapp/dialogs/AdminDialog.ts +++ b/packages/admin.gbapp/dialogs/AdminDialog.ts @@ -425,14 +425,14 @@ export class AdminDialog extends IGBDialog { if (!tokenName) { min.instance.authenticatorAuthorityHostUrl = step.activeDialog.state.authenticatorAuthorityHostUrl; min.instance.authenticatorTenant = step.activeDialog.state.authenticatorTenant; - } + await min.adminService.updateSecurityInfo( min.instance.instanceId, tokenName ? step.activeDialog.state.tenant : step.activeDialog.state.authenticatorTenant, tokenName ? step.activeDialog.state.host : step.activeDialog.state.authenticatorAuthorityHostUrl ); - + } const locale = step.context.activity.locale; const buf = Buffer.alloc(16); const state = `${min.instance.instanceId}${crypto.randomFillSync(buf).toString('hex')}`; diff --git a/packages/admin.gbapp/services/GBAdminService.ts b/packages/admin.gbapp/services/GBAdminService.ts index 8b28ede0..7668938a 100644 --- a/packages/admin.gbapp/services/GBAdminService.ts +++ b/packages/admin.gbapp/services/GBAdminService.ts @@ -238,6 +238,7 @@ export class GBAdminService implements IGBAdminService { tenant: string = null ): Promise { + if (root) { const minBoot = GBServer.globals.minBoot; instanceId = minBoot.instance.instanceId; @@ -251,6 +252,7 @@ export class GBAdminService implements IGBAdminService { throw new Error(`/setupSecurity is required before running /publish.`); } + return new Promise(async (resolve, reject) => { const instance = await this.core.loadInstanceById(instanceId); @@ -259,38 +261,84 @@ export class GBAdminService implements IGBAdminService { const accessToken = await this.getValue(instanceId, `${tokenName}accessToken`); resolve(accessToken); } else { - const oauth2 = tokenName ? 'oauth' : 'oauth2'; - const authorizationUrl = urlJoin( - tokenName ? host : instance.authenticatorAuthorityHostUrl, - tokenName ? tenant : instance.authenticatorTenant, - `/${oauth2}/authorize` - ); - const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`); - const resource = tokenName ? '' : 'https://graph.microsoft.com'; - const authenticationContext = new AuthenticationContext(authorizationUrl); + if (tokenName && !root) { - authenticationContext.acquireTokenWithRefreshToken( - refreshToken, - tokenName ? clientId : instance.marketplaceId, - tokenName ? clientSecret : instance.marketplacePassword, - resource, - async (err, res) => { - if (err !== null) { - reject(err); - } else { - const token = res as TokenResponse; - try { - await this.setValue(instanceId, `${tokenName}accessToken`, token.accessToken); - await this.setValue(instanceId, `${tokenName}refreshToken`, token.refreshToken); - await this.setValue(instanceId, `${tokenName}expiresOn`, token.expiresOn.toString()); - resolve(token.accessToken); - } catch (error) { + const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`); + + let url = urlJoin( + host, + tenant, 'oauth/token'); + let buff = new Buffer(`${clientId}:${clientSecret}`); + const base64 = buff.toString('base64'); + + const options = { + method: 'POST', + headers: { + Accept: '1.0', + Authorization: `Basic ${base64}`, + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: new URLSearchParams({ + 'grant_type': 'refresh_token', + 'refresh_token': refreshToken + }) + }; + const result = await fetch(url, options); + + if (result.status != 200) { + throw new Error(`acquireElevatedToken error: ${result.status}: ${result.statusText}.`) + } + + const text = await result.text(); + const token = JSON.parse(text); + + // Saves token to the database. + + await this.setValue(instanceId, `${tokenName}accessToken`, token['access_token']); + await this.setValue(instanceId, `${tokenName}refreshToken`, token['refresh_token']); + await this.setValue(instanceId, `${tokenName}expiresOn`, + new Date(Date.now() + token['expires_in']).toString()); + await this.setValue(instanceId, `${tokenName}AntiCSRFAttackState`, null); + + resolve(token['access_token']); + + } + else { + + const oauth2 = tokenName ? 'oauth' : 'oauth2'; + const authorizationUrl = urlJoin( + tokenName ? host : instance.authenticatorAuthorityHostUrl, + tokenName ? tenant : instance.authenticatorTenant, + `/${oauth2}/authorize` + ); + + const refreshToken = await this.getValue(instanceId, `${tokenName}refreshToken`); + const resource = tokenName ? '' : 'https://graph.microsoft.com'; + const authenticationContext = new AuthenticationContext(authorizationUrl); + + authenticationContext.acquireTokenWithRefreshToken( + refreshToken, + tokenName ? clientId : instance.marketplaceId, + tokenName ? clientSecret : instance.marketplacePassword, + resource, + async (err, res) => { + if (err !== null) { reject(err); + } else { + const token = res as TokenResponse; + try { + await this.setValue(instanceId, `${tokenName}accessToken`, token.accessToken); + await this.setValue(instanceId, `${tokenName}refreshToken`, token.refreshToken); + await this.setValue(instanceId, `${tokenName}expiresOn`, token.expiresOn.toString()); + resolve(token.accessToken); + } catch (error) { + reject(err); + } } } - } - ); + ); + } } }); } diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 3f251d3c..fa3cb7c7 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -212,10 +212,14 @@ export class GBVMService extends GBService { return { key: 'UUID' }; case 'key': return { key: 'STRING' }; // Assuming key is a string data type + case 'number': + return { key: 'INTEGER' }; case 'integer': return { key: 'INTEGER' }; case 'double': return { key: 'FLOAT' }; + case 'float': + return { key: 'FLOAT' }; case 'date': return { key: 'DATE' }; case 'boolean': @@ -525,9 +529,10 @@ export class GBVMService extends GBService { } public static normalizeQuotes(text: any) { - text = text.replace(/\¨/gm, '"'); - text = text.replace(/\“/gm, '"'); - text = text.replace(/\”/gm, '"'); + text = text.replace(/\"/gm, '`'); + text = text.replace(/\¨/gm, '`'); + text = text.replace(/\“/gm, '`'); + text = text.replace(/\”/gm, '`'); text = text.replace(/\‘/gm, "'"); text = text.replace(/\’/gm, "'"); diff --git a/packages/core.gbapp/services/GBMinService.ts b/packages/core.gbapp/services/GBMinService.ts index d6b0f98d..3fcd326c 100644 --- a/packages/core.gbapp/services/GBMinService.ts +++ b/packages/core.gbapp/services/GBMinService.ts @@ -548,8 +548,11 @@ export class GBMinService { `${tokenName}accessToken`, token['accessToken']?token['accessToken']:token['access_token']); await this.adminService.setValue(instance.instanceId, `${tokenName}refreshToken`, token['refreshToken']?token['refreshToken']:token['refresh_token']); + await this.adminService.setValue(instance.instanceId, - `${tokenName}expiresOn`, token['expiresOn']?token['expiresOn'].toString():token['expires_in'].toString()); + `${tokenName}expiresOn`, token['expiresOn'] ? + token['expiresOn'].toString(): + new Date (Date.now() + token['expires_in'])); await this.adminService.setValue(instance.instanceId, `${tokenName}AntiCSRFAttackState`, null);