UNPKG

@solid/community-server

Version:

Community Solid Server: an open and modular implementation of the Solid specifications

77 lines 3.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MaxKeyLengthStorage = void 0; const node_crypto_1 = require("node:crypto"); const global_logger_factory_1 = require("global-logger-factory"); const NotImplementedHttpError_1 = require("../../util/errors/NotImplementedHttpError"); /** * A {@link KeyValueStorage} that hashes keys in case they would be longer than the set limit. * Hashed keys are prefixed with a certain value to prevent issues with incoming keys that are already hashed. * The default max length is 150 and the default prefix is `$hash$`. * * This class mostly exists to prevent issues when writing storage entries to disk. * Keys that are too long would cause issues with the file name limit. * For this reason, only the part after the last `/` in a key is hashed, to preserve the expected file structure. */ class MaxKeyLengthStorage { logger = (0, global_logger_factory_1.getLoggerFor)(this); source; maxKeyLength; hashPrefix; constructor(source, maxKeyLength = 150, hashPrefix = '$hash$') { this.source = source; this.maxKeyLength = maxKeyLength; this.hashPrefix = hashPrefix; } async has(key) { return this.source.has(this.getKey(key)); } async get(key) { return (await this.source.get(this.getKey(key)))?.payload; } async set(key, value) { await this.source.set(this.getKeyWithCheck(key), this.wrapPayload(key, value)); return this; } async delete(key) { return this.source.delete(this.getKey(key)); } async *entries() { for await (const [, val] of this.source.entries()) { yield [val.key, val.payload]; } } wrapPayload(key, payload) { return { key, payload }; } /** * Similar to `getKey` but checks to make sure the key does not already contain the prefix. * Only necessary for `set` calls. */ getKeyWithCheck(key) { const parts = key.split('/'); // Prevent non-hashed keys with the prefix to prevent false hits if (parts.at(-1)?.startsWith(this.hashPrefix)) { throw new NotImplementedHttpError_1.NotImplementedHttpError(`Unable to store keys starting with ${this.hashPrefix}`); } return this.getKey(key, parts); } /** * Hashes the last part of the key if it is too long. * Otherwise, just returns the key. */ getKey(key, parts) { if (key.length <= this.maxKeyLength) { return key; } // Hash the key if it is too long parts = parts ?? key.split('/'); const last = parts.length - 1; parts[last] = `${this.hashPrefix}${(0, node_crypto_1.createHash)('sha256').update(parts[last]).digest('hex')}`; const newKey = parts.join('/'); this.logger.debug(`Hashing key ${key} to ${newKey}`); return newKey; } } exports.MaxKeyLengthStorage = MaxKeyLengthStorage; //# sourceMappingURL=MaxKeyLengthStorage.js.map