UNPKG

@cloud-copilot/iam-simulate

Version:
163 lines 6.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isActualContextKey = isActualContextKey; exports.contextKeyParts = contextKeyParts; exports.normalizeContextKeyCase = normalizeContextKeyCase; exports.typeForContextKey = typeForContextKey; const iam_data_1 = require("@cloud-copilot/iam-data"); const globalConditionKeys_js_1 = require("../global_conditions/globalConditionKeys.js"); const oidcKeys = new Set(['aud', 'sub', 'email', 'oaud', 'sub']); const oidcProviderPattern = /^[0-9a-zA-Z\._\-]+$/; /** * Check if a context key actually exists * * @param key The context key to check * @returns true if the context key is valid, false otherwise */ async function isActualContextKey(key) { if (key.includes('/')) { return isActualContextKeyWithVariable(key); } if ((0, globalConditionKeys_js_1.globalConditionKeyExists)(key)) { return true; } if (isOidcConditionKey(key)) { return true; } const parts = key.split(':'); if (parts.length !== 2) { return false; } const [service, action] = parts; const serviceExists = await (0, iam_data_1.iamServiceExists)(service); if (!serviceExists) { return false; } const actionExists = await (0, iam_data_1.iamConditionKeyExists)(service, key); return actionExists; } /** * Checks if a context key with a variable in it is a valid context key */ async function isActualContextKeyWithVariable(key) { const slashLocation = key.indexOf('/'); const prefix = key.slice(0, slashLocation); const rest = key.slice(slashLocation + 1); if (rest.length === 0) { return false; } const globalKey = (0, globalConditionKeys_js_1.getVariableGlobalConditionKeyByPrefix)(prefix); if (globalKey) { return true; } const serviceKey = await serviceContextKeyDetails(key); return !!serviceKey; } /** * Takes context key and returns the details for it, accounting for any variables in the key * * @param contextKey The context key to get the details for * @returns The details for the context key if it exists. if the key has variables in it it will return the details for the variable key */ async function serviceContextKeyDetails(contextKey) { const [service, key] = contextKeyParts(contextKey.toLowerCase()); const serviceExists = await (0, iam_data_1.iamServiceExists)(service); if (!serviceExists) { return undefined; } if (key.includes('/')) { const prefix = service + ':' + key.slice(0, key.indexOf('/') + 1); const allConditionsKeys = await (0, iam_data_1.iamConditionKeysForService)(service); const matchingKey = allConditionsKeys.find((k) => k.toLowerCase().startsWith(prefix)); if (matchingKey) { return await (0, iam_data_1.iamConditionKeyDetails)(service, matchingKey); } return undefined; } const exists = await (0, iam_data_1.iamConditionKeyExists)(service, contextKey); if (!exists) { return undefined; } return (0, iam_data_1.iamConditionKeyDetails)(service, contextKey); } /** * Split a context key into the service and the rest of the key. This has to be a special * method because context keys with variables may have a colon in the variable section, * because of course they can. * * @param contextKey The context key to split * @returns A tuple with the service and the rest of the key */ function contextKeyParts(contextKey) { const colonIndex = contextKey.indexOf(':'); return [contextKey.slice(0, colonIndex), contextKey.slice(colonIndex + 1)]; } /** * Check the capitalization of a context key and return the correct capitalization * * @param contextKey the condition key to check * @returns if the condition key is an array type */ async function normalizeContextKeyCase(contextKey) { const serviceKey = await serviceContextKeyDetails(contextKey); if (serviceKey) { return replaceVariableInContextKey(serviceKey.key, contextKey); } const globalConditionKey = (0, globalConditionKeys_js_1.getGlobalConditionKeyWithOrWithoutPrefix)(contextKey); if (globalConditionKey) { return replaceVariableInContextKey(globalConditionKey.key, contextKey); } if (isOidcConditionKey(contextKey)) { return contextKey; } throw new Error(`Context key ${contextKey} not found`); } /** * Replaces a variable in a context key with the actual value from a policy * * @param specKey the string value of the condition key spec * @param actualKey the string value of the condition key in the policy * @returns the spec condition key with the variable portion replaced with the actual value */ function replaceVariableInContextKey(specKey, actualKey) { const slashIndex = specKey.indexOf('/'); if (slashIndex === -1) { return specKey; } const prefix = specKey.slice(0, slashIndex); const suffix = actualKey.slice(slashIndex); return prefix + suffix; } /** * Get the type of a context key * * @param contextKey - The string condition key to get the type for * @returns The type of the condition key * @throws an error if the condition key is not found */ async function typeForContextKey(contextKey) { const globalConditionKey = (0, globalConditionKeys_js_1.getGlobalConditionKeyWithOrWithoutPrefix)(contextKey); if (globalConditionKey) { return globalConditionKey.dataType; } const keyDetails = await serviceContextKeyDetails(contextKey); if (keyDetails) { return keyDetails.type; } throw new Error(`Condition key ${contextKey} not found`); } /** * Checks if a string is a valid OIDC condition key * * @param key the key to check * @returns true if the key is a valid OIDC condition key */ function isOidcConditionKey(key) { const parts = key.split(':'); if (parts.length !== 2) { return false; } const [service, action] = parts; return oidcKeys.has(action) && oidcProviderPattern.test(service); } //# sourceMappingURL=contextKeys.js.map