Includes MFA-capable authentication, session and CSRF security, password recovery, listing lifecycle and ownership rules, inventory image metadata, local ImageStorage, migrations, tests, and implementation status documentation. Verification: npm test (62 passing) and integration suite (14 passing).
45 lines
1.3 KiB
JavaScript
45 lines
1.3 KiB
JavaScript
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
import { createImageStorageContract } from './image-storage.js';
|
|
|
|
function safePath(rootDirectory, key) {
|
|
if (typeof key !== 'string' || key.length === 0 || path.isAbsolute(key)) {
|
|
throw new Error('Image storage key must be a relative non-empty path.');
|
|
}
|
|
|
|
const root = path.resolve(rootDirectory);
|
|
const target = path.resolve(root, key);
|
|
if (target !== root && !target.startsWith(`${root}${path.sep}`)) {
|
|
throw new Error('Image storage key escapes the storage root.');
|
|
}
|
|
|
|
return target;
|
|
}
|
|
|
|
export function createLocalImageStorage(rootDirectory) {
|
|
if (typeof rootDirectory !== 'string' || rootDirectory.length === 0) {
|
|
throw new TypeError('Image storage root directory is required.');
|
|
}
|
|
|
|
return createImageStorageContract({
|
|
async put({ key, data }) {
|
|
if (!Buffer.isBuffer(data)) {
|
|
throw new TypeError('Image storage data must be a Buffer.');
|
|
}
|
|
|
|
const target = safePath(rootDirectory, key);
|
|
await mkdir(path.dirname(target), { recursive: true });
|
|
await writeFile(target, data, { flag: 'wx' });
|
|
return { key };
|
|
},
|
|
|
|
async get(key) {
|
|
return readFile(safePath(rootDirectory, key));
|
|
},
|
|
|
|
async delete(key) {
|
|
await rm(safePath(rootDirectory, key), { force: true });
|
|
},
|
|
});
|
|
} |