2020-05-25 21:30:55 -05:00
|
|
|
import * as Cosmos from "@azure/cosmos";
|
|
|
|
import { RequestInfo, setAuthorizationTokenHeaderUsingMasterKey } from "@azure/cosmos";
|
2020-08-06 14:03:46 -05:00
|
|
|
import { configContext, Platform } from "../ConfigContext";
|
|
|
|
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
|
|
|
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
|
|
|
import { userContext } from "../UserContext";
|
2020-05-25 21:30:55 -05:00
|
|
|
|
|
|
|
const _global = typeof self === "undefined" ? window : self;
|
|
|
|
|
|
|
|
export const tokenProvider = async (requestInfo: RequestInfo) => {
|
|
|
|
const { verb, resourceId, resourceType, headers } = requestInfo;
|
2020-08-06 14:03:46 -05:00
|
|
|
if (configContext.platform === Platform.Emulator) {
|
2020-06-10 16:08:05 -05:00
|
|
|
// TODO This SDK method mutates the headers object. Find a better one or fix the SDK.
|
|
|
|
await setAuthorizationTokenHeaderUsingMasterKey(verb, resourceId, resourceType, headers, EmulatorMasterKey);
|
|
|
|
return decodeURIComponent(headers.authorization);
|
2020-05-25 21:30:55 -05:00
|
|
|
}
|
|
|
|
|
2020-08-06 14:03:46 -05:00
|
|
|
if (userContext.masterKey) {
|
2020-06-10 16:08:05 -05:00
|
|
|
// TODO This SDK method mutates the headers object. Find a better one or fix the SDK.
|
|
|
|
await setAuthorizationTokenHeaderUsingMasterKey(verb, resourceId, resourceType, headers, EmulatorMasterKey);
|
|
|
|
return decodeURIComponent(headers.authorization);
|
2020-05-25 21:30:55 -05:00
|
|
|
}
|
|
|
|
|
2020-08-06 14:03:46 -05:00
|
|
|
if (userContext.resourceToken) {
|
|
|
|
return userContext.resourceToken;
|
2020-05-25 21:30:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
const result = await getTokenFromAuthService(verb, resourceType, resourceId);
|
|
|
|
headers[HttpHeaders.msDate] = result.XDate;
|
|
|
|
return decodeURIComponent(result.PrimaryReadWriteToken);
|
|
|
|
};
|
|
|
|
|
|
|
|
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, next) => {
|
2020-08-06 14:03:46 -05:00
|
|
|
requestContext.endpoint = configContext.PROXY_PATH;
|
2020-05-25 21:30:55 -05:00
|
|
|
requestContext.headers["x-ms-proxy-target"] = endpoint();
|
|
|
|
return next(requestContext);
|
|
|
|
};
|
|
|
|
|
|
|
|
export const endpoint = () => {
|
2020-08-06 14:03:46 -05:00
|
|
|
if (configContext.platform === Platform.Emulator) {
|
2020-06-10 16:08:05 -05:00
|
|
|
// In worker scope, _global(self).parent does not exist
|
|
|
|
const location = _global.parent ? _global.parent.location : _global.location;
|
2020-08-06 14:03:46 -05:00
|
|
|
return configContext.EMULATOR_ENDPOINT || location.origin;
|
2020-05-25 21:30:55 -05:00
|
|
|
}
|
2020-08-06 14:03:46 -05:00
|
|
|
return (
|
|
|
|
userContext.endpoint ||
|
|
|
|
(userContext.databaseAccount &&
|
|
|
|
userContext.databaseAccount.properties &&
|
|
|
|
userContext.databaseAccount.properties.documentEndpoint)
|
|
|
|
);
|
2020-05-25 21:30:55 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> {
|
|
|
|
try {
|
2020-08-06 14:03:46 -05:00
|
|
|
const host = configContext.BACKEND_ENDPOINT || _global.dataExplorer.extensionEndpoint();
|
2020-05-25 21:30:55 -05:00
|
|
|
const response = await _global.fetch(host + "/api/guest/runtimeproxy/authorizationTokens", {
|
|
|
|
method: "POST",
|
|
|
|
headers: {
|
|
|
|
"content-type": "application/json",
|
2020-08-06 14:03:46 -05:00
|
|
|
"x-ms-encrypted-auth-token": userContext.accessToken
|
2020-05-25 21:30:55 -05:00
|
|
|
},
|
|
|
|
body: JSON.stringify({
|
|
|
|
verb,
|
|
|
|
resourceType,
|
|
|
|
resourceId
|
|
|
|
})
|
|
|
|
});
|
|
|
|
//TODO I am not sure why we have to parse the JSON again here. fetch should do it for us when we call .json()
|
|
|
|
const result = JSON.parse(await response.json());
|
|
|
|
return result;
|
|
|
|
} catch (error) {
|
2020-08-06 14:03:46 -05:00
|
|
|
logConsoleError(`Failed to get authorization headers for ${resourceType}: ${JSON.stringify(error)}`);
|
2020-05-25 21:30:55 -05:00
|
|
|
return Promise.reject(error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-06 14:03:46 -05:00
|
|
|
export function client(): Cosmos.CosmosClient {
|
|
|
|
const options: Cosmos.CosmosClientOptions = {
|
|
|
|
endpoint: endpoint() || " ", // CosmosClient gets upset if we pass a falsy value here
|
|
|
|
key: userContext.masterKey,
|
|
|
|
tokenProvider,
|
|
|
|
connectionPolicy: {
|
|
|
|
enableEndpointDiscovery: false
|
|
|
|
},
|
|
|
|
userAgentSuffix: "Azure Portal"
|
|
|
|
};
|
|
|
|
|
|
|
|
// In development we proxy requests to the backend via webpack. This is removed in production bundles.
|
|
|
|
if (process.env.NODE_ENV === "development") {
|
|
|
|
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
|
2020-05-25 21:30:55 -05:00
|
|
|
}
|
2020-08-06 14:03:46 -05:00
|
|
|
return new Cosmos.CosmosClient(options);
|
|
|
|
}
|