UNPKG

@sap-ux/store

Version:

NPM module for storing persistent data

113 lines 5.24 kB
import { getFilesystemStore as dataAccessFilesystem } from './filesystem.js'; import { hasAnyValue, pick } from '../utils/index.js'; import { getSecureStore } from '../secure-store/index.js'; import { getSensitiveDataProperties, getSerializableProperties } from '../decorators/index.js'; import { inspect } from 'node:util'; function getFullyQualifiedServiceName(name) { return 'fiori/v2/' + name; } class HybridStore { logger; filesystem; secureStore; constructor(logger, options = {}) { this.logger = logger; this.filesystem = dataAccessFilesystem(this.logger, options); this.secureStore = getSecureStore(this.logger); } async read({ entityName, id }) { const serialized = await this.filesystem.read({ entityName, id }); if (!serialized) { this.logger.debug(`hybrid/read - id: [${id}], nothing on the filesystem`); } else { this.logger.debug(`hybrid/read - id: [${id}], filesystem: ${inspect(serialized)}`); } const sensitiveData = await this.secureStore.retrieve(getFullyQualifiedServiceName(entityName), id); if (!sensitiveData) { this.logger.debug(`hybrid/read - id: [${id}], nothing in the secure store`); } else { this.logger.debug(`hybrid/read - id: [${id}]. Found sensitive data in secure store`); } if (serialized || sensitiveData) { // Make sure sensitive props override serialized ones return { ...serialized, ...sensitiveData }; } else { return undefined; } } async getAll({ entityName, includeSensitiveData = true }) { return Object.values(await this.readAll({ entityName, includeSensitiveData })); } async readAll({ entityName, includeSensitiveData = true }) { const result = {}; const entitiesFs = (await this.filesystem.readAll({ entityName })) || {}; const isEntitiesFsEmpty = Object.keys(entitiesFs).length === 0; if (!includeSensitiveData && !isEntitiesFsEmpty) { return entitiesFs; } const entitiesInSecureStore = (await this.secureStore.getAll(getFullyQualifiedServiceName(entityName))) || {}; for (const key of new Set([...Object.keys(entitiesFs), ...Object.keys(entitiesInSecureStore)])) { // Make sure sensitive props override serialized ones const entity = { ...entitiesFs[key], ...entitiesInSecureStore[key] }; result[key] = entity; } return result; } async write({ entityName, id, entity }) { const serializableProps = getSerializableProperties(entity); const sensitiveProps = getSensitiveDataProperties(entity); if (serializableProps.length > 0 && sensitiveProps.length > 0) { for (let i = 0; i < serializableProps.length; i = i + 1) { if (sensitiveProps.indexOf(serializableProps[i]) !== -1) { this.logger.debug(`hybrid/write - [${String(serializableProps[i])}] is also marked as sensitive. Not writing to filesystem`); serializableProps.splice(i, 1); } } } const serializable = pick(entity, ...serializableProps); if (hasAnyValue(entity, serializableProps)) { this.logger.debug(`hybrid/write - writing serializable properties: ${inspect(serializable)}`); await this.filesystem.write({ entityName, id, entity: serializable }); } else { this.logger.debug(`hybrid/write - no serializable properties found in ${inspect(serializable)}`); } const sensitiveData = pick(entity, ...sensitiveProps); if (hasAnyValue(sensitiveData, sensitiveProps)) { this.logger.debug(`hybrid/write - writing sensitive properties to secure store. ID: [${id}]`); await this.secureStore.save(getFullyQualifiedServiceName(entityName), id, sensitiveData); } else { this.logger.debug(`hybrid/write - no sensitive properties found in ${inspect(entity)}`); } return entity; } async del({ entityName, id }) { const deletedinFs = await this.filesystem.del({ entityName, id }); this.logger.debug(`hybrid/del - delete result for id [${id}] on the filesystem: ${deletedinFs}`); const deletedInSecureStore = await this.secureStore.delete(getFullyQualifiedServiceName(entityName), id); this.logger.debug(`hybrid/del - delete result for id [${id}] in the secure store: ${deletedInSecureStore}`); return deletedinFs || deletedInSecureStore; } async partialUpdate({ entityName, id, entity }) { return this.filesystem.partialUpdate({ entityName, id, entity }); } } /** A hybrid store * Stores serializable properties on the filesystem * The properties need to be decorated with `@serilizable` annotations * * Sensitive properties (decorated with `@sensitiveData`) will be stored * in the system's secure store */ export function getHybridStore(logger, options) { return new HybridStore(logger, options); } //# sourceMappingURL=hybrid.js.map