From bf14ded8c244e2c135a8034d7b659f6e4f156ebe Mon Sep 17 00:00:00 2001 From: Miguel Gall Martin Date: Mon, 16 Sep 2024 12:01:02 -0400 Subject: [PATCH] Add Token support in main method (#11) * Add Token support in main method * 1.3.0 --- package-lock.json | 14 +- package.json | 4 +- src/main.ts | 519 +++++++++++++++++++++++++++++----------------- 3 files changed, 341 insertions(+), 196 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb4e789..398ca19 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ofs-users/plugin", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ofs-users/plugin", - "version": "1.2.0", + "version": "1.3.0", "license": "UPL-1.0", "dependencies": { - "@ofs-users/proxy": "^1.7.1" + "@ofs-users/proxy": "^1.9.0" }, "devDependencies": { "@rollup/plugin-terser": "^0.2.1", @@ -93,10 +93,12 @@ } }, "node_modules/@ofs-users/proxy": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@ofs-users/proxy/-/proxy-1.7.1.tgz", - "integrity": "sha512-TY4XrDgFRIpEPnjjwW8MXxlhtzEKh/J7NBbxdnFOiKQsLxBWiHbenHK/32JZ0sewpVWJsmPLK1upVROaOgREIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@ofs-users/proxy/-/proxy-1.9.0.tgz", + "integrity": "sha512-kYFMkYSZiv90oy7oCx2VIpHjU0Rhb9FvsRqrmts4Nd1PEuA8RhdEu10dKXk9cY1k7iNoMJPbtVPgHANEAXN2tg==", + "license": "UPL-1.0", "dependencies": { + "@ofs-users/proxy": "^1.8.2", "tslib": "^2.4.1" } }, diff --git a/package.json b/package.json index 327d2bb..619299a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ ], "name": "@ofs-users/plugin", "type": "module", - "version": "1.2.0", + "version": "1.3.0", "description": "Oracle Field Service plugin base code", "main": "dist/ofs-plugin.es.js", "module": "dist/ofs-plugin.es.js", @@ -40,6 +40,6 @@ }, "license": "UPL-1.0", "dependencies": { - "@ofs-users/proxy": "^1.7.1" + "@ofs-users/proxy": "^1.9.0" } } diff --git a/src/main.ts b/src/main.ts index baefce1..a9f655a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -3,211 +3,354 @@ * Licensed under the Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/ */ -import { OFS } from "@ofs-users/proxy"; +import { OFS, OFSCredentials } from "@ofs-users/proxy"; export class OFSMessage { - apiVersion: number = -1; - method: string = "no method"; - securedData?: any; - sendInitData?: boolean; - - static parse(str: string) { - try { - return Object.assign(new OFSMessage(), JSON.parse(str)) as OFSMessage; - } catch (error) { - return new OFSMessage(); - } - } + apiVersion: number = -1; + method: string = "no method"; + securedData?: any; + sendInitData?: boolean; + + static parse(str: string) { + try { + return Object.assign( + new OFSMessage(), + JSON.parse(str) + ) as OFSMessage; + } catch (error) { + return new OFSMessage(); + } + } } export enum Method { - Close = "close", - Open = "open", - Update = "update", - UpdateResult = "updateResult", - Init = "init", - Ready = "ready", - InitEnd = "initEnd", - CallProcedureResult = "callProcedureResult", - CallProcedure = "callProcedure", + Close = "close", + Open = "open", + Update = "update", + UpdateResult = "updateResult", + Init = "init", + Ready = "ready", + InitEnd = "initEnd", + CallProcedureResult = "callProcedureResult", + CallProcedure = "callProcedure", } export class OFSOpenMessage extends OFSMessage { - entity: string | undefined; + entity: string | undefined; } +export class OFSInitMessage extends OFSMessage { + applications: any | undefined; +} +export class OFSInitMessage_applications { + type: string | undefined; + resourceUrl: string | undefined; +} export class OFSCallProcedureResultMessage extends OFSMessage { - resultData: any | undefined; + callId: string | undefined; + resultData: any | undefined; } export class OFSCloseMessage extends OFSMessage { - method: string = "close"; - activity?: any; + method: string = "close"; + activity?: any; } +declare global { + var callId: string; + var waitForProxy: boolean; +} export abstract class OFSPlugin { - private _proxy!: OFS; - private _tag: string; - - constructor(tag: string) { - console.log(`${tag}: Created`); - - this._tag = tag; - - this._setup(); - } - - get proxy(): OFS { - return this._proxy; - } - - get tag(): string { - return this._tag; - } - - /** - * Processes received messages - * @param message Message received - * @returns - */ - private _getWebMessage(message: MessageEvent): boolean { - console.log(`${this._tag}: Message received:`, message.data); - console.log(`${this._tag}: Coming from ${message.origin}`); - // Validate that it is a valid OFS message - var parsed_message = OFSMessage.parse(message.data); - this._storeCredentials(parsed_message); - switch (parsed_message.method) { - case "init": - this._init(parsed_message); - break; - case "open": - this.open(parsed_message as OFSOpenMessage); - break; - case "updateResult": - this.updateResult(parsed_message); - break; - case "callProcedureResult": - this.callProcedureResult( - parsed_message as OFSCallProcedureResultMessage + private _proxy!: OFS; + private _tag: string; + + constructor(tag: string) { + console.log(`${tag}: Created`); + + this._tag = tag; + + this._setup(); + } + + get proxy(): OFS { + return this._proxy; + } + + get tag(): string { + return this._tag; + } + + /** + * Processes received messages + * @param message Message received + * @returns + */ + private async _getWebMessage(message: MessageEvent): Promise { + console.log(`${this._tag}: Message received:`, message.data); + console.log(`${this._tag}: Coming from ${message.origin}`); + // Validate that it is a valid OFS message + var parsed_message = OFSMessage.parse(message.data); + + switch (parsed_message.method) { + case "init": + this._storeInitData(parsed_message as OFSInitMessage); + this._init(parsed_message); + break; + case "open": + globalThis.waitForProxy = false; + this._createProxy(parsed_message); + var iteration: number = 0; + while (globalThis.waitForProxy) { + // I need to wait for the Proxy creation + console.debug( + `${this._tag}: Waiting for the Proxy creation` + ); + await this._sleep(100); + console.log("Slept for 100 ms"); + iteration++; + if (iteration > 30) { + console.error(`${this._tag}: Proxy creation problem`); + globalThis.waitForProxy = false; + break; + } + } + this.open(parsed_message as OFSOpenMessage); + break; + case "updateResult": + this.updateResult(parsed_message); + break; + case "callProcedureResult": + this._callProcedureResult( + parsed_message as OFSCallProcedureResultMessage + ); + break; + case "wakeUp": + this.wakeup(parsed_message); + break; + case "error": + this.error(parsed_message); + break; + case "no method": + console.warn(`${this._tag}: Message discarded`); + break; + + default: + throw new Error(`Unknown method ${parsed_message.method}`); + break; + } + return true; + } + + private async _init(message: OFSMessage) { + this.init(message); + var messageData: OFSMessage = { + apiVersion: 1, + method: "initEnd", + }; + this._sendWebMessage(messageData); + } + private _sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + private _generateCallId(): string { + const characters = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + let result = ""; + const charactersLength = characters.length; + for (let i = 0; i < charactersLength; i++) { + result += characters.charAt( + Math.floor(Math.random() * charactersLength) + ); + } + return result; + } + private _createProxy(message: OFSMessage) { + var applications = this.getInitProperty("applications"); + + if (applications != null) { + applications = JSON.parse(applications); + for (const [key, value] of Object.entries(applications)) { + var applicationKey: string = key; + var application: any = value as OFSInitMessage_applications; + if (application.type == "ofs") { + this.storeInitProperty("baseURL", application.resourceUrl); + var callId = this._generateCallId(); + globalThis.callId = callId; + var callProcedureData = { + callId: callId, + procedure: "getAccessToken", + params: { + applicationKey: applicationKey, + }, + }; + console.debug( + `${ + this.tag + }. I will request the Token forthe application ${applicationKey} with this message ${JSON.stringify( + callProcedureData + )}` + ); + this.callProcedure(callProcedureData); + globalThis.waitForProxy = true; + return; + } + } + } + if (message.securedData) { + console.log(`${this._tag}: Processing`, message.securedData); + // STEP 1: are we going to create a proxy? + if ( + message.securedData.ofsInstance && + message.securedData.ofsClientId && + message.securedData.ofsClientSecret + ) { + this._proxy = new OFS({ + instance: message.securedData.ofsInstance, + clientId: message.securedData.ofsClientId, + clientSecret: message.securedData.ofsClientSecret, + }); + } + } + } + private _storeInitData(message: OFSInitMessage) { + if (message.applications) { + this.storeInitProperty( + "applications", + JSON.stringify(message.applications) + ); + } + } + public storeInitProperty(property: string, data: any) { + console.debug(`${this.tag}.${property}: Storing ${property}`, data); + window.localStorage.setItem(`${this.tag}.${property}`, data); + } + + public getInitProperty(property: string): any { + var data = window.localStorage.getItem(`${this.tag}.${property}`); + return data; + } + private static _getOriginURL(url: string) { + if (url != "") { + if (url.indexOf("://") > -1) { + return "https://" + url.split("/")[2]; + } else { + return "https://" + url.split("/")[0]; + } + } + return ""; + } + private _sendWebMessage(data: OFSMessage) { + console.log( + `${this._tag}: Sending message` + + JSON.stringify(data, undefined, 4) ); - break; - case "wakeUp": - this.wakeup(parsed_message); - break; - case "error": - this.error(parsed_message); - break; - case "no method": - console.warn(`${this._tag}: Message discarded`); - break; - - default: - throw new Error(`Unknown method ${parsed_message.method}`); - break; - } - return true; - } - - private async _init(message: OFSMessage) { - this.init(message); - var messageData: OFSMessage = { - apiVersion: 1, - method: "initEnd", - }; - this._sendWebMessage(messageData); - } - - private _storeCredentials(message: OFSMessage) { - if (message.securedData) { - console.log(`${this._tag}: Processing`, message.securedData); - // STEP 1: are we going to create a proxy? - if ( - message.securedData.ofsInstance && - message.securedData.ofsClientId && - message.securedData.ofsClientSecret - ) { - this._proxy = new OFS({ - instance: message.securedData.ofsInstance, - clientId: message.securedData.ofsClientId, - clientSecret: message.securedData.ofsClientSecret, + var originUrl = + document.referrer || + (document.location.ancestorOrigins && + document.location.ancestorOrigins[0]) || + ""; + + if (originUrl) { + parent.postMessage(data, OFSPlugin._getOriginURL(originUrl)); + } + } + + public sendMessage(method: Method, data?: any): void { + this._sendWebMessage({ + apiVersion: 1, + method: method, + ...data, }); - } - } - } - - private static _getOriginURL(url: string) { - if (url != "") { - if (url.indexOf("://") > -1) { - return "https://" + url.split("/")[2]; - } else { - return "https://" + url.split("/")[0]; - } - } - return ""; - } - private _sendWebMessage(data: OFSMessage) { - console.log( - `${this._tag}: Sending message` + JSON.stringify(data, undefined, 4) - ); - var originUrl = - document.referrer || - (document.location.ancestorOrigins && - document.location.ancestorOrigins[0]) || - ""; - - if (originUrl) { - parent.postMessage(data, OFSPlugin._getOriginURL(originUrl)); - } - } - - public sendMessage(method: Method, data?: any): void { - this._sendWebMessage({ - apiVersion: 1, - method: method, - ...data, - }); - } - - private _setup() { - console.log("OFS plugin ready"); - window.addEventListener("message", this._getWebMessage.bind(this), false); - var messageData: OFSMessage = { - apiVersion: 1, - method: "ready", - sendInitData: true, - }; - this._sendWebMessage(messageData); - } - - // There should be always an 'open' method - abstract open(data: OFSOpenMessage): void; - - // These methods can be overwritten - init(message: OFSMessage) { - // Nothing to be done if not needed - console.warn(`${this._tag}: Empty init method`); - } - - public close(data?: any): void { - this.sendMessage(Method.Close, data); - } - public callProcedure(data?: any): void { - this.sendMessage(Method.CallProcedure, data); - } - public update(data?: any): void { - this.sendMessage(Method.Update, data); - } - - error(parsed_message: OFSMessage) { - throw new Error("ERROR Method not implemented."); - } - wakeup(parsed_message: OFSMessage) { - throw new Error("WAKEUP Method not implemented."); - } - updateResult(parsed_message: OFSMessage) { - throw new Error("UPDATERESULT Method not implemented."); - } - callProcedureResult(parsed_message: OFSMessage) { - throw new Error("CALLPROCEDURERESULT Method not implemented."); - } + } + + private _setup() { + console.log("OFS plugin ready"); + window.addEventListener( + "message", + this._getWebMessage.bind(this), + false + ); + var messageData: OFSMessage = { + apiVersion: 1, + method: "ready", + sendInitData: true, + }; + this._sendWebMessage(messageData); + } + + // There should be always an 'open' method + abstract open(data: OFSOpenMessage): void; + + // These methods can be overwritten + init(message: OFSMessage) { + // Nothing to be done if not needed + console.warn(`${this._tag}: Empty init method`); + } + + public close(data?: any): void { + this.sendMessage(Method.Close, data); + } + public callProcedure(data?: any): void { + this.sendMessage(Method.CallProcedure, data); + } + public update(data?: any): void { + this.sendMessage(Method.Update, data); + } + + error(parsed_message: OFSMessage) { + throw new Error("ERROR Method not implemented."); + } + wakeup(parsed_message: OFSMessage) { + throw new Error("WAKEUP Method not implemented."); + } + updateResult(parsed_message: OFSMessage) { + throw new Error("UPDATERESULT Method not implemented."); + } + callProcedureResult(parsed_message: OFSCallProcedureResultMessage) { + throw new Error("CALLPROCEDURERESULT Method not implemented."); + } + private _callProcedureResult( + parsed_message: OFSCallProcedureResultMessage + ) { + if ((parsed_message.callId = globalThis.callId)) { + var baseURLOFS = this.getInitProperty("baseURL"); + if ("resultData" in parsed_message) { + if ( + "status" in parsed_message.resultData && + parsed_message.resultData.status == "success" + ) { + var OFSCredentials: OFSCredentials = { + baseURL: baseURLOFS, + token: parsed_message.resultData.token, + }; + console.debug( + `${ + this.tag + }. I will create the proxy with this data ${JSON.stringify( + OFSCredentials + )}` + ); + this._proxy = new OFS(OFSCredentials); + globalThis.waitForProxy = false; + return; + } + } else { + console.error( + `${ + this.tag + }. Problems processing the Token Response ${JSON.stringify( + parsed_message + )}` + ); + } + } else { + console.debug( + `${this.tag}. CallId is not the one generated for getting the token '${globalThis.callId}' vs '${parsed_message.callId}'` + ); + this.callProcedureResult( + parsed_message as OFSCallProcedureResultMessage + ); + } + } }