Files
backerup-website/frontend/app/api/upload/route.ts
T
Anders Böttcher 0d58fafe4e feat: implement user authentication and admin management
- Add user management API endpoints for listing and creating users.
- Implement login and logout functionality with rate limiting.
- Create UI components for login form, logout button, and animated elements.
- Add session management with JWT and secure cookie handling.
- Seed initial admin user if no users exist.
- Introduce utility functions for password hashing and user authentication.
- Set up proxy middleware for route protection and security headers.
- Create a JSON file for user data storage.
- Add links configuration for external resources.
2026-05-12 14:58:11 +02:00

77 lines
2.4 KiB
TypeScript

import { NextResponse } from 'next/server'
import { nanoid } from 'nanoid'
import { addFile } from '@/lib/store'
import { getSession } from '@/lib/session'
import type { FileRecord } from '@/lib/store'
const ALLOWED_EXTENSIONS = ['.backerup', '.json']
const MAX_SIZE_BYTES = 500 * 1024 * 1024 // 500 MB
export async function POST(request: Request) {
// Belt-and-suspenders auth check (middleware handles the primary check)
const session = await getSession()
if (!session) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
let formData: FormData
try {
formData = await request.formData()
} catch {
return NextResponse.json({ error: 'Invalid form data' }, { status: 400 })
}
const file = formData.get('file')
if (!(file instanceof File)) {
return NextResponse.json({ error: 'No file provided' }, { status: 400 })
}
const nameLower = file.name.toLowerCase()
if (!ALLOWED_EXTENSIONS.some((ext) => nameLower.endsWith(ext))) {
return NextResponse.json(
{ error: 'Only .backerup and .json files are accepted' },
{ status: 400 },
)
}
const buffer = Buffer.from(await file.arrayBuffer())
if (buffer.byteLength > MAX_SIZE_BYTES) {
return NextResponse.json({ error: 'File exceeds 500 MB limit' }, { status: 413 })
}
const type: FileRecord['type'] = nameLower.endsWith('.backerup') ? 'backerup' : 'config'
const description = String(formData.get('description') ?? '').trim() || undefined
const displayName = String(formData.get('displayName') ?? '').trim() || undefined
const group = String(formData.get('group') ?? '').trim() || undefined
let containerName: string | undefined
let image: string | undefined
if (type === 'config') {
try {
const raw = JSON.parse(buffer.toString('utf-8')) as Record<string, unknown>
const name = String((raw.Name as string | undefined) ?? '').replace(/^\//, '')
containerName = name || undefined
const cfg = raw.Config as Record<string, unknown> | undefined
image = (cfg?.Image as string | undefined) || undefined
} catch {
// Not valid JSON — still accept the file
}
}
const token = nanoid(10)
const record: FileRecord = {
token,
originalName: file.name,
displayName,
size: buffer.byteLength,
type,
uploadedAt: new Date().toISOString(),
description,
group,
containerName,
image,
}
await addFile(record, buffer)
return NextResponse.json({ token })
}