@restorecommerce/acs-client
Version:
Access Control Service Client
185 lines • 7.01 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.setCacheStatus = exports.flushCache = exports.get = exports.getOrFill = exports.initializeCache = void 0;
const config_1 = require("../config");
const logger_1 = __importDefault(require("../logger"));
const crypto = __importStar(require("crypto"));
const redis_1 = require("redis");
let attempted = false;
let redisInstance;
let ttl;
let cacheEnabled = true;
let redisSubjectInstance;
/**
* Initialize ACS Cache
*/
const initializeCache = async () => {
if (attempted || !cacheEnabled) {
return;
}
attempted = true;
try {
const redisConfig = config_1.cfg.get('authorization:cache');
const redisSubConfig = config_1.cfg.get('redis');
if (redisConfig) {
redisConfig.database = config_1.cfg.get('authorization:cache:db-index');
redisInstance = (0, redis_1.createClient)(redisConfig);
redisInstance.on('error', (err) => logger_1.default.error('Redis Client Error in ACS cache', { code: err.code, message: err.message, stack: err.stack }));
await redisInstance.connect();
ttl = config_1.cfg.get('authorization:cache:ttl');
}
if (redisSubConfig) {
// init redis subject instance
redisSubConfig.database = redisSubConfig['db-indexes']['db-subject'];
redisSubjectInstance = (0, redis_1.createClient)(redisSubConfig);
redisSubjectInstance.on('error', (err) => logger_1.default.error('Redis Client Error in ACS cache', { code: err.code, message: err.message, stack: err.stack }));
await redisSubjectInstance.connect();
}
}
catch (e) {
attempted = false;
}
};
exports.initializeCache = initializeCache;
/**
* Find the object in cache. If not found, compute it using the filler function
*
* @param keyData The data to base the cache key on
* @param filler The function to execute if key is not found in cache
* @param prefix The prefix to apply to the object key in the cache
*/
const getOrFill = async (keyData, filler, useCache, prefix) => {
if (!redisInstance || !cacheEnabled) {
return filler(keyData);
}
const inputHash = crypto.createHash('md5').update(JSON.stringify(keyData)).digest().toString('base64');
let redisKey = `${inputHash}`;
if (prefix) {
redisKey = `${prefix}:` + redisKey;
}
const redisKeyResponse = await redisInstance.get(redisKey);
if (redisKeyResponse && useCache) {
const response = JSON.parse(redisKeyResponse);
const evaluation_cacheable = response?.evaluation_cacheable || response?.policy_sets?.some(policy_set => policy_set?.policies?.some(policy => policy?.evaluation_cacheable !== false && policy.rules?.some(rule => rule?.evaluation_cacheable)));
if (evaluation_cacheable) {
logger_1.default.debug('Found key in cache: ' + redisKey);
return response;
}
}
if (!useCache) {
// when useCache is false, dont store in cache
return await filler(keyData);
}
logger_1.default.debug('Filling cache key: ' + redisKey);
const acsResponse = await filler(keyData);
if (acsResponse) {
if (ttl) {
await redisInstance.setEx(redisKey, ttl, JSON.stringify(acsResponse));
}
else {
await redisInstance.set(redisKey, JSON.stringify(acsResponse));
}
}
return acsResponse;
};
exports.getOrFill = getOrFill;
/**
* Find the object in cache.
*
* @param key The key to be looked up in cache
* @param filler The function to execute if key is not found in cache
* @param prefix The prefix to apply to the object key in the cache
*/
const get = async (key) => {
if (!redisSubjectInstance) {
logger_1.default.warn('No Redis Subject Instance!');
return;
}
const redisResponse = await redisSubjectInstance.get(key);
if (!redisResponse) {
logger_1.default.info('Key does not exist', { key });
return;
}
if (redisResponse) {
logger_1.default.debug('Found key in cache: ' + key);
return JSON.parse(redisResponse);
}
};
exports.get = get;
/**
* Flush the ACS cache
*
* @param prefix An optional prefix to flush instead of entire cache
*/
const flushCache = async (prefix) => {
if (!redisInstance || !cacheEnabled) {
logger_1.default.info('Redis client not initialized in acs-client');
return;
}
if (prefix != undefined) {
const flushPattern = `acs:${prefix}:*`;
logger_1.default.debug(`Flushing cache with pattern ${flushPattern}`);
let scanIterator;
try {
scanIterator = redisInstance.scanIterator({ MATCH: flushPattern, COUNT: 100 });
for await (const key of scanIterator) {
await redisInstance.del(key);
}
logger_1.default.debug(`Successfully flushed cache pattern ${flushPattern}`);
return;
}
catch (err) {
logger_1.default.error('Error flushing ACS cache', { code: err.code, message: err.message, stack: err.stack });
return;
}
}
logger_1.default.debug('Flushing ACS cache');
const reply = await redisInstance.flushDb();
if (reply) {
logger_1.default.debug('Flushed ACS cache');
}
};
exports.flushCache = flushCache;
/**
* Enable / Disable ACS Caching
*
* @param enabled Whether to enable or disable the cache
*/
const setCacheStatus = (enabled) => {
cacheEnabled = enabled;
if (enabled) {
logger_1.default.debug('ACS Cache Enabled');
(0, exports.initializeCache)();
}
else {
logger_1.default.debug('ACS Cache Disabled');
}
};
exports.setCacheStatus = setCacheStatus;
//# sourceMappingURL=cache.js.map