UNPKG

@cloud-copilot/iam-simulate

Version:
161 lines 6.59 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.requestMatchesStatementResources = requestMatchesStatementResources; exports.requestMatchesResources = requestMatchesResources; exports.requestMatchesNotResources = requestMatchesNotResources; const util_js_1 = require("../util.js"); /** * Convert a resource segment to a regular expression. This is without variables. * * @param segment the segment to convert to a regular expression * @returns a regular that replaces any wildcards in the segment with the appropriate regular expression. */ function convertResourceSegmentToRegex(segment) { if (segment.indexOf(':') != -1) { throw new Error('Segment should not contain a colon'); } const pattern = '^' + segment.replace(/\?/g, '.').replace(/\*/g, '.*?') + '$'; return new RegExp(pattern, 'i'); } /** * Check if a request matches the Resource or NotResource elements of a statement. * * @param request the request to check * @param statement the statement to check against * @returns true if the request matches the resources in the statement, false otherwise */ function requestMatchesStatementResources(request, statement) { if (statement.isResourceStatement()) { const { matches, explains } = requestMatchesResources(request, statement.resources()); if (!statement.resourceIsArray()) { return { matches, details: { resources: explains[0] } }; } return { matches, details: { resources: explains } }; } else if (statement.isNotResourceStatement()) { const { matches, explains } = requestMatchesNotResources(request, statement.notResources()); if (!statement.notResourceIsArray()) { return { matches, details: { notResources: explains[0] } }; } return { matches, details: { notResources: explains } }; } return { matches: true, details: {} }; } /** * Check if a request matches a set of resources. * * @param request the request to check * @param policyResources the resources to check against * @returns true if the request matches any of the resources, false otherwise */ function requestMatchesResources(request, policyResources) { const explains = policyResources.map((policyResource) => singleResourceMatchesRequest(request, policyResource)); const matches = explains.some((explain) => explain.matches); return { matches, explains }; } /** * Check if a request matches a NotResource element in a policy. * * @param request the request to check * @param policyResources the resources to check against * @returns true if the request does not match any of the resources, false otherwise */ function requestMatchesNotResources(request, policyResources) { const explains = policyResources.map((policyResource) => { const explain = singleResourceMatchesRequest(request, policyResource); if (!explain.errors) { explain.matches = !explain.matches; } return explain; }); const matches = !explains.some((explain) => !explain.matches); return { matches, explains }; } /** * Check if a single resource matches a request. * * @param request the request to check against * @param policyResource the resource to check against * @returns true if the request matches the resource, false otherwise */ function singleResourceMatchesRequest(request, policyResource) { if (policyResource.isAllResources()) { return { resource: policyResource.value(), matches: true }; } else if (policyResource.isArnResource()) { if (!request.resource) { return { resource: policyResource.value(), matches: false, errors: ['Request does not have a resource'] }; } const resource = request.resource; if (!convertResourceSegmentToRegex(policyResource.partition()).test(resource.partition())) { return { resource: policyResource.value(), matches: false, errors: ['Partition does not match'] }; } if (!convertResourceSegmentToRegex(policyResource.service()).test(resource.service())) { return { resource: policyResource.value(), matches: false, errors: ['Service does not match'] }; } if (!convertResourceSegmentToRegex(policyResource.region()).test(resource.region())) { return { resource: policyResource.value(), matches: false, errors: ['Region does not match'] }; } if (!convertResourceSegmentToRegex(policyResource.account()).test(resource.account())) { return { resource: policyResource.value(), matches: false, errors: ['Account does not match'] }; } //Wildcards and variables are not allowed in the product segment https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html "Incorrect wildcard usage" const [policyProduct, policyResourceId] = (0, util_js_1.getResourceSegments)(policyResource); if (!resource.resource().startsWith(policyProduct)) { return { resource: policyResource.value(), matches: false, errors: ['Product does not match'] }; } const requestResourceId = resource.resource().slice(policyProduct.length); const { pattern, errors } = (0, util_js_1.convertIamString)(policyResourceId, request); const resolvedResourceId = (0, util_js_1.convertIamString)(policyResourceId, request, { convertToRegex: false, replaceWildcards: false }); const resolvedResource = policyResource.value().slice(0, policyResource.value().length - policyResourceId.length) + resolvedResourceId; const resolvedValue = resolvedResource === policyResource.value() ? undefined : resolvedResource; if (!pattern.test(requestResourceId)) { return { resource: policyResource.value(), matches: false, errors, resolvedValue }; } return { resource: policyResource.value(), matches: true, resolvedValue }; } else { throw new Error('Unknown resource type'); } } //# sourceMappingURL=resource.js.map