src/components/operations/operation-details/react/runtime/operation-console/consoleUtils.tsx (247 lines of code) (raw):
import * as React from "react";
import { Button, Tooltip } from "@fluentui/react-components";
import { EyeOffRegular, EyeRegular } from "@fluentui/react-icons";
import { HttpHeader } from "@paperbits/common/http/httpHeader";
import { ISettingsProvider } from "@paperbits/common/configuration";
import { SessionManager } from "@paperbits/common/persistence/sessionManager";
import { SubscriptionState } from "../../../../../../contracts/subscription";
import { Api } from "../../../../../../models/api";
import { AuthorizationServer } from "../../../../../../models/authorizationServer";
import { ConsoleHeader } from "../../../../../../models/console/consoleHeader";
import { KnownHttpHeaders } from "../../../../../../models/knownHttpHeaders";
import { ApiService } from "../../../../../../services/apiService";
import { OAuthService } from "../../../../../../services/oauthService";
import { ProductService } from "../../../../../../services/productService";
import { UsersService } from "../../../../../../services/usersService";
import { Utils } from "../../../../../../utils";
import { OAuth2AuthenticationSettings } from "../../../../../../contracts/authenticationSettings";
import { GrantTypes, oauthSessionKey } from "../../../../../../constants";
import { SearchQuery } from "../../../../../../contracts/searchQuery";
import { noAuthFlow } from "./ConsoleAuthorization";
interface SubscriptionOption {
name: string;
value: string;
}
interface StoredCredentials {
grantType: string;
accessToken: string;
}
interface OAuthSession {
[apiName: string]: StoredCredentials;
}
export interface ResponsePackage {
statusCode: number;
statusMessage: string;
headers: HttpHeader[];
body: any;
}
export const getAuthServers = async (api: Api, oauthService: OAuthService): Promise<AuthorizationServer[]> => {
let associatedAuthServers: AuthorizationServer[];
if (api.authenticationSettings?.oAuth2AuthenticationSettings?.length > 0) {
associatedAuthServers = await oauthService.getOauthServers(api.id);
} else if (api.authenticationSettings?.openidAuthenticationSettings?.length > 0) {
associatedAuthServers = await oauthService.getOpenIdAuthServers(api.id);
}
return associatedAuthServers ? associatedAuthServers.filter(a => a.useInTestConsole) : [];
}
export const loadSubscriptionKeys = async (api: Api, apiService: ApiService, productService: ProductService, usersService: UsersService, subscriptionsPattern?: string) => {
if (!api.subscriptionRequired) return;
const userId = await usersService.getCurrentUserId();
if (!userId) return;
const allProducts = await apiService.getAllApiProducts(`/apis/${api.id}`);
const products = allProducts || [];
const subscriptionsQuery: SearchQuery = {
pattern: subscriptionsPattern
};
const allSubscriptions = await productService.getProductsAllSubscriptions(api.name, products, userId, subscriptionsQuery);
const subscriptions = allSubscriptions.filter(subscription => subscription.state === SubscriptionState.active);
const availableProducts = [];
const productsSubscriptions = subscriptions.filter(subscription => !productService.isProductScope(subscription.scope, api.name));
products.forEach(product => {
const keys: SubscriptionOption[] = [];
if (productsSubscriptions.length === 0) {
return;
}
productsSubscriptions.forEach(subscription => {
if (!productService.isProductScope(subscription.scope, product.name)) {
return;
}
keys.push({
name: `Primary: ${subscription.name?.trim() || subscription.primaryKey.substr(0, 4)}`,
value: subscription.primaryKey
});
keys.push({
name: `Secondary: ${subscription.name?.trim() || subscription.secondaryKey.substr(0, 4)}`,
value: subscription.secondaryKey
});
});
if (keys.length > 0) {
availableProducts.push({ name: product.displayName, subscriptionKeys: keys });
}
});
const apiSubscriptions = subscriptions.filter(subscription => productService.isProductScope(subscription.scope, api.name));
const apiKeys: SubscriptionOption[] = [];
apiSubscriptions.forEach(subscription => {
apiKeys.push({
name: `Primary: ${subscription.name?.trim() || subscription.primaryKey.substr(0, 4)}`,
value: subscription.primaryKey
});
apiKeys.push({
name: `Secondary: ${subscription.name?.trim() || subscription.secondaryKey.substr(0, 4)}`,
value: subscription.secondaryKey
});
});
if(apiKeys.length > 0) {
availableProducts.push({ name: "Apis", subscriptionKeys: apiKeys });
}
// this.isSubscriptionListEmptyDueToFilter(availableProducts.length == 0 && this.subscriptionsPattern() !== undefined);
// this.products(availableProducts);
// this.subscriptionsLoading(false);
// if (subscriptions.length == 0) {
// return;
// }
// if (availableProducts.length > 0 && selectFirstSubscription) {
// const subscriptionKey = availableProducts[0].subscriptionKeys[0];
// this.selectedSubscriptionKey(subscriptionKey);
// this.applySubscriptionKey(subscriptionKey);
// }
return availableProducts;
}
export const getBackendUrl = async (settingsProvider: ISettingsProvider): Promise<string> => {
return await settingsProvider.getSetting<string>("backendUrl");
}
export const setAuthHeader = (headers: ConsoleHeader[], accessToken: string): ConsoleHeader[] => {
const headersArray = headers ?? [];
const oldHeader = headersArray.find(header => header.name() === KnownHttpHeaders.Authorization);
if (oldHeader) {
const newHeaders: ConsoleHeader[] = headersArray.map(header => {
header.id === oldHeader.id && header.value(accessToken);
return header;
});
return newHeaders;
}
const authHeader = new ConsoleHeader();
authHeader.name(KnownHttpHeaders.Authorization);
authHeader.value(accessToken);
authHeader.description = "Authorization header.";
authHeader.required = false;
authHeader.secret(true);
authHeader.type = "string";
authHeader.inputTypeValue("password");
headersArray.push(authHeader);
return headersArray;
}
export const setupOAuth = async (api: Api, authServer: AuthorizationServer, headers: ConsoleHeader[], sessionManager: SessionManager) => {
const serverName = authServer.name;
const scopeOverride = getSelectedAuthServerOverrideScope(serverName, api.authenticationSettings?.oAuth2AuthenticationSettings);
const storedCredentials = await getStoredCredentials(serverName, scopeOverride, sessionManager);
let newHeaders = headers ?? [];
if (storedCredentials) {
//this.selectedGrantType(storedCredentials.grantType);
newHeaders = setAuthHeader(headers, storedCredentials.accessToken);
}
return newHeaders;
}
const getSelectedAuthServerOverrideScope = (selectedAuthServerName: string, oAuth2Settings: OAuth2AuthenticationSettings[]): string => {
if (selectedAuthServerName && oAuth2Settings) {
const authServerName = selectedAuthServerName.toLowerCase();
const setting = oAuth2Settings.find(setting => setting.authorizationServerId?.toLowerCase() == authServerName);
return setting?.scope;
}
return null;
}
const getStoredCredentials = async (serverName: string, scopeOverride: string, sessionManager: SessionManager): Promise<StoredCredentials> => {
const oauthSession = await sessionManager.getItem<OAuthSession>(oauthSessionKey);
const recordKey = serverName + (scopeOverride ? `-${scopeOverride}` : "");
const storedCredentials = oauthSession?.[recordKey];
try {
/* Trying to check if it's a JWT token and, if yes, whether it got expired. */
const jwtToken = Utils.parseJwt(storedCredentials.accessToken.replace(/^bearer /i, ""));
const now = new Date();
if (now > jwtToken.exp) {
await clearStoredCredentials(sessionManager);
return null;
}
}
catch (error) {
// do nothing
}
return storedCredentials;
}
const setStoredCredentials = async (serverName: string, scopeOverride: string, grantType: string, accessToken: string, sessionManager: SessionManager): Promise<void> => {
const oauthSession = await sessionManager.getItem<OAuthSession>(oauthSessionKey) || {};
const recordKey = serverName + (scopeOverride ? `-${scopeOverride}` : "");
oauthSession[recordKey] = {
grantType: grantType,
accessToken: accessToken
};
await sessionManager.setItem<object>(oauthSessionKey, oauthSession);
}
const clearStoredCredentials = async (sessionManager: SessionManager): Promise<void> => {
await sessionManager.removeItem(oauthSessionKey);
}
export const onGrantTypeChange = async (
api: Api,
headers: ConsoleHeader[],
authorizationServer: AuthorizationServer,
grantType: string,
sessionManager: SessionManager,
oauthService: OAuthService
): Promise<ConsoleHeader[]> => {
await clearStoredCredentials(sessionManager);
if (!grantType || grantType === GrantTypes.password || grantType === noAuthFlow) {
const authHeader = headers?.find(header => header.name() === KnownHttpHeaders.Authorization);
if (authHeader) {
const newHeaders = headers.filter(header => header.id !== authHeader.id);
return [...newHeaders];
}
return headers;
}
return await authenticateOAuth(api, headers, authorizationServer, grantType, oauthService, sessionManager);
}
const authenticateOAuth = async (
api: Api,
headers: ConsoleHeader[],
authorizationServer: AuthorizationServer,
grantType: string,
oauthService: OAuthService,
sessionManager: SessionManager
): Promise<ConsoleHeader[]> => {
if (!authorizationServer) return;
const serverName = authorizationServer.name;
const scopeOverride = getSelectedAuthServerOverrideScope(serverName, api.authenticationSettings?.oAuth2AuthenticationSettings);
if (scopeOverride) {
authorizationServer.scopes = [scopeOverride];
}
const accessToken = await oauthService.authenticate(grantType, authorizationServer, api.name);
if (!accessToken) {
return;
}
await setStoredCredentials(serverName, scopeOverride, grantType, accessToken, sessionManager);
return setAuthHeader(headers, accessToken);
}
export const authenticateOAuthWithPassword = async (
api: Api,
headers: ConsoleHeader[],
authorizationServer: AuthorizationServer,
username: string,
password: string,
oauthService: OAuthService,
sessionManager: SessionManager
): Promise<ConsoleHeader[]> => {
if (!authorizationServer) return;
const serverName = authorizationServer.name;
const scopeOverride = getSelectedAuthServerOverrideScope(serverName, api.authenticationSettings?.oAuth2AuthenticationSettings);
if (scopeOverride) {
authorizationServer.scopes = [scopeOverride];
}
const accessToken = await oauthService.authenticatePassword(username, password, authorizationServer);
await setStoredCredentials(serverName, scopeOverride, GrantTypes.password, accessToken, sessionManager);
return setAuthHeader(headers, accessToken);
}
export const getValidationMessage = (consoleParameter: {required: boolean, value:() => any}): string => {
return getValidationState(consoleParameter) === "none" ? "" : "Value is required";
}
export const getValidationState = (consoleParameter: {required: boolean, value:() => any}): "none" | "error" | "warning" | "success" => {
if (consoleParameter.required && !consoleParameter.value()) {
return "error";
}
return "none";
}
export const RevealSecretButton = ({showSecret, onClick}) => {
return (
<Tooltip content={showSecret ? "Hide secrets" : "Reveal secrets"} relationship="label">
<Button
icon={showSecret ? <EyeOffRegular /> : <EyeRegular />}
appearance="subtle"
onClick={onClick}
/>
</Tooltip>
);
}