Validate endpoints from feature flags (#1196)
Validate endpoints from feature flags
This commit is contained in:
parent
de5df90f75
commit
f5da8bb276
|
@ -12,7 +12,8 @@
|
||||||
"--inspect-brk",
|
"--inspect-brk",
|
||||||
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
||||||
"--runInBand",
|
"--runInBand",
|
||||||
"--coverage", "false"
|
"--coverage",
|
||||||
|
"false"
|
||||||
],
|
],
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"internalConsoleOptions": "neverOpen",
|
"internalConsoleOptions": "neverOpen",
|
||||||
|
@ -26,7 +27,8 @@
|
||||||
"--inspect-brk",
|
"--inspect-brk",
|
||||||
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
||||||
"${fileBasenameNoExtension}",
|
"${fileBasenameNoExtension}",
|
||||||
"--coverage", "false",
|
"--coverage",
|
||||||
|
"false",
|
||||||
// "--watch",
|
// "--watch",
|
||||||
// // --no-cache only used to make --watch work. Otherwise jest ignores the breakpoints.
|
// // --no-cache only used to make --watch work. Otherwise jest ignores the breakpoints.
|
||||||
// // https://github.com/facebook/jest/issues/6683
|
// // https://github.com/facebook/jest/issues/6683
|
||||||
|
|
|
@ -236,13 +236,12 @@ describe("MongoProxyClient", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns a production endpoint", () => {
|
it("returns a production endpoint", () => {
|
||||||
const endpoint = getEndpoint();
|
const endpoint = getEndpoint("https://main.documentdb.ext.azure.com");
|
||||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/mongo/explorer");
|
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/mongo/explorer");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns a development endpoint", () => {
|
it("returns a development endpoint", () => {
|
||||||
updateConfigContext({ MONGO_BACKEND_ENDPOINT: "https://localhost:1234" });
|
const endpoint = getEndpoint("https://localhost:1234");
|
||||||
const endpoint = getEndpoint();
|
|
||||||
expect(endpoint).toEqual("https://localhost:1234/api/mongo/explorer");
|
expect(endpoint).toEqual("https://localhost:1234/api/mongo/explorer");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -250,7 +249,7 @@ describe("MongoProxyClient", () => {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.EncryptedToken,
|
authType: AuthType.EncryptedToken,
|
||||||
});
|
});
|
||||||
const endpoint = getEndpoint();
|
const endpoint = getEndpoint("https://main.documentdb.ext.azure.com");
|
||||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Constants as CosmosSDKConstants } from "@azure/cosmos";
|
import { Constants as CosmosSDKConstants } from "@azure/cosmos";
|
||||||
import queryString from "querystring";
|
import queryString from "querystring";
|
||||||
|
import { allowedMongoProxyEndpoints, validateEndpoint } from "Utils/EndpointValidation";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { configContext } from "../ConfigContext";
|
import { configContext } from "../ConfigContext";
|
||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
|
@ -336,14 +337,17 @@ export function createMongoCollectionWithProxy(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFeatureEndpointOrDefault(feature: string): string {
|
export function getFeatureEndpointOrDefault(feature: string): string {
|
||||||
return hasFlag(userContext.features.mongoProxyAPIs, feature)
|
const endpoint =
|
||||||
? getEndpoint(userContext.features.mongoProxyEndpoint)
|
hasFlag(userContext.features.mongoProxyAPIs, feature) &&
|
||||||
: getEndpoint();
|
validateEndpoint(userContext.features.mongoProxyEndpoint, allowedMongoProxyEndpoints)
|
||||||
|
? userContext.features.mongoProxyEndpoint
|
||||||
|
: configContext.MONGO_BACKEND_ENDPOINT || configContext.BACKEND_ENDPOINT;
|
||||||
|
|
||||||
|
return getEndpoint(endpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEndpoint(customEndpoint?: string): string {
|
export function getEndpoint(endpoint: string): string {
|
||||||
let url = customEndpoint ? customEndpoint : configContext.MONGO_BACKEND_ENDPOINT || configContext.BACKEND_ENDPOINT;
|
let url = endpoint + "/api/mongo/explorer";
|
||||||
url += "/api/mongo/explorer";
|
|
||||||
|
|
||||||
if (userContext.authType === AuthType.EncryptedToken) {
|
if (userContext.authType === AuthType.EncryptedToken) {
|
||||||
url = url.replace("api/mongo", "api/guest/mongo");
|
url = url.replace("api/mongo", "api/guest/mongo");
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
import { JunoEndpoints } from "Common/Constants";
|
import {
|
||||||
|
allowedAadEndpoints,
|
||||||
|
allowedArcadiaEndpoints,
|
||||||
|
allowedArmEndpoints,
|
||||||
|
allowedBackendEndpoints,
|
||||||
|
allowedEmulatorEndpoints,
|
||||||
|
allowedGraphEndpoints,
|
||||||
|
allowedHostedExplorerEndpoints,
|
||||||
|
allowedJunoOrigins,
|
||||||
|
allowedMongoBackendEndpoints,
|
||||||
|
allowedMsalRedirectEndpoints,
|
||||||
|
validateEndpoint,
|
||||||
|
} from "Utils/EndpointValidation";
|
||||||
|
|
||||||
export enum Platform {
|
export enum Platform {
|
||||||
Portal = "Portal",
|
Portal = "Portal",
|
||||||
|
@ -8,7 +20,7 @@ export enum Platform {
|
||||||
|
|
||||||
export interface ConfigContext {
|
export interface ConfigContext {
|
||||||
platform: Platform;
|
platform: Platform;
|
||||||
allowedParentFrameOrigins: string[];
|
allowedParentFrameOrigins: ReadonlyArray<string>;
|
||||||
gitSha?: string;
|
gitSha?: string;
|
||||||
proxyPath?: string;
|
proxyPath?: string;
|
||||||
AAD_ENDPOINT: string;
|
AAD_ENDPOINT: string;
|
||||||
|
@ -30,7 +42,6 @@ export interface ConfigContext {
|
||||||
isTerminalEnabled: boolean;
|
isTerminalEnabled: boolean;
|
||||||
hostedExplorerURL: string;
|
hostedExplorerURL: string;
|
||||||
armAPIVersion?: string;
|
armAPIVersion?: string;
|
||||||
allowedJunoOrigins: string[];
|
|
||||||
msalRedirectURI?: string;
|
msalRedirectURI?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,8 +55,7 @@ let configContext: Readonly<ConfigContext> = {
|
||||||
`^https:\\/\\/[\\.\\w]*ext\\.azure\\.(com|cn|us)$`,
|
`^https:\\/\\/[\\.\\w]*ext\\.azure\\.(com|cn|us)$`,
|
||||||
`^https:\\/\\/[\\.\\w]*\\.ext\\.microsoftazure\\.de$`,
|
`^https:\\/\\/[\\.\\w]*\\.ext\\.microsoftazure\\.de$`,
|
||||||
`^https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de$`,
|
`^https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de$`,
|
||||||
],
|
], // Webpack injects this at build time
|
||||||
// Webpack injects this at build time
|
|
||||||
gitSha: process.env.GIT_SHA,
|
gitSha: process.env.GIT_SHA,
|
||||||
hostedExplorerURL: "https://cosmos.azure.com/",
|
hostedExplorerURL: "https://cosmos.azure.com/",
|
||||||
AAD_ENDPOINT: "https://login.microsoftonline.com/",
|
AAD_ENDPOINT: "https://login.microsoftonline.com/",
|
||||||
|
@ -61,14 +71,6 @@ let configContext: Readonly<ConfigContext> = {
|
||||||
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
|
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
|
||||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||||
isTerminalEnabled: false,
|
isTerminalEnabled: false,
|
||||||
allowedJunoOrigins: [
|
|
||||||
JunoEndpoints.Test,
|
|
||||||
JunoEndpoints.Test2,
|
|
||||||
JunoEndpoints.Test3,
|
|
||||||
JunoEndpoints.Prod,
|
|
||||||
JunoEndpoints.Stage,
|
|
||||||
"https://localhost",
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function resetConfigContext(): void {
|
export function resetConfigContext(): void {
|
||||||
|
@ -79,6 +81,50 @@ export function resetConfigContext(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateConfigContext(newContext: Partial<ConfigContext>): void {
|
export function updateConfigContext(newContext: Partial<ConfigContext>): void {
|
||||||
|
if (!newContext) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.ARM_ENDPOINT, allowedArmEndpoints)) {
|
||||||
|
delete newContext.ARM_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.AAD_ENDPOINT, allowedAadEndpoints)) {
|
||||||
|
delete newContext.AAD_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.EMULATOR_ENDPOINT, allowedEmulatorEndpoints)) {
|
||||||
|
delete newContext.EMULATOR_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.GRAPH_ENDPOINT, allowedGraphEndpoints)) {
|
||||||
|
delete newContext.GRAPH_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.ARCADIA_ENDPOINT, allowedArcadiaEndpoints)) {
|
||||||
|
delete newContext.ARCADIA_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.BACKEND_ENDPOINT, allowedBackendEndpoints)) {
|
||||||
|
delete newContext.BACKEND_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.MONGO_BACKEND_ENDPOINT, allowedMongoBackendEndpoints)) {
|
||||||
|
delete newContext.MONGO_BACKEND_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.JUNO_ENDPOINT, allowedJunoOrigins)) {
|
||||||
|
delete newContext.JUNO_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.hostedExplorerURL, allowedHostedExplorerEndpoints)) {
|
||||||
|
delete newContext.hostedExplorerURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validateEndpoint(newContext.msalRedirectURI, allowedMsalRedirectEndpoints)) {
|
||||||
|
delete newContext.msalRedirectURI;
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(configContext, newContext);
|
Object.assign(configContext, newContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,18 +148,8 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
|
||||||
});
|
});
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
try {
|
try {
|
||||||
const { allowedParentFrameOrigins, allowedJunoOrigins, ...externalConfig } = await response.json();
|
const { ...externalConfig } = await response.json();
|
||||||
Object.assign(configContext, externalConfig);
|
updateConfigContext(externalConfig);
|
||||||
if (allowedParentFrameOrigins && allowedParentFrameOrigins.length > 0) {
|
|
||||||
updateConfigContext({
|
|
||||||
allowedParentFrameOrigins: [...configContext.allowedParentFrameOrigins, ...allowedParentFrameOrigins],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (allowedJunoOrigins && allowedJunoOrigins.length > 0) {
|
|
||||||
updateConfigContext({
|
|
||||||
allowedJunoOrigins: [...configContext.allowedJunoOrigins, ...allowedJunoOrigins],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Unable to parse json in config file");
|
console.error("Unable to parse json in config file");
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { Link } from "@fluentui/react/lib/Link";
|
import { Link } from "@fluentui/react/lib/Link";
|
||||||
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
|
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
|
||||||
|
import { IGalleryItem } from "Juno/JunoClient";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
|
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValidation";
|
||||||
import shallow from "zustand/shallow";
|
import shallow from "zustand/shallow";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
||||||
|
@ -24,7 +26,6 @@ import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
||||||
import { useSidePanel } from "../hooks/useSidePanel";
|
import { useSidePanel } from "../hooks/useSidePanel";
|
||||||
import { useTabs } from "../hooks/useTabs";
|
import { useTabs } from "../hooks/useTabs";
|
||||||
import { IGalleryItem } from "../Juno/JunoClient";
|
|
||||||
import { PhoenixClient } from "../Phoenix/PhoenixClient";
|
import { PhoenixClient } from "../Phoenix/PhoenixClient";
|
||||||
import * as ExplorerSettings from "../Shared/ExplorerSettings";
|
import * as ExplorerSettings from "../Shared/ExplorerSettings";
|
||||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||||
|
@ -50,7 +51,7 @@ import * as FileSystemUtil from "./Notebook/FileSystemUtil";
|
||||||
import { SnapshotRequest } from "./Notebook/NotebookComponent/types";
|
import { SnapshotRequest } from "./Notebook/NotebookComponent/types";
|
||||||
import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem";
|
import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem";
|
||||||
import type NotebookManager from "./Notebook/NotebookManager";
|
import type NotebookManager from "./Notebook/NotebookManager";
|
||||||
import type { NotebookPaneContent } from "./Notebook/NotebookManager";
|
import { NotebookPaneContent } from "./Notebook/NotebookManager";
|
||||||
import { NotebookUtil } from "./Notebook/NotebookUtil";
|
import { NotebookUtil } from "./Notebook/NotebookUtil";
|
||||||
import { useNotebook } from "./Notebook/useNotebook";
|
import { useNotebook } from "./Notebook/useNotebook";
|
||||||
import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
|
import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
|
||||||
|
@ -178,7 +179,11 @@ export default class Explorer {
|
||||||
this.resourceTree = new ResourceTreeAdapter(this);
|
this.resourceTree = new ResourceTreeAdapter(this);
|
||||||
|
|
||||||
// Override notebook server parameters from URL parameters
|
// Override notebook server parameters from URL parameters
|
||||||
if (userContext.features.notebookServerUrl && userContext.features.notebookServerToken) {
|
if (
|
||||||
|
userContext.features.notebookServerUrl &&
|
||||||
|
validateEndpoint(userContext.features.notebookServerUrl, allowedNotebookServerUrls) &&
|
||||||
|
userContext.features.notebookServerToken
|
||||||
|
) {
|
||||||
useNotebook.getState().setNotebookServerInfo({
|
useNotebook.getState().setNotebookServerInfo({
|
||||||
notebookServerEndpoint: userContext.features.notebookServerUrl,
|
notebookServerEndpoint: userContext.features.notebookServerUrl,
|
||||||
authToken: userContext.features.notebookServerToken,
|
authToken: userContext.features.notebookServerToken,
|
||||||
|
@ -190,19 +195,6 @@ export default class Explorer {
|
||||||
useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath);
|
useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userContext.features.livyEndpoint) {
|
|
||||||
useNotebook.getState().setSparkClusterConnectionInfo({
|
|
||||||
userName: undefined,
|
|
||||||
password: undefined,
|
|
||||||
endpoints: [
|
|
||||||
{
|
|
||||||
endpoint: userContext.features.livyEndpoint,
|
|
||||||
kind: DataModels.SparkClusterEndpointKind.Livy,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.refreshExplorer();
|
this.refreshExplorer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +414,10 @@ export default class Explorer {
|
||||||
connectionStatus.status = ConnectionStatusType.Connected;
|
connectionStatus.status = ConnectionStatusType.Connected;
|
||||||
useNotebook.getState().setConnectionInfo(connectionStatus);
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
useNotebook.getState().setNotebookServerInfo({
|
useNotebook.getState().setNotebookServerInfo({
|
||||||
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.data.notebookServerUrl,
|
notebookServerEndpoint:
|
||||||
|
(validateEndpoint(userContext.features.notebookServerUrl, allowedNotebookServerUrls) &&
|
||||||
|
userContext.features.notebookServerUrl) ||
|
||||||
|
connectionInfo.data.notebookServerUrl,
|
||||||
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
||||||
forwardingId: connectionInfo.data.forwardingId,
|
forwardingId: connectionInfo.data.forwardingId,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
|
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointValidation";
|
||||||
import { GetGithubClientId } from "Utils/GitHubUtils";
|
import { GetGithubClientId } from "Utils/GitHubUtils";
|
||||||
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
|
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
|
||||||
import { configContext } from "../ConfigContext";
|
import { configContext } from "../ConfigContext";
|
||||||
|
@ -484,7 +485,7 @@ export class JunoClient {
|
||||||
// public for tests
|
// public for tests
|
||||||
public static getJunoEndpoint(): string {
|
public static getJunoEndpoint(): string {
|
||||||
const junoEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
const junoEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
||||||
if (configContext.allowedJunoOrigins.indexOf(new URL(junoEndpoint).origin) === -1) {
|
if (!validateEndpoint(junoEndpoint, allowedJunoOrigins)) {
|
||||||
const error = `${junoEndpoint} not allowed as juno endpoint`;
|
const error = `${junoEndpoint} not allowed as juno endpoint`;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import promiseRetry, { AbortError } from "p-retry";
|
import promiseRetry, { AbortError } from "p-retry";
|
||||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointValidation";
|
||||||
import {
|
import {
|
||||||
Areas,
|
Areas,
|
||||||
ConnectionStatusType,
|
ConnectionStatusType,
|
||||||
|
@ -154,7 +155,7 @@ export class PhoenixClient {
|
||||||
public static getPhoenixEndpoint(): string {
|
public static getPhoenixEndpoint(): string {
|
||||||
const phoenixEndpoint =
|
const phoenixEndpoint =
|
||||||
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
||||||
if (configContext.allowedJunoOrigins.indexOf(new URL(phoenixEndpoint).origin) === -1) {
|
if (!validateEndpoint(phoenixEndpoint, allowedJunoOrigins)) {
|
||||||
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
|
|
|
@ -23,7 +23,6 @@ export type Features = {
|
||||||
readonly hostedDataExplorer: boolean;
|
readonly hostedDataExplorer: boolean;
|
||||||
readonly junoEndpoint?: string;
|
readonly junoEndpoint?: string;
|
||||||
readonly phoenixEndpoint?: string;
|
readonly phoenixEndpoint?: string;
|
||||||
readonly livyEndpoint?: string;
|
|
||||||
readonly notebookBasePath?: string;
|
readonly notebookBasePath?: string;
|
||||||
readonly notebookServerToken?: string;
|
readonly notebookServerToken?: string;
|
||||||
readonly notebookServerUrl?: string;
|
readonly notebookServerUrl?: string;
|
||||||
|
@ -72,7 +71,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
||||||
mongoProxyAPIs: get("mongoproxyapis"),
|
mongoProxyAPIs: get("mongoproxyapis"),
|
||||||
junoEndpoint: get("junoendpoint"),
|
junoEndpoint: get("junoendpoint"),
|
||||||
phoenixEndpoint: get("phoenixendpoint"),
|
phoenixEndpoint: get("phoenixendpoint"),
|
||||||
livyEndpoint: get("livyendpoint"),
|
|
||||||
notebookBasePath: get("notebookbasepath"),
|
notebookBasePath: get("notebookbasepath"),
|
||||||
notebookServerToken: get("notebookservertoken"),
|
notebookServerToken: get("notebookservertoken"),
|
||||||
notebookServerUrl: get("notebookserverurl"),
|
notebookServerUrl: get("notebookserverurl"),
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { JunoEndpoints } from "Common/Constants";
|
||||||
|
import * as Logger from "../Common/Logger";
|
||||||
|
|
||||||
|
export function validateEndpoint(
|
||||||
|
endpointToValidate: string | undefined,
|
||||||
|
allowedEndpoints: ReadonlyArray<string>
|
||||||
|
): boolean {
|
||||||
|
try {
|
||||||
|
return validateEndpointInternal(
|
||||||
|
endpointToValidate,
|
||||||
|
allowedEndpoints.map((e) => e)
|
||||||
|
);
|
||||||
|
} catch (reason) {
|
||||||
|
Logger.logError(`${endpointToValidate} not allowed`, "validateEndpoint");
|
||||||
|
Logger.logError(`${JSON.stringify(reason)}`, "validateEndpoint");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateEndpointInternal(
|
||||||
|
endpointToValidate: string | undefined,
|
||||||
|
allowedEndpoints: ReadonlyArray<string>
|
||||||
|
): boolean {
|
||||||
|
if (endpointToValidate === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const originToValidate: string = new URL(endpointToValidate).origin;
|
||||||
|
const allowedOrigins: string[] = allowedEndpoints.map((allowedEndpoint) => new URL(allowedEndpoint).origin) || [];
|
||||||
|
const valid = allowedOrigins.indexOf(originToValidate) >= 0;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
throw new Error(
|
||||||
|
`${endpointToValidate} is not an allowed endpoint. Allowed endpoints are ${allowedArmEndpoints.toString()}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const allowedArmEndpoints: ReadonlyArray<string> = [
|
||||||
|
"https://management.azure.com",
|
||||||
|
"https://management.usgovcloudapi.net",
|
||||||
|
"https://management.chinacloudapi.cn",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const allowedAadEndpoints: ReadonlyArray<string> = ["https://login.microsoftonline.com/"];
|
||||||
|
|
||||||
|
export const allowedBackendEndpoints: ReadonlyArray<string> = [
|
||||||
|
"https://main.documentdb.ext.azure.com",
|
||||||
|
"https://localhost:12901",
|
||||||
|
"https://localhost:1234",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
||||||
|
"https://main.documentdb.ext.azure.com",
|
||||||
|
"https://localhost:12901",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const allowedEmulatorEndpoints: ReadonlyArray<string> = ["https://localhost:8081"];
|
||||||
|
|
||||||
|
export const allowedMongoBackendEndpoints: ReadonlyArray<string> = ["https://localhost:1234"];
|
||||||
|
|
||||||
|
export const allowedGraphEndpoints: ReadonlyArray<string> = ["https://graph.windows.net"];
|
||||||
|
|
||||||
|
export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"];
|
||||||
|
|
||||||
|
export const allowedHostedExplorerEndpoints: ReadonlyArray<string> = ["https://cosmos.azure.com/"];
|
||||||
|
|
||||||
|
export const allowedMsalRedirectEndpoints: ReadonlyArray<string> = [
|
||||||
|
"https://cosmos-explorer-preview.azurewebsites.net/",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const allowedJunoOrigins: ReadonlyArray<string> = [
|
||||||
|
JunoEndpoints.Test,
|
||||||
|
JunoEndpoints.Test2,
|
||||||
|
JunoEndpoints.Test3,
|
||||||
|
JunoEndpoints.Prod,
|
||||||
|
JunoEndpoints.Stage,
|
||||||
|
"https://localhost",
|
||||||
|
];
|
||||||
|
|
||||||
|
export const allowedNotebookServerUrls: ReadonlyArray<string> = [];
|
|
@ -4,7 +4,7 @@ export function isInvalidParentFrameOrigin(event: MessageEvent): boolean {
|
||||||
return !isValidOrigin(configContext.allowedParentFrameOrigins, event);
|
return !isValidOrigin(configContext.allowedParentFrameOrigins, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidOrigin(allowedOrigins: string[], event: MessageEvent): boolean {
|
function isValidOrigin(allowedOrigins: ReadonlyArray<string>, event: MessageEvent): boolean {
|
||||||
const eventOrigin = (event && event.origin) || "";
|
const eventOrigin = (event && event.origin) || "";
|
||||||
const windowOrigin = (window && window.origin) || "";
|
const windowOrigin = (window && window.origin) || "";
|
||||||
if (eventOrigin === windowOrigin) {
|
if (eventOrigin === windowOrigin) {
|
||||||
|
|
Loading…
Reference in New Issue