refactor(security): use centralized getServerDataPath in password-reset-log.js
This commit is contained in:
@@ -1,31 +1,11 @@
|
|||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import fs from 'fs/promises'
|
import fs from 'fs/promises'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { getServerDataPath } from './paths.js'
|
||||||
|
|
||||||
const RETENTION_MS = 72 * 60 * 60 * 1000
|
const RETENTION_MS = 72 * 60 * 60 * 1000
|
||||||
|
|
||||||
function getDataPath(filename) {
|
const LOG_FILE = getServerDataPath('password-reset.log.jsonl')
|
||||||
// sanitize filename: only allow a simple basename (no path separators)
|
|
||||||
const safeName = path.basename(String(filename || ''))
|
|
||||||
// whitelist valid characters to avoid any traversal or weird names
|
|
||||||
if (!/^[a-zA-Z0-9._-]+$/.test(safeName)) {
|
|
||||||
throw new Error('Invalid data filename')
|
|
||||||
}
|
|
||||||
|
|
||||||
const cwd = process.cwd()
|
|
||||||
const dataDir = cwd.endsWith('.output') ? path.join(cwd, '../server/data') : path.join(cwd, 'server/data')
|
|
||||||
|
|
||||||
// build candidate path and verify it's inside the expected data directory
|
|
||||||
const candidate = path.join(dataDir, safeName)
|
|
||||||
const resolved = path.resolve(candidate)
|
|
||||||
const resolvedDataDir = path.resolve(dataDir)
|
|
||||||
if (!resolved.startsWith(resolvedDataDir + path.sep) && resolved !== resolvedDataDir) {
|
|
||||||
throw new Error('Invalid data filename (outside data directory)')
|
|
||||||
}
|
|
||||||
return resolved
|
|
||||||
}
|
|
||||||
|
|
||||||
const LOG_FILE = getDataPath('password-reset.log.jsonl')
|
|
||||||
|
|
||||||
export function normalizeResetEmail(email) {
|
export function normalizeResetEmail(email) {
|
||||||
return String(email || '').trim().toLowerCase()
|
return String(email || '').trim().toLowerCase()
|
||||||
|
|||||||
Reference in New Issue
Block a user