UNPKG

@confluentinc/schemaregistry

Version:
152 lines (151 loc) 6.73 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DekRegistryClient = void 0; const lru_cache_1 = require("lru-cache"); const async_mutex_1 = require("async-mutex"); const rest_service_1 = require("../../../rest-service"); const json_stringify_deterministic_1 = __importDefault(require("json-stringify-deterministic")); const mock_dekregistry_client_1 = require("./mock-dekregistry-client"); class DekRegistryClient { constructor(config) { const cacheOptions = { max: config.cacheCapacity !== undefined ? config.cacheCapacity : 1000, ...(config.cacheLatestTtlSecs !== undefined && { ttl: config.cacheLatestTtlSecs * 1000 }), }; this.restService = new rest_service_1.RestService(config.baseURLs, config.isForward, config.createAxiosDefaults, config.basicAuthCredentials, config.bearerAuthCredentials, config.maxRetries, config.retriesWaitMs, config.retriesMaxWaitMs); this.kekCache = new lru_cache_1.LRUCache(cacheOptions); this.dekCache = new lru_cache_1.LRUCache(cacheOptions); this.kekMutex = new async_mutex_1.Mutex(); this.dekMutex = new async_mutex_1.Mutex(); } static newClient(config) { const url = config.baseURLs[0]; if (url.startsWith("mock://")) { return new mock_dekregistry_client_1.MockDekRegistryClient(); } return new DekRegistryClient(config); } static getEncryptedKeyMaterialBytes(dek) { if (!dek.encryptedKeyMaterial) { return null; } if (!dek.encryptedKeyMaterialBytes) { try { const bytes = Buffer.from(dek.encryptedKeyMaterial, 'base64'); dek.encryptedKeyMaterialBytes = bytes; } catch (err) { if (err instanceof Error) { throw new Error(`Failed to decode base64 string: ${err.message}`); } throw new Error(`Unknown error: ${err}`); } } return dek.encryptedKeyMaterialBytes; } static getKeyMaterialBytes(dek) { if (!dek.keyMaterial) { return null; } if (!dek.keyMaterialBytes) { try { const bytes = Buffer.from(dek.keyMaterial, 'base64'); dek.keyMaterialBytes = bytes; } catch (err) { if (err instanceof Error) { throw new Error(`Failed to decode base64 string: ${err.message}`); } throw new Error(`Unknown error: ${err}`); } } return dek.keyMaterialBytes; } static setKeyMaterial(dek, keyMaterialBytes) { if (keyMaterialBytes) { const str = keyMaterialBytes.toString('base64'); dek.keyMaterial = str; } } async registerKek(name, kmsType, kmsKeyId, shared, kmsProps, doc) { const cacheKey = (0, json_stringify_deterministic_1.default)({ name, deleted: false }); return await this.kekMutex.runExclusive(async () => { const kek = this.kekCache.get(cacheKey); if (kek) { return kek; } const request = { name, kmsType, kmsKeyId, ...kmsProps && { kmsProps }, ...doc && { doc }, shared, }; const response = await this.restService.handleRequest('/dek-registry/v1/keks', 'POST', request); this.kekCache.set(cacheKey, response.data); return response.data; }); } async getKek(name, deleted = false) { const cacheKey = (0, json_stringify_deterministic_1.default)({ name, deleted }); return await this.kekMutex.runExclusive(async () => { const kek = this.kekCache.get(cacheKey); if (kek) { return kek; } name = encodeURIComponent(name); const response = await this.restService.handleRequest(`/dek-registry/v1/keks/${name}?deleted=${deleted}`, 'GET'); this.kekCache.set(cacheKey, response.data); return response.data; }); } async registerDek(kekName, subject, algorithm, version = 1, encryptedKeyMaterial) { const cacheKey = (0, json_stringify_deterministic_1.default)({ kekName, subject, version, algorithm, deleted: false }); return await this.dekMutex.runExclusive(async () => { const dek = this.dekCache.get(cacheKey); if (dek) { return dek; } const request = { subject, version, algorithm, ...encryptedKeyMaterial && { encryptedKeyMaterial }, }; kekName = encodeURIComponent(kekName); const response = await this.restService.handleRequest(`/dek-registry/v1/keks/${kekName}/deks`, 'POST', request); this.dekCache.set(cacheKey, response.data); this.dekCache.delete((0, json_stringify_deterministic_1.default)({ kekName, subject, version: -1, algorithm, deleted: false })); this.dekCache.delete((0, json_stringify_deterministic_1.default)({ kekName, subject, version: -1, algorithm, deleted: true })); return response.data; }); } async getDek(kekName, subject, algorithm, version = 1, deleted = false) { const cacheKey = (0, json_stringify_deterministic_1.default)({ kekName, subject, version, algorithm, deleted }); return await this.dekMutex.runExclusive(async () => { const dek = this.dekCache.get(cacheKey); if (dek) { return dek; } kekName = encodeURIComponent(kekName); subject = encodeURIComponent(subject); const response = await this.restService.handleRequest(`/dek-registry/v1/keks/${kekName}/deks/${subject}/versions/${version}?algorithm=${algorithm}&deleted=${deleted}`, 'GET'); this.dekCache.set(cacheKey, response.data); return response.data; }); } async close() { return; } //Cache methods for testing async checkLatestDekInCache(kekName, subject, algorithm) { const cacheKey = (0, json_stringify_deterministic_1.default)({ kekName, subject, version: -1, algorithm, deleted: false }); const cachedDek = this.dekCache.get(cacheKey); return cachedDek !== undefined; } } exports.DekRegistryClient = DekRegistryClient;