mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-21 01:41:31 +00:00
Checkpoint
This commit is contained in:
@@ -241,7 +241,6 @@ src/Platform/Hosted/Authorization.ts
|
||||
src/Platform/Hosted/DataAccessUtility.ts
|
||||
src/Platform/Hosted/ExplorerFactory.ts
|
||||
src/Platform/Hosted/Helpers/ConnectionStringParser.test.ts
|
||||
src/Platform/Hosted/Helpers/ConnectionStringParser.ts
|
||||
src/Platform/Hosted/HostedUtils.test.ts
|
||||
src/Platform/Hosted/HostedUtils.ts
|
||||
src/Platform/Hosted/Main.ts
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { DatabaseAccount, Subscription } from "../../../Contracts/DataModels";
|
||||
|
||||
import * as React from "react";
|
||||
import { DefaultButton, IButtonStyles, IButtonProps } from "office-ui-fabric-react/lib/Button";
|
||||
import { IContextualMenuProps } from "office-ui-fabric-react/lib/ContextualMenu";
|
||||
import { Dropdown, IDropdownOption, IDropdownProps } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { Dropdown, IDropdownProps } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { useSubscriptions } from "../../../hooks/useSubscriptions";
|
||||
import { useDatabaseAccounts } from "../../../hooks/useDatabaseAccounts";
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import * as React from "react";
|
||||
import { render } from "react-dom";
|
||||
import FeedbackIcon from "../images/Feedback.svg";
|
||||
import ConnectIcon from "../images/HostedConnectwhite.svg";
|
||||
import ChevronRight from "../images/chevron-right.svg";
|
||||
import "../less/hostedexplorer.less";
|
||||
import { CommandButtonComponent } from "./Explorer/Controls/CommandButton/CommandButtonComponent";
|
||||
import "./Explorer/Menus/NavBar/MeControlComponent.less";
|
||||
@@ -22,12 +21,17 @@ import { useGraphPhoto } from "./hooks/useGraphPhoto";
|
||||
import "./Shared/appInsights";
|
||||
import { AccountSwitchComponent } from "./Explorer/Controls/AccountSwitch/AccountSwitchComponent";
|
||||
import { AuthContext, AuthProvider } from "./contexts/authContext";
|
||||
import { usePortalAccessToken } from "./hooks/usePortalAccessToken";
|
||||
import { AuthType } from "./AuthType";
|
||||
|
||||
initializeIcons();
|
||||
|
||||
const App: React.FunctionComponent = () => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const encryptedToken = params && params.get("key");
|
||||
const encryptedTokenMetadata = usePortalAccessToken(encryptedToken);
|
||||
const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false);
|
||||
const { isLoggedIn, login, account, logout } = React.useContext(AuthContext);
|
||||
const { isLoggedIn, aadlogin: login, account, aadlogout: logout } = React.useContext(AuthContext);
|
||||
const [isConnectionStringVisible, { setTrue: showConnectionString }] = useBoolean(false);
|
||||
const photo = useGraphPhoto();
|
||||
|
||||
@@ -121,11 +125,17 @@ const App: React.FunctionComponent = () => {
|
||||
Microsoft Azure
|
||||
</span>
|
||||
<span className="accontSplitter" /> <span className="serviceTitle">Cosmos DB</span>
|
||||
{isLoggedIn && <img className="chevronRight" src={ChevronRight} alt="account separator" />}
|
||||
{(isLoggedIn || encryptedTokenMetadata?.accountName) && (
|
||||
<img className="chevronRight" src={ChevronRight} alt="account separator" />
|
||||
)}
|
||||
{isLoggedIn && (
|
||||
<span className="accountSwitchComponentContainer">
|
||||
<AccountSwitchComponent />
|
||||
<span className="accountNameHeader">REPLACE ME - Connection string mode</span>;
|
||||
</span>
|
||||
)}
|
||||
{!isLoggedIn && encryptedTokenMetadata?.accountName && (
|
||||
<span className="accountSwitchComponentContainer">
|
||||
<span className="accountNameHeader">{encryptedTokenMetadata?.accountName}</span>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -186,9 +196,27 @@ const App: React.FunctionComponent = () => {
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{isLoggedIn ? (
|
||||
<p>LOGGED IN!</p>
|
||||
) : (
|
||||
{encryptedTokenMetadata && !isLoggedIn && (
|
||||
<iframe
|
||||
id="explorerMenu"
|
||||
name="explorer"
|
||||
className="iframe"
|
||||
title="explorer"
|
||||
src={`explorer.html?v=1.0.1&platform=Hosted&authType=${AuthType.EncryptedToken}&key=${encodeURIComponent(
|
||||
encryptedToken
|
||||
)}&metadata=${JSON.stringify(encryptedTokenMetadata)}`}
|
||||
></iframe>
|
||||
)}
|
||||
{!encryptedTokenMetadata && isLoggedIn && (
|
||||
<iframe
|
||||
id="explorerMenu"
|
||||
name="explorer"
|
||||
className="iframe"
|
||||
title="explorer"
|
||||
src={`explorer.html?v=1.0.1&platform=Hosted&authType=${AuthType.AAD}`}
|
||||
></iframe>
|
||||
)}
|
||||
{!isLoggedIn && !encryptedTokenMetadata && (
|
||||
<div id="connectExplorer" className="connectExplorerContainer" style={{ display: "flex" }}>
|
||||
<div className="connectExplorerFormContainer">
|
||||
<div className="connectExplorer">
|
||||
@@ -227,13 +255,6 @@ const App: React.FunctionComponent = () => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* <iframe
|
||||
id="explorerMenu"
|
||||
name="explorer"
|
||||
className="iframe"
|
||||
title="explorer"
|
||||
src="explorer.html?v=1.0.1&platform=Portal"
|
||||
></iframe> */}
|
||||
<div data-bind="react: firewallWarningComponentAdapter" />
|
||||
<div data-bind="react: dialogComponentAdapter" />
|
||||
<Panel headerText="Select Directory" isOpen={isOpen} onDismiss={dismissPanel} closeButtonAriaLabel="Close">
|
||||
|
||||
36
src/Main.tsx
36
src/Main.tsx
@@ -84,42 +84,16 @@ window.authType = AuthType.AAD;
|
||||
const App: React.FunctionComponent = () => {
|
||||
useEffect(() => {
|
||||
initializeConfiguration().then(config => {
|
||||
let explorer: Explorer;
|
||||
if (config.platform === Platform.Hosted) {
|
||||
try {
|
||||
Hosted.initializeExplorer().then(
|
||||
(explorer: Explorer) => {
|
||||
applyExplorerBindings(explorer);
|
||||
Hosted.configureTokenValidationDisplayPrompt(explorer);
|
||||
},
|
||||
(error: unknown) => {
|
||||
try {
|
||||
const uninitializedExplorer: Explorer = Hosted.getUninitializedExplorerForGuestAccess();
|
||||
window.dataExplorer = uninitializedExplorer;
|
||||
ko.applyBindings(uninitializedExplorer);
|
||||
BindingHandlersRegisterer.registerBindingHandlers();
|
||||
if (window.authType !== AuthType.AAD) {
|
||||
uninitializedExplorer.isRefreshingExplorer(false);
|
||||
uninitializedExplorer.displayConnectExplorerForm();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
console.error(error);
|
||||
}
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
explorer = Hosted.initializeExplorer();
|
||||
} else if (config.platform === Platform.Emulator) {
|
||||
window.authType = AuthType.MasterKey;
|
||||
const explorer = Emulator.initializeExplorer();
|
||||
applyExplorerBindings(explorer);
|
||||
explorer = Emulator.initializeExplorer();
|
||||
} else if (config.platform === Platform.Portal) {
|
||||
TelemetryProcessor.trace(Action.InitializeDataExplorer, ActionModifiers.Open, {});
|
||||
const explorer = Portal.initializeExplorer();
|
||||
TelemetryProcessor.trace(Action.InitializeDataExplorer, ActionModifiers.IFrameReady, {});
|
||||
applyExplorerBindings(explorer);
|
||||
explorer = Portal.initializeExplorer();
|
||||
}
|
||||
applyExplorerBindings(explorer);
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import { ConnectionStringParser } from "./ConnectionStringParser";
|
||||
import { parseConnectionString } from "./ConnectionStringParser";
|
||||
|
||||
describe("ConnectionStringParser", () => {
|
||||
const mockAccountName: string = "Test";
|
||||
const mockMasterKey: string = "some-key";
|
||||
|
||||
it("should parse a valid sql account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`AccountEndpoint=https://${mockAccountName}.documents.azure.com:443/;AccountKey=${mockMasterKey};`
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid mongo account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`mongodb://${mockAccountName}:${mockMasterKey}@${mockAccountName}.documents.azure.com:10255`
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid compute mongo account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`mongodb://${mockAccountName}:${mockMasterKey}@${mockAccountName}.mongo.cosmos.azure.com:10255`
|
||||
);
|
||||
|
||||
@@ -33,7 +33,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid graph account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`AccountEndpoint=https://${mockAccountName}.documents.azure.com:443/;AccountKey=${mockMasterKey};ApiKind=Gremlin;`
|
||||
);
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid table account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`DefaultEndpointsProtocol=https;AccountName=${mockAccountName};AccountKey=${mockMasterKey};TableEndpoint=https://${mockAccountName}.table.cosmosdb.azure.com:443/;`
|
||||
);
|
||||
|
||||
@@ -51,7 +51,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid cassandra account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`AccountEndpoint=${mockAccountName}.cassandra.cosmosdb.azure.com;AccountKey=${mockMasterKey};`
|
||||
);
|
||||
|
||||
@@ -60,15 +60,13 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should fail to parse an invalid connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
"some-rogue-connection-string"
|
||||
);
|
||||
const metadata = parseConnectionString("some-rogue-connection-string");
|
||||
|
||||
expect(metadata).toBe(undefined);
|
||||
});
|
||||
|
||||
it("should fail to parse an empty connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString("");
|
||||
const metadata = parseConnectionString("");
|
||||
|
||||
expect(metadata).toBe(undefined);
|
||||
});
|
||||
|
||||
@@ -1,37 +1,36 @@
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import { AccessInputMetadata, ApiKind } from "../../../Contracts/DataModels";
|
||||
|
||||
export class ConnectionStringParser {
|
||||
public static parseConnectionString(connectionString: string): DataModels.AccessInputMetadata {
|
||||
if (!!connectionString) {
|
||||
export function parseConnectionString(connectionString: string): AccessInputMetadata {
|
||||
if (connectionString) {
|
||||
try {
|
||||
const accessInput: DataModels.AccessInputMetadata = {} as DataModels.AccessInputMetadata;
|
||||
const accessInput = {} as AccessInputMetadata;
|
||||
const connectionStringParts = connectionString.split(";");
|
||||
|
||||
connectionStringParts.forEach((connectionStringPart: string) => {
|
||||
if (RegExp(Constants.EndpointsRegex.sql).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.sql)[1];
|
||||
accessInput.apiKind = DataModels.ApiKind.SQL;
|
||||
accessInput.apiKind = ApiKind.SQL;
|
||||
} else if (RegExp(Constants.EndpointsRegex.mongo).test(connectionStringPart)) {
|
||||
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongo);
|
||||
accessInput.accountName = matches && matches.length > 1 && matches[2];
|
||||
accessInput.apiKind = DataModels.ApiKind.MongoDB;
|
||||
accessInput.apiKind = ApiKind.MongoDB;
|
||||
} else if (RegExp(Constants.EndpointsRegex.mongoCompute).test(connectionStringPart)) {
|
||||
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongoCompute);
|
||||
accessInput.accountName = matches && matches.length > 1 && matches[2];
|
||||
accessInput.apiKind = DataModels.ApiKind.MongoDBCompute;
|
||||
accessInput.apiKind = ApiKind.MongoDBCompute;
|
||||
} else if (Constants.EndpointsRegex.cassandra.some(regex => RegExp(regex).test(connectionStringPart))) {
|
||||
Constants.EndpointsRegex.cassandra.forEach(regex => {
|
||||
if (RegExp(regex).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(regex)[1];
|
||||
accessInput.apiKind = DataModels.ApiKind.Cassandra;
|
||||
accessInput.apiKind = ApiKind.Cassandra;
|
||||
}
|
||||
});
|
||||
} else if (RegExp(Constants.EndpointsRegex.table).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.table)[1];
|
||||
accessInput.apiKind = DataModels.ApiKind.Table;
|
||||
accessInput.apiKind = ApiKind.Table;
|
||||
} else if (connectionStringPart.indexOf("ApiKind=Gremlin") >= 0) {
|
||||
accessInput.apiKind = DataModels.ApiKind.Graph;
|
||||
accessInput.apiKind = ApiKind.Graph;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -46,5 +45,4 @@ export class ConnectionStringParser {
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,84 +43,40 @@ export default class Main {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static initializeExplorer(): Q.Promise<Explorer> {
|
||||
public static initializeExplorer(): Explorer {
|
||||
window.addEventListener("message", this._handleMessage.bind(this), false);
|
||||
this._features = {};
|
||||
const params = new URLSearchParams(window.parent.location.search);
|
||||
const deferred: Q.Deferred<Explorer> = Q.defer<Explorer>();
|
||||
let authType: string = null;
|
||||
|
||||
// Encrypted token flow
|
||||
if (!!params && params.has("key")) {
|
||||
Main._encryptedToken = encodeURIComponent(params.get("key"));
|
||||
SessionStorageUtility.setEntryString(StorageKey.EncryptedKeyToken, Main._encryptedToken);
|
||||
authType = AuthType.EncryptedToken;
|
||||
} else if (Main._hasCachedEncryptedKey()) {
|
||||
Main._encryptedToken = SessionStorageUtility.getEntryString(StorageKey.EncryptedKeyToken);
|
||||
authType = AuthType.EncryptedToken;
|
||||
}
|
||||
|
||||
// Aad flow
|
||||
if (AuthHeadersUtil.isUserSignedIn()) {
|
||||
authType = AuthType.AAD;
|
||||
}
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
let authType: string = params && params.get("authType");
|
||||
|
||||
if (params) {
|
||||
this._features = Main.extractFeatures(params);
|
||||
}
|
||||
|
||||
// Encrypted token flow
|
||||
if (params && params.has("key")) {
|
||||
Main._encryptedToken = encodeURIComponent(params.get("key"));
|
||||
Main._accessInputMetadata = JSON.parse(params.get("metadata"));
|
||||
authType = AuthType.EncryptedToken;
|
||||
}
|
||||
|
||||
(<any>window).authType = authType;
|
||||
if (!authType) {
|
||||
return Q.reject("Sign in needed");
|
||||
throw new Error("Sign in needed");
|
||||
}
|
||||
|
||||
const explorer: Explorer = this._instantiateExplorer();
|
||||
if (authType === AuthType.EncryptedToken) {
|
||||
sendMessage({
|
||||
type: MessageTypes.UpdateAccountSwitch,
|
||||
props: {
|
||||
authType: AuthType.EncryptedToken,
|
||||
displayText: "Loading..."
|
||||
}
|
||||
});
|
||||
updateUserContext({
|
||||
accessToken: Main._encryptedToken
|
||||
});
|
||||
Main._getAccessInputMetadata(Main._encryptedToken).then(
|
||||
() => {
|
||||
const expiryTimestamp: number =
|
||||
Main._accessInputMetadata && parseInt(Main._accessInputMetadata.expiryTimestamp);
|
||||
if (authType === AuthType.EncryptedToken && (isNaN(expiryTimestamp) || expiryTimestamp <= 0)) {
|
||||
return deferred.reject("Token expired");
|
||||
}
|
||||
|
||||
Main._initDataExplorerFrameInputs(explorer);
|
||||
deferred.resolve(explorer);
|
||||
},
|
||||
(error: any) => {
|
||||
console.error(error);
|
||||
deferred.reject(error);
|
||||
}
|
||||
);
|
||||
} else if (authType === AuthType.AAD) {
|
||||
sendMessage({
|
||||
type: MessageTypes.GetAccessAadRequest
|
||||
});
|
||||
if (this._getAadAccessDeferred != null) {
|
||||
// already request aad access, don't duplicate
|
||||
return Q(null);
|
||||
}
|
||||
this._explorer = explorer;
|
||||
this._getAadAccessDeferred = Q.defer<Explorer>();
|
||||
return this._getAadAccessDeferred.promise.finally(() => {
|
||||
this._getAadAccessDeferred = null;
|
||||
});
|
||||
} else {
|
||||
Main._initDataExplorerFrameInputs(explorer);
|
||||
deferred.resolve(explorer);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return explorer;
|
||||
}
|
||||
|
||||
public static extractFeatures(params: URLSearchParams): { [key: string]: string } {
|
||||
@@ -137,21 +93,6 @@ export default class Main {
|
||||
return features;
|
||||
}
|
||||
|
||||
public static configureTokenValidationDisplayPrompt(explorer: Explorer): void {
|
||||
const authType: AuthType = (<any>window).authType;
|
||||
if (
|
||||
!explorer ||
|
||||
!Main._encryptedToken ||
|
||||
!Main._accessInputMetadata ||
|
||||
Main._accessInputMetadata.expiryTimestamp == null ||
|
||||
authType !== AuthType.EncryptedToken
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
Main._showGuestAccessTokenRenewalPromptInMs(explorer, parseInt(Main._accessInputMetadata.expiryTimestamp));
|
||||
}
|
||||
|
||||
public static parseResourceTokenConnectionString(connectionString: string): resourceTokenConnectionStringProperties {
|
||||
let accountEndpoint: string;
|
||||
let collectionId: string;
|
||||
@@ -234,7 +175,6 @@ export default class Main {
|
||||
}
|
||||
|
||||
const masterKey: string = Main._getMasterKeyFromConnectionString(connectionString);
|
||||
Main.configureTokenValidationDisplayPrompt(explorer);
|
||||
Main._setExplorerReady(explorer, masterKey);
|
||||
|
||||
deferred.resolve();
|
||||
@@ -398,14 +338,6 @@ export default class Main {
|
||||
return explorer;
|
||||
}
|
||||
|
||||
private static _showGuestAccessTokenRenewalPromptInMs(explorer: Explorer, interval: number): void {
|
||||
if (interval != null && !isNaN(interval)) {
|
||||
setTimeout(() => {
|
||||
explorer.displayGuestAccessTokenRenewalPrompt();
|
||||
}, interval);
|
||||
}
|
||||
}
|
||||
|
||||
private static _hasCachedEncryptedKey(): boolean {
|
||||
return SessionStorageUtility.hasItem(StorageKey.EncryptedKeyToken);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ const msal = new Msal.UserAgentApplication({
|
||||
auth: {
|
||||
authority: "https://login.microsoft.com/common",
|
||||
clientId: "203f1145-856a-4232-83d4-a43568fba23d",
|
||||
redirectUri: "https://dataexplorer-dev.azurewebsites.net"
|
||||
redirectUri: "https://dataexplorer-dev.azurewebsites.net" // TODO! This should only be set development
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,16 +18,16 @@ interface AuthContext {
|
||||
account?: Msal.Account;
|
||||
graphToken?: string;
|
||||
armToken?: string;
|
||||
logout: () => unknown;
|
||||
login: () => unknown;
|
||||
aadlogout: () => unknown;
|
||||
aadlogin: () => unknown;
|
||||
}
|
||||
|
||||
export const AuthContext = createContext<AuthContext>({
|
||||
isLoggedIn: false,
|
||||
login: () => {
|
||||
aadlogin: () => {
|
||||
throw Error(defaultError);
|
||||
},
|
||||
logout: () => {
|
||||
aadlogout: () => {
|
||||
throw Error(defaultError);
|
||||
}
|
||||
});
|
||||
@@ -38,36 +38,27 @@ export const AuthProvider: React.FunctionComponent = ({ children }) => {
|
||||
const [graphToken, setGraphToken] = useState<string>();
|
||||
const [armToken, setArmToken] = useState<string>();
|
||||
|
||||
const login = useCallback(() => {
|
||||
msal.loginPopup().then(response => {
|
||||
const aadlogin = useCallback(async () => {
|
||||
const response = await msal.loginPopup();
|
||||
setLoggedIn();
|
||||
setAccount(response.account);
|
||||
msal
|
||||
.acquireTokenSilent({ scopes: ["https://graph.windows.net//.default"] })
|
||||
.then(resp => {
|
||||
setGraphToken(resp.accessToken);
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
msal
|
||||
.acquireTokenSilent({ scopes: ["https://management.azure.com//.default"] })
|
||||
.then(resp => {
|
||||
setArmToken(resp.accessToken);
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
});
|
||||
|
||||
const [graphTokenResponse, armTokenResponse] = await Promise.all([
|
||||
msal.acquireTokenSilent({ scopes: ["https://graph.windows.net//.default"] }),
|
||||
msal.acquireTokenSilent({ scopes: ["https://management.azure.com//.default"] })
|
||||
]);
|
||||
|
||||
setGraphToken(graphTokenResponse.accessToken);
|
||||
setArmToken(armTokenResponse.accessToken);
|
||||
}, []);
|
||||
|
||||
const logout = useCallback(() => {
|
||||
const aadlogout = useCallback(() => {
|
||||
msal.logout();
|
||||
setLoggedOut();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={{ isLoggedIn, account, login, logout, graphToken, armToken }}>
|
||||
<AuthContext.Provider value={{ isLoggedIn, account, aadlogin, aadlogout, graphToken, armToken }}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
|
||||
36
src/hooks/usePortalAccessToken.tsx
Normal file
36
src/hooks/usePortalAccessToken.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { ApiEndpoints } from "../Common/Constants";
|
||||
import { configContext } from "../ConfigContext";
|
||||
import { AccessInputMetadata } from "../Contracts/DataModels";
|
||||
|
||||
const url = `${configContext.BACKEND_ENDPOINT}${ApiEndpoints.guestRuntimeProxy}/accessinputmetadata?_=1609359229955`;
|
||||
|
||||
export async function fetchAccessData(portalToken: string): Promise<AccessInputMetadata> {
|
||||
const headers = new Headers();
|
||||
// Portal encrypted token API quirk: The token header must be URL encoded
|
||||
headers.append("x-ms-encrypted-auth-token", encodeURIComponent(portalToken));
|
||||
|
||||
const options = {
|
||||
method: "GET",
|
||||
headers: headers
|
||||
};
|
||||
|
||||
return (
|
||||
fetch(url, options)
|
||||
.then(response => response.json())
|
||||
// Portal encrypted token API quirk: The response is double JSON encoded
|
||||
.then(json => JSON.parse(json))
|
||||
.catch(error => console.log(error))
|
||||
);
|
||||
}
|
||||
|
||||
export function usePortalAccessToken(token: string): AccessInputMetadata {
|
||||
const [state, setState] = useState<AccessInputMetadata>();
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
fetchAccessData(token).then(response => setState(response));
|
||||
}
|
||||
}, [token]);
|
||||
return state;
|
||||
}
|
||||
Reference in New Issue
Block a user