UNPKG

@cloud-copilot/iam-lens

Version:

Visibility in IAM in and across AWS accounts

149 lines 5.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.encodeBitSet = encodeBitSet; exports.decodeBitSet = decodeBitSet; exports.compressHex = compressHex; exports.decompressHex = decompressHex; exports.compressPrincipalString = compressPrincipalString; exports.decompressPrincipalString = decompressPrincipalString; const bitset_1 = require("bitset"); /** * Encode a BitSet into a more compact representation * * @param bitset the BitSet to encode * @returns the encoded representation */ function encodeBitSet(bitset) { const rawHex = bitset.toString(16); const compressedHex = compressHex(rawHex); const sparseString = ',' + bitset.toArray().join(','); if (sparseString.length < compressedHex.length && sparseString.length < rawHex.length) { return sparseString; } if (compressedHex.length < rawHex.length) { return compressedHex; } return rawHex; } /** * Decode a BitSet from a compact representation * * @param encoded the encoded representation * @returns the decoded BitSet */ function decodeBitSet(encoded) { if (Array.isArray(encoded)) { const bitset = new bitset_1.default(); bitset.setRange(encoded[0], encoded[1], 1); return bitset; } else if (typeof encoded === 'string') { // Check if it's a sparse array (comma-separated numbers) if (encoded.startsWith(',')) { // It's a sparse array - convert to BitSet const positions = encoded.slice(1).split(',').map(Number); const bitset = new bitset_1.default(); positions.forEach((pos) => bitset.set(pos, 1)); return bitset; } else if (encoded.includes('z')) { // It's compressed hex - decompress first const decompressedHex = decompressHex(encoded); return bitset_1.default.fromHexString(decompressedHex); } else if (encoded === '') { return new bitset_1.default(); } else { // Assume it's raw hex return bitset_1.default.fromHexString(encoded); } } // Handle other formats if needed return bitset_1.default.fromHexString(encoded); } /** * Compress a hexadecimal string by replacing runs of zeros with a compact representation * * @param rawHex the original hexadecimal string * @returns the compressed hexadecimal string */ function compressHex(rawHex) { const repeatedZeroPattern = /((0){4,})/g; return rawHex.replace(repeatedZeroPattern, (match) => { return `z${match.length} `; }); } /** * Decompress a hexadecimal string * * @param compressedHex the compressed hexadecimal string * @returns the decompressed hexadecimal string */ function decompressHex(compressedHex) { // Handle the "z" compression pattern (z followed by number of zeros) const zeroPattern = /z(\d+)\s*/g; return compressedHex.replace(zeroPattern, (match, count) => { return '0'.repeat(parseInt(count, 10)); }); } /** * Compress a principal string for storage * * @param principalString the full principal string * @returns the compressed principal string */ function compressPrincipalString(principalString) { const parts = principalString.split(':'); let accountId = parts[4]; let end = parts.slice(5).join(':'); if (end.startsWith('role/aws-reserved/')) { end = end.replace('role/aws-reserved/', 'ar/'); } else if (end.startsWith('role/aws-service-role/')) { end = end.replace('role/aws-service-role/', 'asr/'); } else if (end.startsWith('role/service-role/')) { end = end.replace('role/service-role/', 'sr/'); } else if (end.startsWith('role/')) { end = end.replace('role/', 'r/'); } else if (end.startsWith('user/')) { end = end.replace('user/', 'u/'); } return `${accountId}:${end}`; } /** * Decompress a principal string * * @param compressedString the compressed principal string * @param prefix the ARN prefix to use * @returns the decompressed principal string */ function decompressPrincipalString(compressedString, prefix = 'arn:aws:iam::') { const parts = compressedString.split(':'); if (parts.length !== 2) { throw new Error(`Invalid compressed principal format: ${compressedString}`); } const accountId = parts[0]; let roleType = parts[1]; // Expand compressed role types back to full paths if (roleType.startsWith('ar/')) { roleType = roleType.replace('ar/', 'role/aws-reserved/'); } else if (roleType.startsWith('asr/')) { roleType = roleType.replace('asr/', 'role/aws-service-role/'); } else if (roleType.startsWith('sr/')) { roleType = roleType.replace('sr/', 'role/service-role/'); } else if (roleType.startsWith('r/')) { roleType = roleType.replace('r/', 'role/'); } else if (roleType.startsWith('u/')) { roleType = roleType.replace('u/', 'user/'); } return `${prefix}${accountId}:${roleType}`; } //# sourceMappingURL=bitset.js.map