From c3d5aef5e01ee7c8ca1741aa36a81364e97b68cb Mon Sep 17 00:00:00 2001 From: "Peter.Morton" Date: Wed, 20 Dec 2023 23:16:39 -0600 Subject: [PATCH] moved channel automation code into helper --- package-lock.json | 7 ++ package.json | 1 + src/@types/ChannelAutomationAPI.ts | 5 ++ src/@types/JSONWebToken.ts | 3 + src/@types/SessionIdentiferProps.ts | 3 - src/helpers/index.ts | 107 +++++++++++++++------------- src/views/DebugView.vue | 35 ++++----- src/views/TelephonyContext.vue | 23 ++---- vite.config.ts | 10 ++- 9 files changed, 107 insertions(+), 87 deletions(-) create mode 100644 src/@types/ChannelAutomationAPI.ts create mode 100644 src/@types/JSONWebToken.ts delete mode 100644 src/@types/SessionIdentiferProps.ts diff --git a/package-lock.json b/package-lock.json index 1a243de..2a951d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@types/d3": "^7.4.3", + "@types/jwk-to-pem": "^2.0.3", "@types/jwt-decode": "^3.1.0", "@vitejs/plugin-vue": "^4.2.3", "@vue/eslint-config-prettier": "^8.0.0", @@ -1101,6 +1102,12 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jwk-to-pem": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/jwk-to-pem/-/jwk-to-pem-2.0.3.tgz", + "integrity": "sha512-I/WFyFgk5GrNbkpmt14auGO3yFK1Wt4jXzkLuI+fDBNtO5ZI2rbymyGd6bKzfSBEuyRdM64ZUwxU1+eDcPSOEQ==", + "dev": true + }, "node_modules/@types/jwt-decode": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-3.1.0.tgz", diff --git a/package.json b/package.json index 7af8e88..11293fb 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ }, "devDependencies": { "@types/d3": "^7.4.3", + "@types/jwk-to-pem": "^2.0.3", "@types/jwt-decode": "^3.1.0", "@vitejs/plugin-vue": "^4.2.3", "@vue/eslint-config-prettier": "^8.0.0", diff --git a/src/@types/ChannelAutomationAPI.ts b/src/@types/ChannelAutomationAPI.ts new file mode 100644 index 0000000..f612393 --- /dev/null +++ b/src/@types/ChannelAutomationAPI.ts @@ -0,0 +1,5 @@ +export interface ChannelAutomationAPI { + host: string; + tenant: string; + authentication: string; +} diff --git a/src/@types/JSONWebToken.ts b/src/@types/JSONWebToken.ts new file mode 100644 index 0000000..baeeb59 --- /dev/null +++ b/src/@types/JSONWebToken.ts @@ -0,0 +1,3 @@ +export interface JSONWebToken { + iss: string; +} diff --git a/src/@types/SessionIdentiferProps.ts b/src/@types/SessionIdentiferProps.ts deleted file mode 100644 index 4d6e960..0000000 --- a/src/@types/SessionIdentiferProps.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface SessionIdentiferProps { - sessionIdentifier: string; -} diff --git a/src/helpers/index.ts b/src/helpers/index.ts index aa2036b..37871af 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1,54 +1,61 @@ -import { apiBaseUrl } from "../app.config.js"; -import type { SessionIdentiferProps } from "../@types/SessionIdentiferProps"; +import type { ChannelAutomationAPI } from "../@types/ChannelAutomationAPI"; +import { jwtDecode } from "jwt-decode"; +import type { VueCookies } from "vue-cookies"; +import { inject } from "vue"; -export function getAuthKeyFromProperties(props: SessionIdentiferProps) { - let authKey; +export const COOKIE_PREFIX = "__Host-VRNTOTCT"; - if (props.sessionIdentifier && props.sessionIdentifier.length > 0) { - authKey = props.sessionIdentifier; - } else { - throw new Error( - "_sessionIdentifier property not found (check query params)", - ); - } - return authKey; -} - -export function getTenantProperty(key: string, props: SessionIdentiferProps) { - return new Promise((resolve, reject) => { - if (!props) { - reject("no props provided for authentication"); - return; - } - if (!key || key.length == 0) { - reject("no key provided"); - return; - } - - const authKey = getAuthKeyFromProperties(props); - console.log(`Fetching TPS Property [${key}]`); - fetch(`${apiBaseUrl}/tps/${key}?authKey=${authKey}`, { - credentials: "include", // fetch won't send cookies unless you set credentials - }) - .then((response) => { - // check for error response - if (!response.ok) { - reject(response.body || response.statusText); +export function getChannnelAutomationAPI(): + | Readonly + | undefined { + const $cookies = inject("$cookies"); + if ($cookies) { + for (const cookieKey of $cookies.keys()) { + if (cookieKey.startsWith(COOKIE_PREFIX)) { + const authCookie = $cookies.get(cookieKey) as string; + const jwtDecoded = jwtDecode(authCookie); + if (jwtDecoded && jwtDecoded.iss) { + const issSplit = jwtDecoded.iss.split("/oidc-token-service/"); + return { + host: issSplit[0], + tenant: issSplit[1], + authentication: authCookie, + }; } - response - .json() - .then((data: { data: { value: string } }) => { - console.log("Found Property:" + JSON.stringify(data)); - resolve(data.data.value); - }) - .catch((error) => { - console.error(error); - reject(error); - }); - }) - .catch((error) => { - console.error(error); - reject(error); - }); - }); + } + } + } + return undefined; +} + +export function getTenantProperty(key?: string): string | undefined { + const channelAutomationAPI = getChannnelAutomationAPI(); + if (!channelAutomationAPI) { + return undefined; + } + const headers = { + Authorization: `OIDC_id_token ${channelAutomationAPI.authentication}`, + "Content-Type": "application/json", + }; + + fetch( + `${channelAutomationAPI.host}/tenant-properties-service/${channelAutomationAPI.tenant}/properties?fields=name,value,lastModifiedDate,lastModifiedBy?q=${key}`, + { headers }, + ) + .then(async (response) => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const data = await response.json(); + + // check for error response + if (!response.ok) { + // get error message from body or default to response statusText + // const error = (data && data.message) || response.statusText; + return Promise.reject(response.statusText); + } + + console.debug(data); + }) + .catch((error) => { + console.error("There was an error!", error); + }); } diff --git a/src/views/DebugView.vue b/src/views/DebugView.vue index a887fdf..4c1856c 100644 --- a/src/views/DebugView.vue +++ b/src/views/DebugView.vue @@ -1,35 +1,38 @@ @@ -39,8 +42,8 @@ onMounted(() => { -

VRNTOTCT authentication

-

OIDC Token is {{ authCookie }}

JWT Decoded

-
{{ jwtDecoded }}
+
{{ JSON.stringify(jwtDecoded, null, 2) }}
+

API Connection from JWT Token

+
{{ channelAutomationAPI }}
diff --git a/src/views/TelephonyContext.vue b/src/views/TelephonyContext.vue index 420fd14..31f4009 100644 --- a/src/views/TelephonyContext.vue +++ b/src/views/TelephonyContext.vue @@ -7,14 +7,13 @@ import IntegrationCard from "../components/IntegrationCard.vue"; import DaVinciView from "./DaVinciView.vue"; import type { VueCookies } from "vue-cookies"; -import type { SessionIdentiferProps } from "../@types/SessionIdentiferProps"; const $cookies = inject("$cookies"); if ($cookies) { const key = "__Host-VRNTOTCT404fdb6f"; $cookies.set( key, - "eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4MThlZDMxMmVkOGRhNTVkZWZkM2EzZmI0OGY1NjQzMWFjMWMwMmEzZjZkMmFkMjVjNDA5ZmEwOTA1NDU3ZTkiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOlsiZGVmYXVsdCJdLCJhenAiOiJkZWZhdWx0IiwiY29tLnZlcmludC5pc0V4dGVybmFsbHlBdXRoZW50aWNhdGVkIjpmYWxzZSwiY29tLnZlcmludC5sb2dpblJlc3VsdCI6MSwiY29tLnZlcmludC5zY3JlZW5IZWlnaHQiOiI5MTQiLCJjb20udmVyaW50LnNjcmVlbldpZHRoIjoiMTQxNCIsImNvbnRlbnRfZW50aXRsZW1lbnRzIjpbIlRlYW1FRDpjY2FnZW50dGVhbSIsIlRlYW1Sb2xlRUQ6Y2NhZ2VudHRlYW1yb2xlIiwiVGVhbUVEOkNsYWltcyIsIlJlZ2lzdGVyZWRVc2VyQ29udGVudCIsIlBhZ2VTZXRFeGVjdXRpb25FbnRpdGxlbWVudDAiXSwiY29udGV4dF9lbnRpdGxlbWVudHMiOlsiQ29udGV4dFVwZGF0ZXJBUElBY2Nlc3MiXSwiZW1fYXBpX2FjY2VzcyI6WyJlbWFpbF9vdXRnb2luZ19jcmVhdGUiLCJlbWFpbF9vdXRnb2luZ19mb3J3YXJkIiwiZW1haWxfb3V0Z29pbmdfcmVwbHkiLCJhY2Nlc3NfY2FzZV9jcmVhdGUiLCJhY2Nlc3NfYXR0YWNobWVudF9kb3dubG9hZCIsImFjY2Vzc19hdHRhY2htZW50X3VwbG9hZCIsImNhc2VfdXBkYXRlIiwiYWNjZXNzX2N1c3RvbWVyX2NyZWF0ZSIsImN1c3RvbWVyX3JlYWQiLCJjdXN0b21lcl9zZWFyY2giLCJlbWFpbG1haWxib3hfc2VhcmNoIiwiYWNjZXNzX21lc3NhZ2luZ19yZWFkIiwicHJlZmVyZW5jZXNfY29udGVudGxvY2FsZSIsInByZWZlcmVuY2VzX2Rlc2t0b3Bsb2NhbGUiLCJNZXNzYWdpbmciXSwiZXhwIjoxNzAzMDcwMjI3LCJpYXQiOjE3MDMwMzQyMjcsImlzcyI6Imh0dHBzOi8vZW0yMC52ZXJpbnQubGl2ZTo0NDMvb2lkYy10b2tlbi1zZXJ2aWNlL2RlZmF1bHQiLCJyZWFsbSI6Ii9kZWZhdWx0Iiwic3ViIjoiY2NhZ2VudCIsInpvbmVpbmZvIjoiQW1lcmljYS9DaGljYWdvIn0.hRQLzfOSp8eWMoDVXNPVNBsaSJLEbZtHfbAWHseTB76dvqVPtw6TYW6ZP8FPKX339ngpuHkHj9QtyaVPbriJnvoKkEK9mSgbDWkO1d8nkGtnzcCxkZoLz7MsAUllbIVaaBqED_jf17rio_dc73dfbRjDOIg44firKVnC4SbGMiLHw5796maP3qoIs7PAw1tG_7YrPc0_idMinsF5hA71hl-NgVq-BIz5m7Sjy0Jm4h162PxXGcNek-PxZkOIrQyrGi9D1e8xdZpzbXMvgRD6YoTYkMc45bzY4-aHf3TwYWKaE64hunuWe05KRnlInsHH2BJpPOqRkov9sJx6DGOlIQ", + "eyJhbGciOiJSUzI1NiIsImtpZCI6IjM4MThlZDMxMmVkOGRhNTVkZWZkM2EzZmI0OGY1NjQzMWFjMWMwMmEzZjZkMmFkMjVjNDA5ZmEwOTA1NDU3ZTkiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOlsiZGVmYXVsdCJdLCJhenAiOiJkZWZhdWx0IiwiY29tLnZlcmludC5pc0V4dGVybmFsbHlBdXRoZW50aWNhdGVkIjpmYWxzZSwiY29tLnZlcmludC5sb2dpblJlc3VsdCI6MSwiY29udGVudF9lbnRpdGxlbWVudHMiOlsiUmVnaXN0ZXJlZFVzZXJDb250ZW50Il0sImNvbnRleHRfZW50aXRsZW1lbnRzIjpbIkNvbnRleHRVcGRhdGVyQVBJQWNjZXNzIl0sImVtX2FwaV9hY2Nlc3MiOlsic2VjdXJlbXNnX21lc3NhZ2Vfc2VhcmNoIiwiZW1haWxfb3V0Z29pbmdfZm9yd2FyZCIsImR5bmFtaWNlbnRpdHlfY3JlYXRlIiwiZHluYW1pY2VudGl0eV91cGRhdGUiLCJhY2Nlc3NfYXR0YWNobWVudF91cGxvYWQiLCJhY2Nlc3NfYXR0YWNobWVudF9kb3dubG9hZCIsImVtYWlsbWFpbGJveF9zZWFyY2giLCJlbWFpbF9vdXRnb2luZ19yZXBseSIsImFjY2Vzc19jYXNlX2NyZWF0ZSIsIkNhc2VBdHRhY2htZW50VmlldyIsImVudGl0eV9maWVsZF9hdWRpdF9yZWFkIiwiYWNjZXNzX2FnZW50X3VwZGF0ZSIsIkNhc2VBdHRhY2htZW50VXBsb2FkIiwiY3VzdG9tZXJfcmVhZCIsImVtYWlsbWFpbGJveF9jb25maWd1cmUiLCJ3aWFzX3JlYWQiLCJhY2Nlc3NfdWRnX3JlYWQiLCJhY2Nlc3NfY3VzdG9tZXJfY3JlYXRlIiwic2VjdXJlbXNnX2NvbnZlcnNhdGlvbl9jcmVhdGUiLCJzZWN1cmVtc2dfbWVzc2FnZV9jcmVhdGUiLCJzZWN1cmVtc2dfY29udmVyc2F0aW9uX3JlYWQiLCJzZWN1cmVtc2dfY29udmVyc2F0aW9uX3VwZGF0ZSIsInNlY3VyZW1zZ19tZXNzYWdlX2RlbGV0ZSIsImFjY2Vzc19jdXN0b21lcl9kZWxldGUiLCJhY2Nlc3NfYWdlbnRfY3JlYXRlIiwiYWNjZXNzX2FnZW50X3JlYWQiLCJhY2Nlc3NfdGVuYW50X3Byb3BlcnRpZXNfdXBkYXQiLCJhY2Nlc3NfdGVuYW50X3Byb3BlcnRpZXNfYmF0Y2giLCJhY2Nlc3NfYXR0YWNobWVudF9kZWxldGUiLCJlbWFpbF9vdXRnb2luZ19jcmVhdGUiLCJwcmVmZXJlbmNlc19kZXNrdG9wbG9jYWxlIiwiY2FzZV91cGRhdGUiLCJwcmVmZXJlbmNlc19jb250ZW50bG9jYWxlIl0sImV4cCI6MTcwMzE1NjkzNywiaWF0IjoxNzAzMTIwOTM3LCJpc3MiOiJodHRwczovL2VtMjAudmVyaW50LmxpdmU6NDQzL29pZGMtdG9rZW4tc2VydmljZS9kZWZhdWx0IiwicmVhbG0iOiIvZGVmYXVsdCIsInN1YiI6ImFwaWNsaWVudCJ9.WQdvTn6sLKbEakxdWaXRiIXD-RAca1ts-dW3sF1WoXLCuzBVm-Zq7yfCjZ2OhT4qQzECSlRHco1oaHf8j-Mo21qnvexQnXhYO98A0FRsvB0vAefD5WWUlkynGDkfgvKuG69e_5L-QJpetdH_pvIgNg5Mr_wrNiMLPs6XLyi4x8u1ZRpVgseSJyrCnOFzAT54D3sJUi_SrZTDtCKQv2N91uCY0l5mu3CPosDqgIU1qBux_ZCWeyUab0vI-Zu6QLaduMaCsYBweZY8r52RGEP1MXBFY_p3apGmp7WRumVy9_Q0KYVw6PpIyqyLRbD0zU0C_NdujALojg9-kB1Yq19ZlA", "1d", "/", undefined, @@ -56,20 +55,10 @@ onMounted(() => { fetchData(); }); -function setValueFromTPS( - reference: { value: string }, - param: string, - props: SessionIdentiferProps, -) { +function setValueFromTPS(reference: { value: string }, param: string) { if (param.startsWith("tps:")) { const tpsProperty = param.substring(4, param.length); - getTenantProperty(tpsProperty, props) - .then((value: unknown) => { - reference.value = value as string; - }) - .catch((err: Error) => { - errorMessage.value = `${err.message} for TPS property ${tpsProperty}`; - }); + reference.value = getTenantProperty(tpsProperty) as string; } else { reference.value = param; } @@ -79,9 +68,9 @@ function fetchData() { //clear errors errorMessage.value = ""; - setValueFromTPS(transferSummaryValue, props.transferSummary, props); - setValueFromTPS(integrationCardTitleValue, props.integrationCardTitle, props); - setValueFromTPS(integrationCardDocValue, props.integrationCardDoc, props); + setValueFromTPS(transferSummaryValue, props.transferSummary); + setValueFromTPS(integrationCardTitleValue, props.integrationCardTitle); + setValueFromTPS(integrationCardDocValue, props.integrationCardDoc); } diff --git a/vite.config.ts b/vite.config.ts index 6833d09..73f94bc 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -8,6 +8,14 @@ export default defineConfig(({ command }) => { if (command === "build") { return { plugins: [vue()], base: "/ca_vue_apps/dist" }; } else { - return { plugins: [eslintPlugin(), mkcert(), vue()] }; + return { + cors: { + origin: "*", + methods: "GET,HEAD,PUT,PATCH,POST,DELETE", + preflightContinue: false, + optionsSuccessStatus: 204, + }, + plugins: [eslintPlugin(), mkcert(), vue()], + }; } });