mirror of
https://gitlab.w-hs.de/an14051/backerup-website.git
synced 2026-07-27 17:35:29 +00:00
0d58fafe4e
- 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.
77 lines
2.4 KiB
TypeScript
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 })
|
|
}
|