mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Hash lock-related identifiers
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
{
|
||||
"comment": "Used for internal storage by the locker.",
|
||||
"@id": "urn:solid-server:default:LockStorage",
|
||||
"@type": "EncodingPathStorage",
|
||||
"@type": "HashEncodingPathStorage",
|
||||
"relativePath": "/locks/",
|
||||
"source": { "@id": "urn:solid-server:default:BackendKeyValueStorage" }
|
||||
},
|
||||
|
||||
@@ -388,6 +388,7 @@ export * from './storage/conversion/TypedRepresentationConverter';
|
||||
// Storage/KeyValue
|
||||
export * from './storage/keyvalue/EncodingPathStorage';
|
||||
export * from './storage/keyvalue/ExpiringStorage';
|
||||
export * from './storage/keyvalue/HashEncodingPathStorage';
|
||||
export * from './storage/keyvalue/JsonFileStorage';
|
||||
export * from './storage/keyvalue/JsonResourceStorage';
|
||||
export * from './storage/keyvalue/KeyValueStorage';
|
||||
|
||||
@@ -10,8 +10,8 @@ import type { KeyValueStorage } from './KeyValueStorage';
|
||||
* without having to worry about cleaning the input keys.
|
||||
*/
|
||||
export class EncodingPathStorage<T> implements KeyValueStorage<string, T> {
|
||||
private readonly basePath: string;
|
||||
private readonly source: KeyValueStorage<string, T>;
|
||||
protected readonly basePath: string;
|
||||
protected readonly source: KeyValueStorage<string, T>;
|
||||
|
||||
public constructor(relativePath: string, source: KeyValueStorage<string, T>) {
|
||||
this.source = source;
|
||||
@@ -53,7 +53,7 @@ export class EncodingPathStorage<T> implements KeyValueStorage<string, T> {
|
||||
/**
|
||||
* Converts a key into a path for internal storage.
|
||||
*/
|
||||
private keyToPath(key: string): string {
|
||||
protected keyToPath(key: string): string {
|
||||
const encodedKey = Buffer.from(key).toString('base64');
|
||||
return joinUrl(this.basePath, encodedKey);
|
||||
}
|
||||
@@ -61,7 +61,7 @@ export class EncodingPathStorage<T> implements KeyValueStorage<string, T> {
|
||||
/**
|
||||
* Converts an internal storage path string into the original path key.
|
||||
*/
|
||||
private pathToKey(path: string): string {
|
||||
protected pathToKey(path: string): string {
|
||||
const buffer = Buffer.from(path.slice(this.basePath.length), 'base64');
|
||||
return buffer.toString('utf-8');
|
||||
}
|
||||
|
||||
28
src/storage/keyvalue/HashEncodingPathStorage.ts
Normal file
28
src/storage/keyvalue/HashEncodingPathStorage.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { createHash } from 'crypto';
|
||||
import { getLoggerFor } from '../../logging/LogUtil';
|
||||
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
||||
import { joinUrl } from '../../util/PathUtil';
|
||||
import { EncodingPathStorage } from './EncodingPathStorage';
|
||||
|
||||
/**
|
||||
* A variant of the {@link EncodingPathStorage} that hashes the key instead of converting to base64 encoding.
|
||||
*
|
||||
* This class was created specifically to prevent the issue of identifiers being too long when storing data:
|
||||
* https://github.com/CommunitySolidServer/CommunitySolidServer/issues/1013
|
||||
*
|
||||
* This should eventually be replaced by a more structural approach once internal storage has been refactored
|
||||
* and data migration from older versions and formats is supported.
|
||||
*/
|
||||
export class HashEncodingPathStorage<T> extends EncodingPathStorage<T> {
|
||||
protected readonly logger = getLoggerFor(this);
|
||||
|
||||
protected keyToPath(key: string): string {
|
||||
const hash = createHash('sha256').update(key).digest('hex');
|
||||
this.logger.debug(`Hashing key ${key} to ${hash}`);
|
||||
return joinUrl(this.basePath, hash);
|
||||
}
|
||||
|
||||
protected pathToKey(): string {
|
||||
throw new NotImplementedHttpError('Hash keys cannot be converted back.');
|
||||
}
|
||||
}
|
||||
31
test/unit/storage/keyvalue/HashEncodingPathStorage.test.ts
Normal file
31
test/unit/storage/keyvalue/HashEncodingPathStorage.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { HashEncodingPathStorage } from '../../../../src/storage/keyvalue/HashEncodingPathStorage';
|
||||
import type { KeyValueStorage } from '../../../../src/storage/keyvalue/KeyValueStorage';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
|
||||
describe('A HashEncodingPathStorage', (): void => {
|
||||
const relativePath = '/container/';
|
||||
let map: Map<string, string>;
|
||||
let source: KeyValueStorage<string, string>;
|
||||
let storage: HashEncodingPathStorage<string>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
map = new Map<string, string>();
|
||||
source = map as any;
|
||||
storage = new HashEncodingPathStorage<string>(relativePath, source);
|
||||
});
|
||||
|
||||
it('hashes the keys.', async(): Promise<void> => {
|
||||
const key = 'key';
|
||||
const hash = '2c70e12b7a0646f92279f427c7b38e7334d8e5389cff167a1dc30e73f826b683';
|
||||
const data = 'data';
|
||||
await storage.set(key, data);
|
||||
expect(map.size).toBe(1);
|
||||
expect(map.get(`${relativePath}${hash}`)).toBe(data);
|
||||
await expect(storage.get(key)).resolves.toBe(data);
|
||||
});
|
||||
|
||||
it('errors when paths should be converted back to keys.', async(): Promise<void> => {
|
||||
await storage.set('key', 'data');
|
||||
await expect(storage.entries().next()).rejects.toThrow(NotImplementedHttpError);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user