added consent

This commit is contained in:
Sourabh Jain 2025-02-25 11:23:42 +05:30
parent 9b2cb8a1a9
commit 2c3c4e7db7
4 changed files with 105 additions and 63 deletions

View File

@ -7,7 +7,7 @@ import { configContext } from "../../../ConfigContext";
import { armRequest } from "../../../Utils/arm/request"; import { armRequest } from "../../../Utils/arm/request";
import { Authorization, ConnectTerminalResponse, NetworkType, OsType, ProvisionConsoleResponse, SessionType, Settings, ShellType } from "./DataModels"; import { Authorization, ConnectTerminalResponse, NetworkType, OsType, ProvisionConsoleResponse, SessionType, Settings, ShellType } from "./DataModels";
const cloudshellToken = ""; const cloudshellToken = "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImltaTBZMnowZFlLeEJ0dEFxS19UdDVoWUJUayIsImtpZCI6ImltaTBZMnowZFlLeEJ0dEFxS19UdDVoWUJUayJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuY29yZS53aW5kb3dzLm5ldC8iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC83MmY5ODhiZi04NmYxLTQxYWYtOTFhYi0yZDdjZDAxMWRiNDcvIiwiaWF0IjoxNzQwNDU5Njc2LCJuYmYiOjE3NDA0NTk2NzYsImV4cCI6MTc0MDQ2NDA0NSwiX2NsYWltX25hbWVzIjp7Imdyb3VwcyI6InNyYzEifSwiX2NsYWltX3NvdXJjZXMiOnsic3JjMSI6eyJlbmRwb2ludCI6Imh0dHBzOi8vZ3JhcGgud2luZG93cy5uZXQvNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3L3VzZXJzL2U4MGZmZGE4LTlmZDUtNDQ4ZC05M2VhLWY5YzgyM2ZjN2RkOC9nZXRNZW1iZXJPYmplY3RzIn19LCJhY3IiOiIxIiwiYWlvIjoiQVpRQWEvOFpBQUFBRjcvNHplb1lpQWYxcytvR1FMVXVsa2NJbU93dGx1aVJNMVVKeVI3czIrV0Z5VVdPM2MrUlUybmdsTlBRaGtwTFo4SktsYjg0a1dlTVhCZFFXemJGcUJGQ0M1aXU3ZUxyamRYY3NOaVMwc0l5Z1crdTJsT1I3VzBsNC8xT3UzRnRjakJoQlZLSTFFTGpLWHJjbzkrbTM0WUZJbmYrc0VPNkhuNmJFMmdIL3kxamUyQXZvZXNTaDhmZlpQdjZNSUcxIiwiYW1yIjpbInJzYSIsIm1mYSJdLCJhcHBpZCI6ImM0NGI0MDgzLTNiYjAtNDljMS1iNDdkLTk3NGU1M2NiZGYzYyIsImFwcGlkYWNyIjoiMCIsImRldmljZWlkIjoiZTM4YzBiOTgtMzQ5OS00YWQzLTkwN2EtYjc2NzJjNzdkZTQ3IiwiZmFtaWx5X25hbWUiOiJKYWluIiwiZ2l2ZW5fbmFtZSI6IlNvdXJhYmgiLCJpZHR5cCI6InVzZXIiLCJpcGFkZHIiOiIyNDA1OjIwMTo0MDMzOjIxY2U6OWRkOTpkMGY1OmJjZWE6YjFiMCIsIm5hbWUiOiJTb3VyYWJoIEphaW4iLCJvaWQiOiJlODBmZmRhOC05ZmQ1LTQ0OGQtOTNlYS1mOWM4MjNmYzdkZDgiLCJvbnByZW1fc2lkIjoiUy0xLTUtMjEtMjE0Njc3MzA4NS05MDMzNjMyODUtNzE5MzQ0NzA3LTI3MDcwNjYiLCJwdWlkIjoiMTAwMzIwMDExQTY5NDVGMCIsInJoIjoiMS5BUm9BdjRqNWN2R0dyMEdScXkxODBCSGJSMFpJZjNrQXV0ZFB1a1Bhd2ZqMk1CTWFBT2dhQUEuIiwic2NwIjoidXNlcl9pbXBlcnNvbmF0aW9uIiwic2lkIjoiMDAyMDEzMDktMmE2MC1jYzVjLWI1MzEtM2IwZDA1YWQxZjc1Iiwic3ViIjoiOHhzRHhTS2pyZzJxd1dpM1gzSmYteTFSQ1dSNnZQMERnSkVsS2hNbTltMCIsInRpZCI6IjcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0NyIsInVuaXF1ZV9uYW1lIjoic291cmFiaGphaW5AbWljcm9zb2Z0LmNvbSIsInVwbiI6InNvdXJhYmhqYWluQG1pY3Jvc29mdC5jb20iLCJ1dGkiOiJUVDYwRzBpSFJrMmN4Y1AtVVZzbEFBIiwidmVyIjoiMS4wIiwieG1zX2lkcmVsIjoiMSAzMCIsInhtc190Y2R0IjoxMjg5MjQxNTQ3fQ.LBYpLSmj8Cd-ZL3i9yuqVvPB0CirALEq7ldFywDH2U5c9LlnUfLgOf_C_N0Uu0ChthTl9Eu54TXuGCxFXwfVSg_kaPuZhtc-vDqVurjHtyNr-53qKg8fbQYbOnB_JGqC86TzdqPRv1XwhZj9C2bNjjGZ2GrcOWitv8CgM9Fs9Cul1OHiq5j8BTJl8OX_THC-VUB11fB-5qyitH9pTtETC4o7AKg4fOHftXYDkFI0gVF_WCZoquI6kFEnoQtt_qhu4rK71VqVRt5qqBeT8tgH4GwsP2W7pBlzESdjSXWMJ5u7klXJwheYvuytrxioD1f0HCOLHyBFpVf5JTBBeXjPow";
export const validateUserSettings = (userSettings: Settings) => { export const validateUserSettings = (userSettings: Settings) => {
if (userSettings.sessionType !== SessionType.Ephemeral && userSettings.osType !== OsType.Linux) { if (userSettings.sessionType !== SessionType.Ephemeral && userSettings.osType !== OsType.Linux) {
@ -163,15 +163,14 @@ export const getLocale = () => {
return (langLocale && langLocale.length === 2 ? langLocale[1] : 'en-us'); return (langLocale && langLocale.length === 2 ? langLocale[1] : 'en-us');
}; };
const validCloudShellRegions = new Set(["westus", "southcentralus", "eastus", "northeurope", "westeurope", "centralindia", "southeastasia", "westcentralus", "eastus2euap", "centraluseuap"]); const validCloudShellRegions = new Set(["westus", "southcentralus", "eastus", "northeurope", "westeurope", "centralindia", "southeastasia", "westcentralus"]);
const defaultCloudshellRegion = "westus";
export const getNormalizedRegion = (region: string) => { export const getNormalizedRegion = (region: string, defaultCloudshellRegion: string) => {
if (!region) return defaultCloudshellRegion; if (!region) return defaultCloudshellRegion;
const regionMap: Record<string, string> = { const regionMap: Record<string, string> = {
"centralus": "centraluseuap", "centralus": "westcentralus",
"eastus2": "eastus2euap" "eastus2": "eastus"
}; };
const normalizedRegion = regionMap[region.toLowerCase()] || region; const normalizedRegion = regionMap[region.toLowerCase()] || region;

View File

@ -3,7 +3,7 @@
*/ */
export const LogError = (message: string) => { export const LogError = (message: string) => {
return `\n\r\x1B[1;37m${message}`; return `\x1B[1;31m${message}`;
} }
export const LogInfo = (message: string) => { export const LogInfo = (message: string) => {

View File

@ -24,66 +24,23 @@ export const startCloudShellterminal = async (xterminal: Terminal, initCommands:
const region = userContext.databaseAccount?.location; const region = userContext.databaseAccount?.location;
xterminal.writeln(LogInfo(`Database Acount Region identified as '${region}'`)); xterminal.writeln(LogInfo(`Database Acount Region identified as '${region}'`));
const resolvedRegion = getNormalizedRegion(region); const defaultCloudshellRegion = "westus";
const resolvedRegion = getNormalizedRegion(region, defaultCloudshellRegion);
xterminal.writeln(LogInfo(`Requesting Cloudshell instance at '${resolvedRegion}'`)); xterminal.writeln(LogInfo(`Requesting Cloudshell instance at '${resolvedRegion}'`));
try { try {
// do not use the subscription from the preferred settings use the one from the context var { socketUri, provisionConsoleResponse, targetUri } = await provisionCloudShellSession(resolvedRegion, xterminal);
await putEphemeralUserSettings(userContext.subscriptionId, resolvedRegion); }
} catch (err) { catch (err) {
xterminal.writeln(LogError('Unable to update user settings to ephemeral session.')); xterminal.writeln(LogError(err));
throw err; xterminal.writeln(LogError(`Unable to provision console in request region, Falling back to default region i.e. ${defaultCloudshellRegion}`));
var { socketUri, provisionConsoleResponse, targetUri } = await provisionCloudShellSession(defaultCloudshellRegion, xterminal);
} }
// verify user settings after they have been updated to ephemeral if(!socketUri) {
try { xterminal.writeln(LogError('Unable to provision console. Close and Open the terminal again to retry.'));
const userSettings = await getUserSettings(); return{};
const isValidUserSettings = validateUserSettings(userSettings);
if (!isValidUserSettings) {
throw new Error("Invalid user settings detected for ephemeral session.");
}
} catch (err) {
xterminal.writeln(LogError('Unable to verify user settings for ephemeral session.'));
throw err;
}
// trigger callback to provision console internal
let provisionConsoleResponse;
try {
provisionConsoleResponse = await provisionConsole(userContext.subscriptionId, resolvedRegion);
} catch (err) {
xterminal.writeln(LogError('Unable to provision console.\n\r'));
throw err;
}
if (provisionConsoleResponse.properties.provisioningState !== "Succeeded") {
xterminal.writeln(LogError("Failed to provision console.\n\r"));
throw new Error("Failed to provision console.");
}
xterminal.writeln(LogInfo("Connecting to cloudshell"));
xterminal.writeln(LogInfo("Please wait..."));
// connect the terminal
let connectTerminalResponse;
try {
connectTerminalResponse = await connectTerminal(provisionConsoleResponse.properties.uri, { rows: xterminal.rows, cols: xterminal.cols });
} catch (err) {
xterminal.writeln('');
xterminal.writeln(LogError('Unable to connect terminal.'));
throw err;
}
const targetUri = provisionConsoleResponse.properties.uri + `/terminals?cols=${xterminal.cols}&rows=${xterminal.rows}&version=2019-01-01&shell=bash`;
const termId = connectTerminalResponse.id;
let socketUri = connectTerminalResponse.socketUri.replace(":443/", "");
const targetUriBody = targetUri.replace('https://', '').split('?')[0];
if (socketUri.indexOf(targetUriBody) === -1) {
socketUri = 'wss://' + targetUriBody + '/' + termId;
}
if (targetUriBody.includes('servicebus')) {
const targetUriBodyArr = targetUriBody.split('/');
socketUri = 'wss://' + targetUriBodyArr[0] + '/$hc/' + targetUriBodyArr[1] + '/terminals/' + termId;
} }
const socket = new WebSocket(socketUri); const socket = new WebSocket(socketUri);
@ -190,3 +147,89 @@ export const configureSocket = (socket: WebSocket, uri: string, terminal: any,
return socket; return socket;
}; };
const provisionCloudShellSession = async(
resolvedRegion: string,
xterminal: Terminal
): Promise<{ socketUri?: string; provisionConsoleResponse?: any; targetUri?: string }> => {
return new Promise((resolve, reject) => {
// Show consent message inside the terminal
xterminal.writeln(`\x1B[1;33m⚠ Are you agreeing to continue with cloudshell terminal at ${resolvedRegion}.\x1B[0m`);
xterminal.writeln("\x1B[1;37mPress 'Y' to continue or 'N' to exit.\x1B[0m");
// Listen for user input
const handleKeyPress = xterminal.onKey(async ({ key }: { key: string }) => {
// Remove the event listener after first execution
handleKeyPress.dispose();
if (key.toLowerCase() === "y") {
xterminal.writeln("\x1B[1;32m✅ Consent given. Terminal ready!\x1B[0m");
try {
await putEphemeralUserSettings(userContext.subscriptionId, resolvedRegion);
} catch (err) {
xterminal.writeln(LogError('Unable to update user settings to ephemeral session.'));
return reject(err);
}
// verify user settings after they have been updated to ephemeral
try {
const userSettings = await getUserSettings();
const isValidUserSettings = validateUserSettings(userSettings);
if (!isValidUserSettings) {
throw new Error("Invalid user settings detected for ephemeral session.");
}
} catch (err) {
xterminal.writeln(LogError('Unable to verify user settings for ephemeral session.'));
return reject(err);
}
// trigger callback to provision console internal
let provisionConsoleResponse;
try {
provisionConsoleResponse = await provisionConsole(userContext.subscriptionId, resolvedRegion);
} catch (err) {
xterminal.writeln(LogError('Unable to provision console.\n\r'));
return reject(err);
}
if (provisionConsoleResponse.properties.provisioningState !== "Succeeded") {
xterminal.writeln(LogError("Failed to provision console.\n\r"));
return reject(new Error("Failed to provision console."));
}
xterminal.writeln(LogInfo("Connecting to cloudshell"));
xterminal.writeln(LogInfo("Please wait..."));
// connect the terminal
let connectTerminalResponse;
try {
connectTerminalResponse = await connectTerminal(provisionConsoleResponse.properties.uri, { rows: xterminal.rows, cols: xterminal.cols });
} catch (err) {
xterminal.writeln('');
xterminal.writeln(LogError('Unable to connect terminal.'));
return reject(err);
}
const targetUri = provisionConsoleResponse.properties.uri + `/terminals?cols=${xterminal.cols}&rows=${xterminal.rows}&version=2019-01-01&shell=bash`;
const termId = connectTerminalResponse.id;
let socketUri = connectTerminalResponse.socketUri.replace(":443/", "");
const targetUriBody = targetUri.replace('https://', '').split('?')[0];
if (socketUri.indexOf(targetUriBody) === -1) {
socketUri = 'wss://' + targetUriBody + '/' + termId;
}
if (targetUriBody.includes('servicebus')) {
const targetUriBodyArr = targetUriBody.split('/');
socketUri = 'wss://' + targetUriBodyArr[0] + '/$hc/' + targetUriBodyArr[1] + '/terminals/' + termId;
}
return resolve({ socketUri, provisionConsoleResponse, targetUri });
} else if (key.toLowerCase() === "n") {
xterminal.writeln("\x1B[1;31m❌ Consent denied. Exiting...\x1B[0m");
setTimeout(() => xterminal.dispose(), 2000); // Close terminal after 2 sec
return resolve({});
}
});
});
};