mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-05-03 23:13:55 +01:00
mongo is working
This commit is contained in:
parent
323276beff
commit
ce08ce05f2
20
package-lock.json
generated
20
package-lock.json
generated
@ -50,6 +50,7 @@
|
|||||||
"@types/mkdirp": "1.0.1",
|
"@types/mkdirp": "1.0.1",
|
||||||
"@types/node-fetch": "2.5.7",
|
"@types/node-fetch": "2.5.7",
|
||||||
"@xmldom/xmldom": "0.7.13",
|
"@xmldom/xmldom": "0.7.13",
|
||||||
|
"@xterm/xterm": "5.5.0",
|
||||||
"allotment": "1.20.2",
|
"allotment": "1.20.2",
|
||||||
"applicationinsights": "1.8.0",
|
"applicationinsights": "1.8.0",
|
||||||
"bootstrap": "3.4.1",
|
"bootstrap": "3.4.1",
|
||||||
@ -113,7 +114,6 @@
|
|||||||
"tinykeys": "2.1.0",
|
"tinykeys": "2.1.0",
|
||||||
"underscore": "1.12.1",
|
"underscore": "1.12.1",
|
||||||
"utility-types": "3.10.0",
|
"utility-types": "3.10.0",
|
||||||
"xterm-for-react": "1.0.4",
|
|
||||||
"zustand": "3.5.0"
|
"zustand": "3.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -13238,6 +13238,11 @@
|
|||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@xterm/xterm": {
|
||||||
|
"version": "5.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||||
|
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
||||||
|
},
|
||||||
"node_modules/@xtuc/ieee754": {
|
"node_modules/@xtuc/ieee754": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
@ -36550,19 +36555,6 @@
|
|||||||
"xterm": "^4.0.0"
|
"xterm": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/xterm-for-react": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/xterm-for-react/-/xterm-for-react-1.0.4.tgz",
|
|
||||||
"integrity": "sha512-DCkLR9ZXeW907YyyaCTk/3Ol34VRHfCnf3MAPOkj3dUNA85sDqHvTXN8efw4g7bx7gWdJQRsEpGt2tJOXKG3EQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"prop-types": "^15.7.2",
|
|
||||||
"xterm": "^4.5.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^16.0.0",
|
|
||||||
"react-dom": "^16.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
"@types/mkdirp": "1.0.1",
|
"@types/mkdirp": "1.0.1",
|
||||||
"@types/node-fetch": "2.5.7",
|
"@types/node-fetch": "2.5.7",
|
||||||
"@xmldom/xmldom": "0.7.13",
|
"@xmldom/xmldom": "0.7.13",
|
||||||
"xterm-for-react":"1.0.4",
|
"@xterm/xterm": "5.5.0",
|
||||||
"allotment": "1.20.2",
|
"allotment": "1.20.2",
|
||||||
"applicationinsights": "1.8.0",
|
"applicationinsights": "1.8.0",
|
||||||
"bootstrap": "3.4.1",
|
"bootstrap": "3.4.1",
|
||||||
|
@ -1,28 +1,55 @@
|
|||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { XTerm } from "xterm-for-react";
|
import { Terminal } from "xterm";
|
||||||
import { useAADAuth } from "../../hooks/useAADAuth";
|
import "xterm/css/xterm.css";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
|
import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
|
||||||
|
|
||||||
const XTermComponent: React.FC = () => {
|
const XTermComponent: React.FC = () => {
|
||||||
const xtermRef = useRef(null);
|
const terminalRef = useRef(null); // Reference for terminal container
|
||||||
|
const xtermRef = useRef(null); // Reference for XTerm instance
|
||||||
|
const socketRef = useRef(null); // Reference for WebSocket
|
||||||
const intervalsToClearRef = useRef<NodeJS.Timer[]>([]);
|
const intervalsToClearRef = useRef<NodeJS.Timer[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (xtermRef.current) {
|
// Initialize XTerm instance
|
||||||
xtermRef.current.terminal.writeln("Hello, World!");
|
const term = new Terminal({
|
||||||
|
cursorBlink: true,
|
||||||
|
fontSize: 14,
|
||||||
|
theme: { background: "#1d1f21", foreground: "#c5c8c6" },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Attach terminal to the DOM
|
||||||
|
if (terminalRef.current) {
|
||||||
|
term.open(terminalRef.current);
|
||||||
|
xtermRef.current = term;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
term.writeln("Hello, World!");
|
||||||
|
|
||||||
const authorizationHeader = getAuthorizationHeader()
|
const authorizationHeader = getAuthorizationHeader()
|
||||||
startCloudShellterminal(xtermRef.current.terminal, intervalsToClearRef, authorizationHeader.token);
|
socketRef.current = startCloudShellterminal(term, intervalsToClearRef, authorizationHeader.token);
|
||||||
|
|
||||||
|
term.onData((data) => {
|
||||||
|
if (socketRef.current && socketRef.current.readyState === WebSocket.OPEN) {
|
||||||
|
socketRef.current.send(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cleanup function to close WebSocket and dispose terminal
|
||||||
|
return () => {
|
||||||
|
if (socketRef.current) {
|
||||||
|
socketRef.current.close(); // Close WebSocket connection
|
||||||
|
}
|
||||||
|
term.dispose(); // Clean up XTerm instance
|
||||||
|
};
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <XTerm ref={xtermRef} />;
|
return <div ref={terminalRef} style={{ width: "100%", height: "500px" }} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const startCloudShellterminal = async (xterminal: any, intervalsToClearRef: any, authorizationToken: any) => {
|
const startCloudShellterminal = async (xterminal: Terminal, intervalsToClearRef: any, authorizationToken: any) => {
|
||||||
|
|
||||||
// const allowedParentFrameAuthorities = ["localhost:1234", "localhost:3000", "portal.azure.com", "portal.azure.us", "rc.portal.azure.com", "ms.portal.azure.com", "canary.portal.azure.com", "canary-ms.portal.azure.com", "docs.microsoft.com", "review.docs.microsoft.com", "ppe.docs.microsoft.com", "ux.console.azure.us", "admin-local.teams.microsoft.net", "admin-ignite.microsoft.com", "wusportalprv.office.com", "portal-sdf.office.com", "ncuportalprv.office.com", "admin.microsoft.com", "portal.microsoft.com", "portal.office.com", "admin.microsoft365.com", "admin-sdf.exchange.microsoft.com", "admin.exchange.microsoft.com", "cloudconsole-ux-prod-usnatwest.appservice.eaglex.ic.gov", "cloudconsole-ux-prod-usnateast.appservice.eaglex.ic.gov", "portal.azure.eaglex.ic.gov", "cloudconsole-ux-prod-ussecwest.appservice.microsoft.scloud", "cloudconsole-ux-prod-usseceast.appservice.microsoft.scloud", "portal.azure.microsoft.scloud", "admin-local.teams.microsoft.net", "admin-dev.teams.microsoft.net", "admin-int.teams.microsoft.net", "admin.teams.microsoft.com", "preview.portal.azure.com", "learn.microsoft.com", "review.learn.microsoft.com", "ppe.learn.microsoft.com", "dev.learn.microsoft.com"];
|
// const allowedParentFrameAuthorities = ["localhost:1234", "localhost:3000", "portal.azure.com", "portal.azure.us", "rc.portal.azure.com", "ms.portal.azure.com", "canary.portal.azure.com", "canary-ms.portal.azure.com", "docs.microsoft.com", "review.docs.microsoft.com", "ppe.docs.microsoft.com", "ux.console.azure.us", "admin-local.teams.microsoft.net", "admin-ignite.microsoft.com", "wusportalprv.office.com", "portal-sdf.office.com", "ncuportalprv.office.com", "admin.microsoft.com", "portal.microsoft.com", "portal.office.com", "admin.microsoft365.com", "admin-sdf.exchange.microsoft.com", "admin.exchange.microsoft.com", "cloudconsole-ux-prod-usnatwest.appservice.eaglex.ic.gov", "cloudconsole-ux-prod-usnateast.appservice.eaglex.ic.gov", "portal.azure.eaglex.ic.gov", "cloudconsole-ux-prod-ussecwest.appservice.microsoft.scloud", "cloudconsole-ux-prod-usseceast.appservice.microsoft.scloud", "portal.azure.microsoft.scloud", "admin-local.teams.microsoft.net", "admin-dev.teams.microsoft.net", "admin-int.teams.microsoft.net", "admin.teams.microsoft.com", "preview.portal.azure.com", "learn.microsoft.com", "review.learn.microsoft.com", "ppe.learn.microsoft.com", "dev.learn.microsoft.com"];
|
||||||
// const trustedParentOrigin = getTrustedParentOrigin();
|
// const trustedParentOrigin = getTrustedParentOrigin();
|
||||||
@ -59,28 +86,33 @@ const startCloudShellterminal = async (xterminal: any, intervalsToClearRef: any,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const region = await getUserRegion(authorizationToken, userContext.subscriptionId).then((res) => {
|
const region = await getUserRegion(authorizationToken, userContext.subscriptionId).then((res) => {
|
||||||
const reqId = (res.headers as any).get("x-ms-routing-request-id");
|
// const reqId = (res.headers as any).get("x-ms-routing-request-id");
|
||||||
const location = reqId?.split(":")?.[0]?.toLowerCase() ?? "";
|
// const location = reqId?.split(":")?.[0]?.toLowerCase() ?? "";
|
||||||
const validRegions = new Set(["westus", "southcentralus", "eastus", "northeurope", "westeurope", "centralindia", "southeastasia", "westcentralus", "eastus2euap", "centraluseuap"]);
|
// const validRegions = new Set(["westus", "southcentralus", "eastus", "northeurope", "westeurope", "centralindia", "southeastasia", "westcentralus", "eastus2euap", "centraluseuap"]);
|
||||||
if (validRegions.has(location.toLowerCase())) {
|
// if (validRegions.has(location.toLowerCase())) {
|
||||||
return location;
|
// return location;
|
||||||
}
|
// }
|
||||||
if (location === "centralus") {
|
// if (location === "centralus") {
|
||||||
return "centraluseuap";
|
// return "centraluseuap";
|
||||||
}
|
// }
|
||||||
if (location === "eastus2") {
|
// if (location === "eastus2") {
|
||||||
return "eastus2euap";
|
// return "eastus2euap";
|
||||||
}
|
// }
|
||||||
return "westus";
|
// return "westus";
|
||||||
}).catch((err) => {
|
// }).catch((err) => {
|
||||||
xterminal.writeln('');
|
// xterminal.writeln('');
|
||||||
xterminal.writeln('Unable to get user region.');
|
// xterminal.writeln('Unable to get user region.');
|
||||||
|
// return "westus";
|
||||||
return "westus";
|
return "westus";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//const cloudshellToken = await acquireMsalTokenForAccount(userContext.databaseAccount, false, "b677c290-cf4b-4a8e-a60e-91ba650a4abe");
|
||||||
|
|
||||||
|
xterminal.writeln('Requested Region ' + region);
|
||||||
|
const cloudshellToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImltaTBZMnowZFlLeEJ0dEFxS19UdDVoWUJUayIsImtpZCI6ImltaTBZMnowZFlLeEJ0dEFxS19UdDVoWUJUayJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuY29yZS53aW5kb3dzLm5ldC8iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcvIiwiaWF0IjoxNzQwMDQ2ODAzLCJuYmYiOjE3NDAwNDY4MDMsImV4cCI6MTc0MDA1MjQ4OSwiX2NsYWltX25hbWVzIjp7Imdyb3VwcyI6InNyYzEifSwiX2NsYWltX3NvdXJjZXMiOnsic3JjMSI6eyJlbmRwb2ludCI6Imh0dHBzOi8vZ3JhcGgud2luZG93cy5uZXQvNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3L3VzZXJzL2U4MGZmZGE4LTlmZDUtNDQ4ZC05M2VhLWY5YzgyM2ZjN2RkOC9nZXRNZW1iZXJPYmplY3RzIn19LCJhY3IiOiIxIiwiYWlvIjoiQVpRQWEvOFpBQUFBVWd4YU5ram1kVWZ5VlhmR3kwODJzaEFkUEFQYkd6NW1TNDBjNW0zM3hjQTNCYmpOSTVjNTArVloxMFNCbzNGNjV2Rml6a2J4Z2VuNXk1dXQvWGVVZmUvNHMyb1lSdkczTnR4V2NJK09samI2aHRBQzNuSk5uQ1JINnNnUHNqd2VBZFkxcXZTTTFnMUtZVmZ5MG11Nm5aL0NYQWhCSkpoNWNLLzRNS0F5TzZvc2NDZjN0Q2N3dS9ZcXd6ZzIwbG9UIiwiYW1yIjpbInJzYSIsIm1mYSJdLCJhcHBpZCI6ImI2NzdjMjkwLWNmNGItNGE4ZS1hNjBlLTkxYmE2NTBhNGFiZSIsImFwcGlkYWNyIjoiMCIsImRldmljZWlkIjoiZTM4YzBiOTgtMzQ5OS00YWQzLTkwN2EtYjc2NzJjNzdkZTQ3IiwiZmFtaWx5X25hbWUiOiJKYWluIiwiZ2l2ZW5fbmFtZSI6IlNvdXJhYmgiLCJpZHR5cCI6InVzZXIiLCJpcGFkZHIiOiIyNDA0OmY4MDE6ODAyODozOjhjZTU6MTk2ZDpjNWE3OmQ3YTYiLCJuYW1lIjoiU291cmFiaCBKYWluIiwib2lkIjoiZTgwZmZkYTgtOWZkNS00NDhkLTkzZWEtZjljODIzZmM3ZGQ4Iiwib25wcmVtX3NpZCI6IlMtMS01LTIxLTIxNDY3NzMwODUtOTAzMzYzMjg1LTcxOTM0NDcwNy0yNzA3MDY2IiwicHVpZCI6IjEwMDMyMDAxMUE2OTQ1RjAiLCJyaCI6IjEuQVJvQXY0ajVjdkdHcjBHUnF5MTgwQkhiUjBaSWYza0F1dGRQdWtQYXdmajJNQk1hQU9nYUFBLiIsInNjcCI6InVzZXJfaW1wZXJzb25hdGlvbiIsInNpZCI6IjAwMjAxMzA5LTJhNjAtY2M1Yy1iNTMxLTNiMGQwNWFkMWY3NSIsInN1YiI6Ijh4c0R4U0tqcmcycXdXaTNYM0pmLXkxUkNXUjZ2UDBEZ0pFbEtoTW05bTAiLCJ0aWQiOiI3MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDciLCJ1bmlxdWVfbmFtZSI6InNvdXJhYmhqYWluQG1pY3Jvc29mdC5jb20iLCJ1cG4iOiJzb3VyYWJoamFpbkBtaWNyb3NvZnQuY29tIiwidXRpIjoiN3BZYmN4MDRja3liNHZlYy1tMUdBQSIsInZlciI6IjEuMCIsIndpZHMiOlsiYjc5ZmJmNGQtM2VmOS00Njg5LTgxNDMtNzZiMTk0ZTg1NTA5Il0sInhtc19pZHJlbCI6IjI4IDEiLCJ4bXNfdGNkdCI6MTI4OTI0MTU0N30.A3eOAHuSDbA3w4n5r4xaMzpchoMuQMzAy7g7pyWGpY-zHsbUykUDYgbSOpAytMDzkcL9pbVCPlB8OxNnFOtgUn0lBRxmInCf-xWp38WoxSy_kqJ59i6PSmjSyNRVxHP70b3dNO3ZT6rkdvWWghaImTV-thQoSQyO7jYJrgEwhu8wNUV_uEQ67IGTKdylo0TupIxYW6VxpfMWfkVGaPRuZHnjQe14PwisZIJ9KJnTkgsszrv_fefbUkiE4dcG9PaWmIfSs7vLAsszNp2IozTo5VReZCztmxdTY1bNSRd2AKYb3wgywOTbB5DDzUxLLr2VofK946_eN8bHAm6uouiNOw";
|
||||||
try {
|
try {
|
||||||
// do not use the subscription from the preferred settings use the one from the context
|
// do not use the subscription from the preferred settings use the one from the context
|
||||||
await putEphemeralUserSettings(userContext.subscriptionId, region, authorizationToken);
|
await putEphemeralUserSettings(userContext.subscriptionId, region, `${cloudshellToken}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
xterminal.writeln('');
|
xterminal.writeln('');
|
||||||
xterminal.writeln('Unable to update user settings to ephemeral session.');
|
xterminal.writeln('Unable to update user settings to ephemeral session.');
|
||||||
@ -90,7 +122,7 @@ const startCloudShellterminal = async (xterminal: any, intervalsToClearRef: any,
|
|||||||
|
|
||||||
// verify user settings after they have been updated to ephemeral
|
// verify user settings after they have been updated to ephemeral
|
||||||
try {
|
try {
|
||||||
const userSettings = await getUserSettings(authorizationToken);
|
const userSettings = await getUserSettings(cloudshellToken);
|
||||||
const isValidUserSettings = validateUserSettings(userSettings);
|
const isValidUserSettings = validateUserSettings(userSettings);
|
||||||
if (!isValidUserSettings) {
|
if (!isValidUserSettings) {
|
||||||
throw new Error("Invalid user settings detected for ephemeral session.");
|
throw new Error("Invalid user settings detected for ephemeral session.");
|
||||||
@ -105,7 +137,7 @@ const startCloudShellterminal = async (xterminal: any, intervalsToClearRef: any,
|
|||||||
// trigger callback to provision console internal
|
// trigger callback to provision console internal
|
||||||
let provisionConsoleResponse;
|
let provisionConsoleResponse;
|
||||||
try {
|
try {
|
||||||
provisionConsoleResponse = await provisionConsole(userContext.subscriptionId, authorizationToken, region);
|
provisionConsoleResponse = await provisionConsole(userContext.subscriptionId, cloudshellToken, region);
|
||||||
// statusPaneUpdateCommands.setTerminalUri(provisionConsoleResponse.properties.uri);
|
// statusPaneUpdateCommands.setTerminalUri(provisionConsoleResponse.properties.uri);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
xterminal.writeln('');
|
xterminal.writeln('');
|
||||||
@ -125,7 +157,7 @@ const startCloudShellterminal = async (xterminal: any, intervalsToClearRef: any,
|
|||||||
// connect the terminal
|
// connect the terminal
|
||||||
let connectTerminalResponse;
|
let connectTerminalResponse;
|
||||||
try {
|
try {
|
||||||
connectTerminalResponse = await connectTerminal(provisionConsoleResponse.properties.uri, authorizationToken, { rows: xterminal.rows, cols: xterminal.cols });
|
connectTerminalResponse = await connectTerminal(provisionConsoleResponse.properties.uri, cloudshellToken, { rows: xterminal.rows, cols: xterminal.cols });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
xterminal.writeln('');
|
xterminal.writeln('');
|
||||||
xterminal.writeln('Unable to connect terminal.');
|
xterminal.writeln('Unable to connect terminal.');
|
||||||
@ -147,12 +179,12 @@ const startCloudShellterminal = async (xterminal: any, intervalsToClearRef: any,
|
|||||||
socketUri = 'wss://' + targetUriBodyArr[0] + '/$hc/' + targetUriBodyArr[1] + '/terminals/' + termId;
|
socketUri = 'wss://' + targetUriBodyArr[0] + '/$hc/' + targetUriBodyArr[1] + '/terminals/' + termId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// provision appropriate first party permissions to cloudshell instance
|
// // provision appropriate first party permissions to cloudshell instance
|
||||||
await postTokens(provisionConsoleResponse.properties.uri, authorizationToken).catch((err) => {
|
// await postTokens(provisionConsoleResponse.properties.uri, authorizationToken).catch((err) => {
|
||||||
xterminal.writeln('Unable to provision first party permissions to cloudshell instance.');
|
// xterminal.writeln('Unable to provision first party permissions to cloudshell instance.');
|
||||||
intervalsToClear.forEach((val) => window.clearInterval(+val));
|
// intervalsToClear.forEach((val) => window.clearInterval(+val));
|
||||||
throw err;
|
// throw err;
|
||||||
});
|
// });
|
||||||
|
|
||||||
const socket = new WebSocket(socketUri);
|
const socket = new WebSocket(socketUri);
|
||||||
|
|
||||||
@ -160,16 +192,21 @@ const startCloudShellterminal = async (xterminal: any, intervalsToClearRef: any,
|
|||||||
|
|
||||||
// authorize the session
|
// authorize the session
|
||||||
try {
|
try {
|
||||||
const authorizeResponse = await authorizeSession(provisionConsoleResponse.properties.uri, authorizationToken);
|
const authorizeResponse = await authorizeSession(provisionConsoleResponse.properties.uri, cloudshellToken);
|
||||||
const cookieToken = authorizeResponse.token;
|
const cookieToken = authorizeResponse.token;
|
||||||
const a = document.createElement("img");
|
const a = document.createElement("img");
|
||||||
a.src = targetUri + "?token=" + encodeURIComponent(cookieToken);
|
a.src = targetUri + "&token=" + encodeURIComponent(cookieToken);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
xterminal.writeln('Unable to authroize the session');
|
xterminal.writeln('Unable to authroize the session');
|
||||||
intervalsToClear.forEach((val) => window.clearInterval(+val));
|
intervalsToClear.forEach((val) => window.clearInterval(+val));
|
||||||
socket.close();
|
socket.close();
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xterminal.writeln("Connected to cloudshell.");
|
||||||
|
xterminal.focus();
|
||||||
|
|
||||||
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const validateUserSettings = (userSettings: Settings) => {
|
export const validateUserSettings = (userSettings: Settings) => {
|
||||||
@ -183,34 +220,34 @@ export const validateUserSettings = (userSettings: Settings) => {
|
|||||||
export const enum OsType {
|
export const enum OsType {
|
||||||
Linux = "linux",
|
Linux = "linux",
|
||||||
Windows = "windows"
|
Windows = "windows"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum ShellType {
|
export const enum ShellType {
|
||||||
Bash = "bash",
|
Bash = "bash",
|
||||||
PowerShellCore = "pwsh"
|
PowerShellCore = "pwsh"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum NetworkType {
|
export const enum NetworkType {
|
||||||
Default = "Default",
|
Default = "Default",
|
||||||
Isolated = "Isolated"
|
Isolated = "Isolated"
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum SessionType {
|
export const enum SessionType {
|
||||||
Mounted = "Mounted",
|
Mounted = "Mounted",
|
||||||
Ephemeral = "Ephemeral"
|
Ephemeral = "Ephemeral"
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/q/38598280 (Is it possible to wrap a function and retain its types?)
|
// https://stackoverflow.com/q/38598280 (Is it possible to wrap a function and retain its types?)
|
||||||
export const trackedApiCall = <T extends Array<any>, U>(apiCall: (...args: T) => Promise<U>, name: string) => {
|
export const trackedApiCall = <T extends Array<any>, U>(apiCall: (...args: T) => Promise<U>, name: string) => {
|
||||||
return async (...args: T): Promise<U> => {
|
return async (...args: T): Promise<U> => {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const result = await apiCall(...args);
|
const result = await apiCall(...args);
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserRegion = trackedApiCall(async (authToken: string, subscriptionId: string) => {
|
export const getUserRegion = trackedApiCall(async (authToken: string, subscriptionId: string) => {
|
||||||
const locale = getLocale();
|
const locale = getLocale();
|
||||||
const locationUri = getArmUri("management.azure.com")(`/subscriptions/${subscriptionId}/locations?api-version=2022-12-01`).toString();
|
const locationUri = getArmUri("management.azure.com")(`/subscriptions/${subscriptionId}/locations?api-version=2022-12-01`).toString();
|
||||||
return await fetch(locationUri, {
|
return await fetch(locationUri, {
|
||||||
@ -223,15 +260,15 @@ export const enum OsType {
|
|||||||
'x-ms-correlation-request-id': uuidv4(),
|
'x-ms-correlation-request-id': uuidv4(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, "getUserRegion");
|
}, "getUserRegion");
|
||||||
|
|
||||||
export type Settings = {
|
export type Settings = {
|
||||||
location: string;
|
location: string;
|
||||||
sessionType: SessionType;
|
sessionType: SessionType;
|
||||||
osType: OsType;
|
osType: OsType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getUserSettings = trackedApiCall(async (authToken: string): Promise<Settings> => {
|
export const getUserSettings = trackedApiCall(async (authToken: string): Promise<Settings> => {
|
||||||
// figure out how to set the Accept-Language dynamically
|
// figure out how to set the Accept-Language dynamically
|
||||||
const armUri = getArmUri("management.azure.com")(`/providers/Microsoft.Portal/userSettings/cloudconsole?api-version=2023-02-01-preview`).toString();;
|
const armUri = getArmUri("management.azure.com")(`/providers/Microsoft.Portal/userSettings/cloudconsole?api-version=2023-02-01-preview`).toString();;
|
||||||
const locale = getLocale();
|
const locale = getLocale();
|
||||||
@ -252,9 +289,9 @@ export const enum OsType {
|
|||||||
sessionType: json?.properties?.sessionType,
|
sessionType: json?.properties?.sessionType,
|
||||||
osType: json?.properties?.preferredOsType
|
osType: json?.properties?.preferredOsType
|
||||||
};
|
};
|
||||||
}, "getUserSettings");
|
}, "getUserSettings");
|
||||||
|
|
||||||
export const verifyCloudshellProviderRegistration = async(subscriptionId: string, authToken: string) => {
|
export const verifyCloudshellProviderRegistration = async(subscriptionId: string, authToken: string) => {
|
||||||
const targetUri = getArmUri("management.azure.com")(`/subscriptions/${subscriptionId}/providers/Microsoft.CloudShell?api-version=2022-12-01`).toString();
|
const targetUri = getArmUri("management.azure.com")(`/subscriptions/${subscriptionId}/providers/Microsoft.CloudShell?api-version=2022-12-01`).toString();
|
||||||
const locale = getLocale();
|
const locale = getLocale();
|
||||||
return await fetch(targetUri, {
|
return await fetch(targetUri, {
|
||||||
@ -266,9 +303,9 @@ export const enum OsType {
|
|||||||
'Accept-Language': locale,
|
'Accept-Language': locale,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const registerCloudShellProvider = async (subscriptionId: string, authToken: string) => {
|
export const registerCloudShellProvider = async (subscriptionId: string, authToken: string) => {
|
||||||
const targetUri = getArmUri("management.azure.com")(`/subscriptions/${subscriptionId}/providers/Microsoft.CloudShell/register?api-version=2022-12-01`).toString();
|
const targetUri = getArmUri("management.azure.com")(`/subscriptions/${subscriptionId}/providers/Microsoft.CloudShell/register?api-version=2022-12-01`).toString();
|
||||||
return await fetch(targetUri, {
|
return await fetch(targetUri, {
|
||||||
method: "post",
|
method: "post",
|
||||||
@ -278,10 +315,10 @@ export const enum OsType {
|
|||||||
'Authorization': authToken
|
'Authorization': authToken
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: update accept language header
|
// TODO: update accept language header
|
||||||
export const putEphemeralUserSettings = trackedApiCall(async (userSubscriptionId: string, userRegion: string, authorizationToken: string) => {
|
export const putEphemeralUserSettings = trackedApiCall(async (userSubscriptionId: string, userRegion: string, authorizationToken: string) => {
|
||||||
const ephemeralSettings = {
|
const ephemeralSettings = {
|
||||||
properties: {
|
properties: {
|
||||||
preferredOsType: OsType.Linux,
|
preferredOsType: OsType.Linux,
|
||||||
@ -304,17 +341,17 @@ export const enum OsType {
|
|||||||
'Accept-Language': getLocale(),
|
'Accept-Language': getLocale(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, "putEphemeralUserSettings");
|
}, "putEphemeralUserSettings");
|
||||||
|
|
||||||
type provisionConsoleResponse = {
|
type provisionConsoleResponse = {
|
||||||
properties: {
|
properties: {
|
||||||
osType: OsType;
|
osType: OsType;
|
||||||
provisioningState: string;
|
provisioningState: string;
|
||||||
uri: string;
|
uri: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const provisionConsole = trackedApiCall(async (subscriptionId: string, authorizationToken: string, location: string): Promise<provisionConsoleResponse> => {
|
export const provisionConsole = trackedApiCall(async (subscriptionId: string, authorizationToken: string, location: string): Promise<provisionConsoleResponse> => {
|
||||||
const armUri = getArmUri("management.azure.com")(`providers/Microsoft.Portal/consoles/default?api-version=2023-02-01-preview&feature.azureconsole.sessiontype=mounted&feature.azureconsole.usersubscription=${subscriptionId}`).toString();
|
const armUri = getArmUri("management.azure.com")(`providers/Microsoft.Portal/consoles/default?api-version=2023-02-01-preview&feature.azureconsole.sessiontype=mounted&feature.azureconsole.usersubscription=${subscriptionId}`).toString();
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
@ -335,19 +372,18 @@ export const enum OsType {
|
|||||||
body: JSON.stringify(data)
|
body: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
return resp.json();
|
return resp.json();
|
||||||
}, "provisionConsole");
|
}, "provisionConsole");
|
||||||
|
|
||||||
export type ConnectTerminalResponse = {
|
export type ConnectTerminalResponse = {
|
||||||
id: string;
|
id: string;
|
||||||
idleTimeout: string;
|
idleTimeout: string;
|
||||||
rootDirectory: string;
|
rootDirectory: string;
|
||||||
socketUri: string;
|
socketUri: string;
|
||||||
tokenUpdated: boolean;
|
tokenUpdated: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const postTokens = trackedApiCall(async (consoleUri: string, authorizationToken: string) => {
|
export const postTokens = trackedApiCall(async (consoleUri: string, authorizationToken: string) => {
|
||||||
const targetUri = consoleUri + '/accessToken';
|
const targetUri = consoleUri + '/accessToken';
|
||||||
let aadAuth = useAADAuth();
|
|
||||||
let token = aadAuth.armToken;
|
let token = aadAuth.armToken;
|
||||||
|
|
||||||
await fetch(targetUri, {
|
await fetch(targetUri, {
|
||||||
@ -360,9 +396,9 @@ export const enum OsType {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({ token })
|
body: JSON.stringify({ token })
|
||||||
});
|
});
|
||||||
}, "postTokens");
|
}, "postTokens");
|
||||||
|
|
||||||
export const connectTerminal = trackedApiCall(async (consoleUri: string, authorizationToken: string, size: { rows: number, cols: number }): Promise<ConnectTerminalResponse> => {
|
export const connectTerminal = trackedApiCall(async (consoleUri: string, authorizationToken: string, size: { rows: number, cols: number }): Promise<ConnectTerminalResponse> => {
|
||||||
const targetUri = consoleUri + `/terminals?cols=${size.cols}&rows=${size.rows}&version=2019-01-01&shell=bash`;
|
const targetUri = consoleUri + `/terminals?cols=${size.cols}&rows=${size.rows}&version=2019-01-01&shell=bash`;
|
||||||
const resp = await fetch(targetUri, {
|
const resp = await fetch(targetUri, {
|
||||||
method: "post",
|
method: "post",
|
||||||
@ -377,13 +413,13 @@ export const enum OsType {
|
|||||||
body: "{}" // empty body is necessary
|
body: "{}" // empty body is necessary
|
||||||
});
|
});
|
||||||
return resp.json();
|
return resp.json();
|
||||||
}, "connectTerminal");
|
}, "connectTerminal");
|
||||||
|
|
||||||
export type Authroization = {
|
export type Authorization = {
|
||||||
token: string;
|
token: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const authorizeSession = trackedApiCall(async (consoleUri: string, accessToken: string): Promise<Authroization> => {
|
export const authorizeSession = trackedApiCall(async (consoleUri: string, accessToken: string): Promise<Authorization> => {
|
||||||
const targetUri = consoleUri + "/authorize";
|
const targetUri = consoleUri + "/authorize";
|
||||||
const resp = await fetch(targetUri, {
|
const resp = await fetch(targetUri, {
|
||||||
method: "post",
|
method: "post",
|
||||||
@ -392,49 +428,57 @@ export const enum OsType {
|
|||||||
'Authorization': accessToken,
|
'Authorization': accessToken,
|
||||||
'Accept-Language': getLocale(),
|
'Accept-Language': getLocale(),
|
||||||
"Content-Type": 'application/json'
|
"Content-Type": 'application/json'
|
||||||
}
|
},
|
||||||
|
body: "{}" // empty body is necessary
|
||||||
});
|
});
|
||||||
return resp.json();
|
return resp.json();
|
||||||
}, "authorizeSession");
|
}, "authorizeSession");
|
||||||
|
|
||||||
|
|
||||||
export const getArmUri = (origin: string): (relativePath: string) => string => {
|
export const getArmUri = (origin: string): (relativePath: string) => string => {
|
||||||
let originNoTrailingSlash = origin;
|
let originNoTrailingSlash = origin;
|
||||||
if (origin.endsWith("/")) {
|
if (origin.endsWith("/")) {
|
||||||
originNoTrailingSlash = originNoTrailingSlash.slice(0, originNoTrailingSlash.length - 1);
|
originNoTrailingSlash = originNoTrailingSlash.slice(0, originNoTrailingSlash.length - 1);
|
||||||
} else {
|
} else {
|
||||||
origin += "/";
|
origin += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (relativePath: string) => {
|
return (relativePath: string) => {
|
||||||
if (!relativePath) {
|
if (!relativePath) {
|
||||||
throw new Error(`relativePath is required: ${relativePath}`);
|
throw new Error(`relativePath is required: ${relativePath}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `https://${relativePath.charAt(0) === "/" ? originNoTrailingSlash : origin}${relativePath}`;
|
return `https://${relativePath.charAt(0) === "/" ? originNoTrailingSlash : origin}${relativePath}`;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getLocale = () => {
|
export const getLocale = () => {
|
||||||
const langLocale = navigator.language;
|
const langLocale = navigator.language;
|
||||||
return (langLocale && langLocale.length === 2 ? langLocale[1] : 'en-us');
|
return (langLocale && langLocale.length === 2 ? langLocale[1] : 'en-us');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTrustedParentOrigin = () => {
|
export const getTrustedParentOrigin = () => {
|
||||||
const searchParams = new URLSearchParams(window.location.search);
|
const searchParams = new URLSearchParams(window.location.search);
|
||||||
return searchParams.get("trustedAuthority") || '';
|
return searchParams.get("trustedAuthority") || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let keepAliveID: NodeJS.Timeout = null;
|
let keepAliveID: NodeJS.Timeout = null;
|
||||||
let pingCount = 0;
|
let pingCount = 0;
|
||||||
|
|
||||||
export const configureSocket = (socket: WebSocket, uri: string, terminal: any, intervals: NodeJS.Timer[], socketRetryCount: number) => {
|
export const configureSocket = (socket: WebSocket, uri: string, terminal: any, intervals: NodeJS.Timer[], socketRetryCount: number) => {
|
||||||
let jsonData = '';
|
let jsonData = '';
|
||||||
socket.onopen = () => {
|
socket.onopen = () => {
|
||||||
|
terminal.writeln("Socket Opened");
|
||||||
const initializeCommand =
|
const initializeCommand =
|
||||||
`rm -rf ie.log && rm -rf ie && rm -rf scenarios/ && \n` +
|
`curl -s https://ipinfo.io \n` +
|
||||||
`echo Welcome to this quick start shell. This Cloud Shell terminal will be used to execute commands as part of the scenario. Follow the instructions on the left to get started\n`;
|
`curl -LO https://downloads.mongodb.com/compass/mongosh-2.3.8-linux-x64.tgz \n` +
|
||||||
|
`tar -xvzf mongosh-2.3.8-linux-x64.tgz \n` +
|
||||||
|
`mkdir -p ~/mongosh && mv mongosh-2.3.8-linux-x64/* ~/mongosh/ \n` +
|
||||||
|
`echo 'export PATH=$PATH:$HOME/mongosh/bin' >> ~/.bashrc \n` +
|
||||||
|
`source ~/.bashrc \n` +
|
||||||
|
`mongosh --version \n`;
|
||||||
|
|
||||||
|
terminal.writeln(initializeCommand);
|
||||||
socket.send(initializeCommand);
|
socket.send(initializeCommand);
|
||||||
|
|
||||||
const keepSocketAlive = (socket: WebSocket) => {
|
const keepSocketAlive = (socket: WebSocket) => {
|
||||||
@ -452,6 +496,7 @@ export const enum OsType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
socket.onclose = () => {
|
socket.onclose = () => {
|
||||||
|
terminal.writeln("Socket Closed");
|
||||||
if (keepAliveID) {
|
if (keepAliveID) {
|
||||||
clearTimeout(keepAliveID);
|
clearTimeout(keepAliveID);
|
||||||
pingCount = 0;
|
pingCount = 0;
|
||||||
@ -476,6 +521,7 @@ export const enum OsType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
socket.onmessage = (event: MessageEvent<string>) => {
|
socket.onmessage = (event: MessageEvent<string>) => {
|
||||||
|
terminal.writeln("Socket onMessage");
|
||||||
// if we are sending and receiving messages the terminal is not idle set ping count to 0
|
// if we are sending and receiving messages the terminal is not idle set ping count to 0
|
||||||
pingCount = 0;
|
pingCount = 0;
|
||||||
|
|
||||||
@ -491,6 +537,8 @@ export const enum OsType {
|
|||||||
}
|
}
|
||||||
if (typeof event.data === 'string') {
|
if (typeof event.data === 'string') {
|
||||||
eventData = event.data;
|
eventData = event.data;
|
||||||
|
|
||||||
|
terminal.write(eventData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// process as one line or process as multiline
|
// process as one line or process as multiline
|
||||||
@ -511,6 +559,8 @@ export const enum OsType {
|
|||||||
jsonData += eventData;
|
jsonData += eventData;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return socket;
|
return socket;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default XTermComponent;
|
export default XTermComponent;
|
||||||
|
@ -46,14 +46,14 @@ export function decryptJWTToken(token: string) {
|
|||||||
return JSON.parse(tokenPayload);
|
return JSON.parse(tokenPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getMsalInstance() {
|
export async function getMsalInstance(clientId: string = "203f1145-856a-4232-83d4-a43568fba23d"){
|
||||||
const msalConfig: msal.Configuration = {
|
const msalConfig: msal.Configuration = {
|
||||||
cache: {
|
cache: {
|
||||||
cacheLocation: "localStorage",
|
cacheLocation: "localStorage",
|
||||||
},
|
},
|
||||||
auth: {
|
auth: {
|
||||||
authority: `${configContext.AAD_ENDPOINT}organizations`,
|
authority: `${configContext.AAD_ENDPOINT}organizations`,
|
||||||
clientId: "203f1145-856a-4232-83d4-a43568fba23d",
|
clientId: clientId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -68,7 +68,8 @@ export async function getMsalInstance() {
|
|||||||
export async function acquireMsalTokenForAccount(
|
export async function acquireMsalTokenForAccount(
|
||||||
account: DatabaseAccount,
|
account: DatabaseAccount,
|
||||||
silent: boolean = false,
|
silent: boolean = false,
|
||||||
user_hint?: string,
|
clientId: string = "203f1145-856a-4232-83d4-a43568fba23d",
|
||||||
|
user_hint?: string
|
||||||
) {
|
) {
|
||||||
if (userContext.databaseAccount.properties?.documentEndpoint === undefined) {
|
if (userContext.databaseAccount.properties?.documentEndpoint === undefined) {
|
||||||
throw new Error("Database account has no document endpoint defined");
|
throw new Error("Database account has no document endpoint defined");
|
||||||
@ -77,7 +78,7 @@ export async function acquireMsalTokenForAccount(
|
|||||||
/\/+$/,
|
/\/+$/,
|
||||||
"/.default",
|
"/.default",
|
||||||
);
|
);
|
||||||
const msalInstance = await getMsalInstance();
|
const msalInstance = await getMsalInstance(clientId);
|
||||||
const knownAccounts = msalInstance.getAllAccounts();
|
const knownAccounts = msalInstance.getAllAccounts();
|
||||||
// If user_hint is provided, we will try to use it to find the account.
|
// If user_hint is provided, we will try to use it to find the account.
|
||||||
// If no account is found, we will use the current active account or first account in the list.
|
// If no account is found, we will use the current active account or first account in the list.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user