Fix security issues: path traversal, typed errors, file validation

- Fix path traversal in file serve endpoint (validate company prefix, block ..)
- Add typed error classes: ValidationError, NotFoundError, ForbiddenError,
  ConflictError, StorageError
- Global error handler catches AppError subclasses with correct status codes
- 4xx logged as warn, 5xx as error with request ID
- File upload validates entityType whitelist, UUID format, category pattern
- Remove fragile string-matching error handling from routes
- Services throw typed errors instead of plain Error
- Health endpoint documented as intentionally public
This commit is contained in:
Ryan Moon
2026-03-28 16:03:45 -05:00
parent 5aadd68128
commit e65175ef19
9 changed files with 150 additions and 86 deletions

View File

@@ -0,0 +1,47 @@
export class AppError extends Error {
statusCode: number
constructor(message: string, statusCode: number) {
super(message)
this.name = 'AppError'
this.statusCode = statusCode
}
}
export class ValidationError extends AppError {
details?: unknown
constructor(message: string, details?: unknown) {
super(message, 400)
this.name = 'ValidationError'
this.details = details
}
}
export class NotFoundError extends AppError {
constructor(entity: string) {
super(`${entity} not found`, 404)
this.name = 'NotFoundError'
}
}
export class ForbiddenError extends AppError {
constructor(message = 'Insufficient permissions') {
super(message, 403)
this.name = 'ForbiddenError'
}
}
export class ConflictError extends AppError {
constructor(message: string) {
super(message, 409)
this.name = 'ConflictError'
}
}
export class StorageError extends AppError {
constructor(message: string) {
super(message, 500)
this.name = 'StorageError'
}
}