Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 20 additions & 28 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ const DEFAULT_API_VERSION = 1;
const DEFAULT_SERVER_VERSION = "2016.2.0";
import * as Atelier from "./atelier";
import { isfsConfig } from "../utils/FileProviderUtil";
import { Authorization, IServerSpec } from "@intersystems-community/intersystems-servermanager";

// Map of the authRequest promises for each username@host:port/pathPrefix target to avoid concurrency issues
const authRequestMap = new Map<string, Promise<any>>();

/** Map of `username@host:port/pathPrefix` to cookies */
const cookiesMap = new Map<string, string[]>();

interface ConnectionSettings {
export interface ConnectionSettings {
serverName: string;
active: boolean;
apiVersion: number;
Expand All @@ -37,8 +38,7 @@ interface ConnectionSettings {
superserverPort?: number;
pathPrefix: string;
ns: string;
username: string;
password: string;
auth: Authorization;
docker: boolean;
dockerService?: string;
}
Expand All @@ -59,15 +59,15 @@ export class AtelierAPI {
}

public get config(): ConnectionSettings {
const { serverName, active = false, https = false, pathPrefix = "", username } = this._config;
const { serverName, active = false, https = false, pathPrefix = "", auth } = this._config;
const ns = this.namespace || this._config.ns;
const wsKey = this.configName.toLowerCase();
const host = this.externalServer ? this._config.host : workspaceState.get(wsKey + ":host", this._config.host);
const port = this.externalServer ? this._config.port : workspaceState.get(wsKey + ":port", this._config.port);
const superserverPort = this.externalServer
? this._config.superserverPort
: workspaceState.get(wsKey + ":superserverPort", this._config.superserverPort);
const password = workspaceState.get(wsKey + ":password", this._config.password);
auth.resolve({ accessToken: workspaceState.get(wsKey + ":password", undefined) });
const apiVersion = workspaceState.get(wsKey + ":apiVersion", DEFAULT_API_VERSION);
const serverVersion = workspaceState.get(wsKey + ":serverVersion", DEFAULT_SERVER_VERSION);
const docker = workspaceState.get(wsKey + ":docker", false);
Expand All @@ -83,8 +83,7 @@ export class AtelierAPI {
superserverPort,
pathPrefix,
ns,
username,
password,
auth,
docker,
dockerService,
};
Expand Down Expand Up @@ -147,14 +146,12 @@ export class AtelierAPI {
* Manually set the connection spec for this object,
* where `connSpec` is the return value of `getResolvedConnectionSpec()`.
*/
public setConnSpec(serverName: string, connSpec: any): void {
public setConnSpec(serverName: string, connSpec: IServerSpec): void {
const {
webServer: { scheme, host, port, pathPrefix = "" },
username,
password,
auth,
} = connSpec;
this._config.username = username;
this._config.password = password;
this._config.auth = auth;
this._config.https = scheme == "https";
this._config.host = host;
this._config.port = port;
Expand Down Expand Up @@ -209,12 +206,12 @@ export class AtelierAPI {

/** Return the key for getting values from connection-specific Maps for this connection */
private mapKey(): string {
const { host, port, username } = this.config;
const { host, port, auth } = this.config;
let pathPrefix = this._config.pathPrefix || "";
if (pathPrefix.length && !pathPrefix.startsWith("/")) {
pathPrefix = "/" + pathPrefix;
}
return `${username}@${host}:${port}${pathPrefix}`;
return `${auth.username}@${host}:${port}${pathPrefix}`;
}

private setConnection(workspaceFolderName: string, namespace?: string): void {
Expand All @@ -239,8 +236,7 @@ export class AtelierAPI {
if (serverName !== "") {
const {
webServer: { scheme, host, port, pathPrefix = "" },
username,
password,
auth,
superServer,
} = getResolvedConnectionSpec(serverName, config("intersystems.servers", workspaceFolderName).get(serverName));
this._config = {
Expand All @@ -253,8 +249,7 @@ export class AtelierAPI {
host,
port,
superserverPort: superServer?.port,
username,
password,
auth,
pathPrefix,
docker: false,
};
Expand All @@ -264,8 +259,7 @@ export class AtelierAPI {
if (resolvedSpec) {
const {
webServer: { scheme, host, port, pathPrefix = "" },
username,
password,
auth,
superServer,
} = resolvedSpec;
this._config = {
Expand All @@ -278,8 +272,7 @@ export class AtelierAPI {
host,
port,
superserverPort: superServer?.port,
username,
password,
auth,
pathPrefix,
docker: true,
dockerService: conn["docker-compose"].service,
Expand Down Expand Up @@ -316,7 +309,7 @@ export class AtelierAPI {
headers?: any,
options?: any
): Promise<any> {
const { active, apiVersion, host, port, username, password, https } = this.config;
const { active, apiVersion, host, port, https } = this.config;
if (!active || !port || !host) {
return Promise.reject();
}
Expand Down Expand Up @@ -369,12 +362,11 @@ export class AtelierAPI {
let auth: Promise<any>;
let authRequest = authRequestMap.get(mapKey);
if (cookies.length || (method === "HEAD" && !originalPath)) {
auth = Promise.resolve(cookies);

// Only send basic authorization if username and password specified (including blank, for unauthenticated access)
if (typeof username === "string" && typeof password === "string") {
headers["Authorization"] = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
if (this.config.auth.resolved()) {
headers["Authorization"] = this.config.auth.httpAuthorizationHeader;
}
auth = Promise.resolve(cookies);
} else if (!cookies.length) {
if (!authRequest) {
// Recursion point
Expand Down Expand Up @@ -449,7 +441,7 @@ export class AtelierAPI {
if (this.wsOrFile && !checkingConnection) {
setTimeout(() => {
checkConnection(
password ? true : false,
this.config.auth.resolved(),
typeof this.wsOrFile === "object" ? this.wsOrFile : undefined,
true
);
Expand Down
4 changes: 2 additions & 2 deletions src/commands/connectFolderToServerNamespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
serverManagerApi,
resolveUsernameAndPassword,
} from "../extension";
import { handleError, isUnauthenticated, notIsfs, displayableUri } from "../utils";
import { handleError, notIsfs, displayableUri } from "../utils";

interface ConnSettings {
server: string;
Expand Down Expand Up @@ -80,7 +80,7 @@ export async function connectFolderToServerNamespace(): Promise<void> {
.serverInfo(false)
.then((data) => data.result.content.namespaces)
.catch(async (error) => {
if (error?.statusCode == 401 && isUnauthenticated(api.config.username)) {
if (error?.statusCode == 401 && !api.config.auth.resolved()) {
// Attempt to resolve username and password and try again
const newSpec = await resolveUsernameAndPassword(api.config.serverName, connSpec);
if (newSpec) {
Expand Down
15 changes: 3 additions & 12 deletions src/commands/restDebugPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,8 @@ export class RESTDebugPanel {
form.onchange = () => sendData(false);
button.onclick = () => sendData(true);
// Bubble change events up to the form
bodyContent.onchange = headersText.onchange =
paramsText.onchange = path.onchange =
bodyContent.onchange = headersText.onchange =
paramsText.onchange = path.onchange =
() => form.dispatchEvent(new Event("change"));
</script>
</body>
Expand Down Expand Up @@ -548,16 +548,7 @@ export class RESTDebugPanel {
.trim();
}
});
if (
headers["authorization"] == undefined &&
typeof api.config.username === "string" &&
typeof api.config.password === "string"
) {
// Use the server connection's auth if the user didn't specify any
headers["authorization"] = `Basic ${Buffer.from(`${api.config.username}:${api.config.password}`).toString(
"base64"
)}`;
}
headers["authorization"] = headers["authorization"] ?? (api.config.auth.httpAuthorizationHeader || "");
const hasBody =
typeof message.bodyContent == "string" && message.bodyContent != "" && message.bodyType != "No Body";
if (hasBody) {
Expand Down
6 changes: 3 additions & 3 deletions src/commands/serverActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type ServerAction = { detail: string; id: string; label: string; rawLink?: strin
export async function serverActions(): Promise<void> {
const { apiTarget, configName: workspaceFolder } = connectionTarget();
const api = new AtelierAPI(apiTarget);
const { active, host = "", ns = "", https, port = 0, pathPrefix, username, docker } = api.config;
const { active, host = "", ns = "", https, port = 0, pathPrefix, auth, docker } = api.config;
const explorerCount = (await explorerProvider.getChildren()).length;
if (!explorerCount && (!docker || host === "")) {
await vscode.commands.executeCommand("ObjectScriptExplorer.focus");
Expand Down Expand Up @@ -152,7 +152,7 @@ export async function serverActions(): Promise<void> {
.replace("${serverAuth}", "")
.replace("${ns}", nsEncoded)
.replace("${namespace}", ns == "%SYS" ? "sys" : nsEncoded.toLowerCase())
.replace("${username}", username)
.replace("${username}", auth.username)
.replace("${classname}", classname)
.replace("${classnameEncoded}", classnameEncoded)
.replace("${project}", project);
Expand Down Expand Up @@ -248,7 +248,7 @@ export async function serverActions(): Promise<void> {
if (addin) {
sendStudioAddinTelemetryEvent(addin.label);
let params = `Namespace=${nsEncoded}`;
params += `&User=${encodeURIComponent(username)}`;
params += `&User=${encodeURIComponent(auth.username)}`;
if (project != "") {
params += `&Project=${encodeURIComponent(project)}`;
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/webSocketTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ class WebSocketTerminal implements vscode.Pseudoterminal {
this._hideCursorWrite("\x1b]633;P;HasRichCommandDetection=True\x07");
// Print the opening message
this._hideCursorWrite(
`\x1b[32mConnected to \x1b[0m\x1b[4m${api.config.host}:${api.config.port}${api.config.pathPrefix}\x1b[0m\x1b[32m as \x1b[0m\x1b[3m${api.config.username}\x1b[0m\r\n`
`\x1b[32mConnected to \x1b[0m\x1b[4m${api.config.host}:${api.config.port}${api.config.pathPrefix}\x1b[0m\x1b[32m as \x1b[0m\x1b[3m${api.config.auth.username}\x1b[0m\r\n`
);
// Add event handlers to the socket
this._socket
Expand Down
Loading
Loading