From 27c37639b6d40eda8bdb35863249f5f3705ab2f0 Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Wed, 29 May 2024 08:32:28 -0400 Subject: [PATCH 1/4] Remove SMP Simple Browser button --- package.json | 18 ++------------ src/api/getPortalUriWithToken.ts | 42 +++----------------------------- src/extension.ts | 20 +++------------ src/ui/serverManagerView.ts | 4 --- 4 files changed, 9 insertions(+), 75 deletions(-) diff --git a/package.json b/package.json index 03252f6..9e93065 100644 --- a/package.json +++ b/package.json @@ -272,17 +272,12 @@ }, { "command": "intersystems-community.servermanager.openPortalExternal", - "title": "Open Management Portal in External Browser", + "title": "Open Management Portal", "icon": "$(link-external)" }, - { - "command": "intersystems-community.servermanager.openPortalTab", - "title": "Open Management Portal in Tab", - "icon": "$(tools)" - }, { "command": "intersystems-community.servermanager.openPortalExplorerExternal", - "title": "Open Management Portal Here in External Browser", + "title": "Open Management Portal Here", "icon": "$(link-external)" }, { @@ -428,10 +423,6 @@ "command": "intersystems-community.servermanager.openPortalExternal", "when": "false" }, - { - "command": "intersystems-community.servermanager.openPortalTab", - "when": "false" - }, { "command": "intersystems-community.servermanager.openPortalExplorerExternal", "when": "false" @@ -576,11 +567,6 @@ "when": "view == intersystems-community_servermanager && viewItem =~ /webapp$/", "group": "inline@20" }, - { - "command": "intersystems-community.servermanager.openPortalTab", - "when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./", - "group": "inline@80" - }, { "command": "intersystems-community.servermanager.openPortalExternal", "when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./", diff --git a/src/api/getPortalUriWithToken.ts b/src/api/getPortalUriWithToken.ts index 297d77e..14e1780 100644 --- a/src/api/getPortalUriWithToken.ts +++ b/src/api/getPortalUriWithToken.ts @@ -4,17 +4,9 @@ import { IServerSpec } from "@intersystems-community/intersystems-servermanager" import { extensionId } from "../extension"; import { makeRESTRequest } from "../makeRESTRequest"; -export enum BrowserTarget { - SIMPLE = 0, - EXTERNAL = 1, -} - -const allTokens = [new Map(), new Map()]; - -const simpleBrowserCompatible = new Map(); +const allTokens = new Map(); export async function getPortalUriWithToken( - target: BrowserTarget, name: string, page = "/csp/sys/UtilHome.csp", namespace = "%SYS", @@ -28,7 +20,7 @@ export async function getPortalUriWithToken( if (typeof spec !== "undefined") { // Retrieve previously cached token - let token = allTokens[target].get(name) || ""; + let token = allTokens.get(name) || ""; // Revalidate and extend existing token, or obtain a new one const response = await makeRESTRequest( @@ -41,36 +33,10 @@ export async function getPortalUriWithToken( if (!response) { // User will have to enter credentials token = ""; - allTokens[target].delete(name); + allTokens.delete(name); } else { token = response.data?.result?.content[0]?.token || ""; - allTokens[target].set(name, token); - } - - if (target === BrowserTarget.SIMPLE && !simpleBrowserCompatible.has(name)) { - // Check that the portal webapps have all been altered so they don't require session cookie support, which Simple Browser cannot provide - const response = await makeRESTRequest( - "POST", - spec, - { apiVersion: 1, namespace: "%SYS", path: "/action/query" }, - { query: "SELECT Name FROM Security.Applications WHERE {fn CONCAT(Name, '/')} %STARTSWITH '/csp/sys/' AND UseCookies = 2" }, - ); - if (response) { - const appsRequiringCookie = (response.data?.result?.content as any[]).map((row) => { - return row.Name as string; - }); - if (appsRequiringCookie.length > 0) { - await vscode.window.showWarningMessage(`Portal web apps cannot be used in the Simple Browser tab if their 'UseCookies' property is set to 'Always' (the default). To resolve this, use Portal's security section to change it to 'Autodetect' in these apps: ${appsRequiringCookie.join(", ")}`, { modal: true }); - return; - } - else { - simpleBrowserCompatible.set(name, true); - } - } - else { - vscode.window.showWarningMessage(`Unable to check the Portal web apps for compatibility with Simple Browser.`); - simpleBrowserCompatible.set(name, true); - } + allTokens.set(name, token); } const webServer = spec.webServer; diff --git a/src/extension.ts b/src/extension.ts index ab51fa1..3d18bc2 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,7 +3,7 @@ import * as vscode from "vscode"; import { IServerName, IServerSpec } from "@intersystems-community/intersystems-servermanager"; import { addServer } from "./api/addServer"; -import { BrowserTarget, getPortalUriWithToken } from "./api/getPortalUriWithToken"; +import { getPortalUriWithToken } from "./api/getPortalUriWithToken"; import { getServerNames } from "./api/getServerNames"; import { getServerSpec } from "./api/getServerSpec"; import { getServerSummary } from "./api/getServerSummary"; @@ -97,7 +97,7 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand(`${extensionId}.openPortalExternal`, (server?: ServerTreeItem) => { if (server?.contextValue?.match(/\.server\./) && server.name) { - getPortalUriWithToken(BrowserTarget.EXTERNAL, server.name).then((uriWithToken) => { + getPortalUriWithToken(server.name).then((uriWithToken) => { if (uriWithToken) { vscode.env.openExternal(uriWithToken); } @@ -105,20 +105,6 @@ export function activate(context: vscode.ExtensionContext) { } }), ); - context.subscriptions.push( - vscode.commands.registerCommand(`${extensionId}.openPortalTab`, (server?: ServerTreeItem) => { - if (server?.contextValue?.match(/\.server\./) && server.name) { - getPortalUriWithToken(BrowserTarget.SIMPLE, server.name).then((uriWithToken) => { - if (uriWithToken) { - // - // It is essential to pass skipEncoding=true when converting the uri to a string, - // otherwise the querystring's & and = get encoded. - vscode.commands.executeCommand("simpleBrowser.show", uriWithToken.toString(true)); - } - }); - } - }), - ); context.subscriptions.push( vscode.commands.registerCommand(`${extensionId}.openPortalExplorerExternal`, (namespaceTreeItem?: NamespaceTreeItem) => { if (namespaceTreeItem) { @@ -126,7 +112,7 @@ export function activate(context: vscode.ExtensionContext) { if (pathParts && pathParts.length === 4) { const serverName = pathParts[1]; const namespace = pathParts[3]; - getPortalUriWithToken(BrowserTarget.EXTERNAL, serverName, "/csp/sys/exp/%25CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => { + getPortalUriWithToken(serverName, "/csp/sys/exp/%25CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => { if (uriWithToken) { vscode.env.openExternal(uriWithToken); } diff --git a/src/ui/serverManagerView.ts b/src/ui/serverManagerView.ts index a74e040..a9c2301 100644 --- a/src/ui/serverManagerView.ts +++ b/src/ui/serverManagerView.ts @@ -359,10 +359,6 @@ export class ServerTreeItem extends SMTreeItem { "server-environment", color ? new vscode.ThemeColor("charts." + color) : undefined, ); - - // TODO If single click on server item should open Portal tab - // this.command = {command: 'intersystems-community.servermanager.openPortalTab', - // title: 'Open Management Portal in Simple Browser Tab', arguments: [this]}; } } From 634257c52135eabc8a4bfc9a948da4f78620dcfa Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Wed, 29 May 2024 12:39:36 -0400 Subject: [PATCH 2/4] Revert "Remove SMP Simple Browser button" This reverts commit 27c37639b6d40eda8bdb35863249f5f3705ab2f0. --- package.json | 18 ++++++++++++-- src/api/getPortalUriWithToken.ts | 42 +++++++++++++++++++++++++++++--- src/extension.ts | 20 ++++++++++++--- src/ui/serverManagerView.ts | 4 +++ 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 9e93065..03252f6 100644 --- a/package.json +++ b/package.json @@ -272,12 +272,17 @@ }, { "command": "intersystems-community.servermanager.openPortalExternal", - "title": "Open Management Portal", + "title": "Open Management Portal in External Browser", "icon": "$(link-external)" }, + { + "command": "intersystems-community.servermanager.openPortalTab", + "title": "Open Management Portal in Tab", + "icon": "$(tools)" + }, { "command": "intersystems-community.servermanager.openPortalExplorerExternal", - "title": "Open Management Portal Here", + "title": "Open Management Portal Here in External Browser", "icon": "$(link-external)" }, { @@ -423,6 +428,10 @@ "command": "intersystems-community.servermanager.openPortalExternal", "when": "false" }, + { + "command": "intersystems-community.servermanager.openPortalTab", + "when": "false" + }, { "command": "intersystems-community.servermanager.openPortalExplorerExternal", "when": "false" @@ -567,6 +576,11 @@ "when": "view == intersystems-community_servermanager && viewItem =~ /webapp$/", "group": "inline@20" }, + { + "command": "intersystems-community.servermanager.openPortalTab", + "when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./", + "group": "inline@80" + }, { "command": "intersystems-community.servermanager.openPortalExternal", "when": "view == intersystems-community_servermanager && viewItem =~ /\\.server\\./", diff --git a/src/api/getPortalUriWithToken.ts b/src/api/getPortalUriWithToken.ts index 14e1780..297d77e 100644 --- a/src/api/getPortalUriWithToken.ts +++ b/src/api/getPortalUriWithToken.ts @@ -4,9 +4,17 @@ import { IServerSpec } from "@intersystems-community/intersystems-servermanager" import { extensionId } from "../extension"; import { makeRESTRequest } from "../makeRESTRequest"; -const allTokens = new Map(); +export enum BrowserTarget { + SIMPLE = 0, + EXTERNAL = 1, +} + +const allTokens = [new Map(), new Map()]; + +const simpleBrowserCompatible = new Map(); export async function getPortalUriWithToken( + target: BrowserTarget, name: string, page = "/csp/sys/UtilHome.csp", namespace = "%SYS", @@ -20,7 +28,7 @@ export async function getPortalUriWithToken( if (typeof spec !== "undefined") { // Retrieve previously cached token - let token = allTokens.get(name) || ""; + let token = allTokens[target].get(name) || ""; // Revalidate and extend existing token, or obtain a new one const response = await makeRESTRequest( @@ -33,10 +41,36 @@ export async function getPortalUriWithToken( if (!response) { // User will have to enter credentials token = ""; - allTokens.delete(name); + allTokens[target].delete(name); } else { token = response.data?.result?.content[0]?.token || ""; - allTokens.set(name, token); + allTokens[target].set(name, token); + } + + if (target === BrowserTarget.SIMPLE && !simpleBrowserCompatible.has(name)) { + // Check that the portal webapps have all been altered so they don't require session cookie support, which Simple Browser cannot provide + const response = await makeRESTRequest( + "POST", + spec, + { apiVersion: 1, namespace: "%SYS", path: "/action/query" }, + { query: "SELECT Name FROM Security.Applications WHERE {fn CONCAT(Name, '/')} %STARTSWITH '/csp/sys/' AND UseCookies = 2" }, + ); + if (response) { + const appsRequiringCookie = (response.data?.result?.content as any[]).map((row) => { + return row.Name as string; + }); + if (appsRequiringCookie.length > 0) { + await vscode.window.showWarningMessage(`Portal web apps cannot be used in the Simple Browser tab if their 'UseCookies' property is set to 'Always' (the default). To resolve this, use Portal's security section to change it to 'Autodetect' in these apps: ${appsRequiringCookie.join(", ")}`, { modal: true }); + return; + } + else { + simpleBrowserCompatible.set(name, true); + } + } + else { + vscode.window.showWarningMessage(`Unable to check the Portal web apps for compatibility with Simple Browser.`); + simpleBrowserCompatible.set(name, true); + } } const webServer = spec.webServer; diff --git a/src/extension.ts b/src/extension.ts index 3d18bc2..ab51fa1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,7 +3,7 @@ import * as vscode from "vscode"; import { IServerName, IServerSpec } from "@intersystems-community/intersystems-servermanager"; import { addServer } from "./api/addServer"; -import { getPortalUriWithToken } from "./api/getPortalUriWithToken"; +import { BrowserTarget, getPortalUriWithToken } from "./api/getPortalUriWithToken"; import { getServerNames } from "./api/getServerNames"; import { getServerSpec } from "./api/getServerSpec"; import { getServerSummary } from "./api/getServerSummary"; @@ -97,7 +97,7 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push( vscode.commands.registerCommand(`${extensionId}.openPortalExternal`, (server?: ServerTreeItem) => { if (server?.contextValue?.match(/\.server\./) && server.name) { - getPortalUriWithToken(server.name).then((uriWithToken) => { + getPortalUriWithToken(BrowserTarget.EXTERNAL, server.name).then((uriWithToken) => { if (uriWithToken) { vscode.env.openExternal(uriWithToken); } @@ -105,6 +105,20 @@ export function activate(context: vscode.ExtensionContext) { } }), ); + context.subscriptions.push( + vscode.commands.registerCommand(`${extensionId}.openPortalTab`, (server?: ServerTreeItem) => { + if (server?.contextValue?.match(/\.server\./) && server.name) { + getPortalUriWithToken(BrowserTarget.SIMPLE, server.name).then((uriWithToken) => { + if (uriWithToken) { + // + // It is essential to pass skipEncoding=true when converting the uri to a string, + // otherwise the querystring's & and = get encoded. + vscode.commands.executeCommand("simpleBrowser.show", uriWithToken.toString(true)); + } + }); + } + }), + ); context.subscriptions.push( vscode.commands.registerCommand(`${extensionId}.openPortalExplorerExternal`, (namespaceTreeItem?: NamespaceTreeItem) => { if (namespaceTreeItem) { @@ -112,7 +126,7 @@ export function activate(context: vscode.ExtensionContext) { if (pathParts && pathParts.length === 4) { const serverName = pathParts[1]; const namespace = pathParts[3]; - getPortalUriWithToken(serverName, "/csp/sys/exp/%25CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => { + getPortalUriWithToken(BrowserTarget.EXTERNAL, serverName, "/csp/sys/exp/%25CSP.UI.Portal.ClassList.zen", namespace).then((uriWithToken) => { if (uriWithToken) { vscode.env.openExternal(uriWithToken); } diff --git a/src/ui/serverManagerView.ts b/src/ui/serverManagerView.ts index a9c2301..a74e040 100644 --- a/src/ui/serverManagerView.ts +++ b/src/ui/serverManagerView.ts @@ -359,6 +359,10 @@ export class ServerTreeItem extends SMTreeItem { "server-environment", color ? new vscode.ThemeColor("charts." + color) : undefined, ); + + // TODO If single click on server item should open Portal tab + // this.command = {command: 'intersystems-community.servermanager.openPortalTab', + // title: 'Open Management Portal in Simple Browser Tab', arguments: [this]}; } } From c92d52d3cdf7af018a659a2ebd48f7d7b07a695f Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Wed, 29 May 2024 13:01:50 -0400 Subject: [PATCH 3/4] Update getPortalUriWithToken.ts --- src/api/getPortalUriWithToken.ts | 65 +++++++++++++++++++------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/src/api/getPortalUriWithToken.ts b/src/api/getPortalUriWithToken.ts index 297d77e..a7df51c 100644 --- a/src/api/getPortalUriWithToken.ts +++ b/src/api/getPortalUriWithToken.ts @@ -27,50 +27,63 @@ export async function getPortalUriWithToken( const spec: IServerSpec | undefined = await myApi.getServerSpec(name, scope); if (typeof spec !== "undefined") { - // Retrieve previously cached token - let token = allTokens[target].get(name) || ""; - - // Revalidate and extend existing token, or obtain a new one - const response = await makeRESTRequest( - "POST", - spec, - { apiVersion: 1, namespace, path: "/action/query" }, - { query: "select %Atelier_v1_Utils.General_GetCSPToken(?, ?) token", parameters: [page, token] }, - ); - - if (!response) { - // User will have to enter credentials - token = ""; - allTokens[target].delete(name); - } else { - token = response.data?.result?.content[0]?.token || ""; - allTokens[target].set(name, token); - } - if (target === BrowserTarget.SIMPLE && !simpleBrowserCompatible.has(name)) { // Check that the portal webapps have all been altered so they don't require session cookie support, which Simple Browser cannot provide const response = await makeRESTRequest( "POST", spec, { apiVersion: 1, namespace: "%SYS", path: "/action/query" }, - { query: "SELECT Name FROM Security.Applications WHERE {fn CONCAT(Name, '/')} %STARTSWITH '/csp/sys/' AND UseCookies = 2" }, + { + query: + "SELECT Name FROM Security.Applications WHERE {fn CONCAT(Name, '/')} %STARTSWITH '/csp/sys/' AND UseCookies = 2 " + + "UNION SELECT $PIECE($PIECE($PIECE($ZVERSION,') ',2),' '),'.') AS Name" + }, ); if (response) { const appsRequiringCookie = (response.data?.result?.content as any[]).map((row) => { return row.Name as string; }); - if (appsRequiringCookie.length > 0) { - await vscode.window.showWarningMessage(`Portal web apps cannot be used in the Simple Browser tab if their 'UseCookies' property is set to 'Always' (the default). To resolve this, use Portal's security section to change it to 'Autodetect' in these apps: ${appsRequiringCookie.join(", ")}`, { modal: true }); - return; + if (appsRequiringCookie.length && parseInt(appsRequiringCookie[appsRequiringCookie.length - 1], 10) >= 2024) { + // SMP in 2024.1+ can't be embedded in a cross-origin iframe + vscode.window.showWarningMessage(`The Portal cannot be opened in the Simple Browser for IRIS versions 2024.1+.`, "Dismiss"); + simpleBrowserCompatible.set(name, false); + } + else if (appsRequiringCookie.length > 1) { + vscode.window.showWarningMessage(`Portal web apps cannot be used in the Simple Browser tab if their 'UseCookies' property is set to 'Always' (the default). To resolve this, use Portal's security section to change it to 'Autodetect' in these apps: ${appsRequiringCookie.join(", ")}`, { modal: true }); } else { simpleBrowserCompatible.set(name, true); } } else { - vscode.window.showWarningMessage(`Unable to check the Portal web apps for compatibility with Simple Browser.`); - simpleBrowserCompatible.set(name, true); + vscode.window.showWarningMessage(`Unable to check the Portal web apps for compatibility with Simple Browser.`, "Dismiss"); } + if (!simpleBrowserCompatible.get(name)) return; + } + + if (target === BrowserTarget.SIMPLE && simpleBrowserCompatible.has(name) && !simpleBrowserCompatible.get(name)) { + vscode.window.showWarningMessage(`The Portal cannot be opened in the Simple Browser for IRIS versions 2024.1+.`, "Dismiss"); + return; + } + + // Retrieve previously cached token + let token = allTokens[target].get(name) || ""; + + // Revalidate and extend existing token, or obtain a new one + const response = await makeRESTRequest( + "POST", + spec, + { apiVersion: 1, namespace, path: "/action/query" }, + { query: "select %Atelier_v1_Utils.General_GetCSPToken(?, ?) token", parameters: [page, token] }, + ); + + if (!response) { + // User will have to enter credentials + token = ""; + allTokens[target].delete(name); + } else { + token = response.data?.result?.content[0]?.token || ""; + allTokens[target].set(name, token); } const webServer = spec.webServer; From 4cd4c55c6beef04492a17275584313b2db2f4f20 Mon Sep 17 00:00:00 2001 From: Brett Saviano Date: Wed, 29 May 2024 13:34:13 -0400 Subject: [PATCH 4/4] Update getPortalUriWithToken.ts --- src/api/getPortalUriWithToken.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/getPortalUriWithToken.ts b/src/api/getPortalUriWithToken.ts index a7df51c..904a9ea 100644 --- a/src/api/getPortalUriWithToken.ts +++ b/src/api/getPortalUriWithToken.ts @@ -49,7 +49,7 @@ export async function getPortalUriWithToken( simpleBrowserCompatible.set(name, false); } else if (appsRequiringCookie.length > 1) { - vscode.window.showWarningMessage(`Portal web apps cannot be used in the Simple Browser tab if their 'UseCookies' property is set to 'Always' (the default). To resolve this, use Portal's security section to change it to 'Autodetect' in these apps: ${appsRequiringCookie.join(", ")}`, { modal: true }); + vscode.window.showWarningMessage(`Portal web apps cannot be used in the Simple Browser tab if their 'UseCookies' property is set to 'Always' (the default). To resolve this, use Portal's security section to change it to 'Autodetect' in these apps: ${appsRequiringCookie.slice(0, -1).join(", ")}`, { modal: true }); } else { simpleBrowserCompatible.set(name, true);