Initial commit

This commit is contained in:
kikootwo
2026-01-28 11:41:24 -05:00
commit a3ba192fbd
257 changed files with 89482 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
/**
* User Registration Endpoint
* Documentation: documentation/features/audiobookshelf-integration.md
*/
import { NextRequest, NextResponse } from 'next/server';
import { LocalAuthProvider } from '@/lib/services/auth/LocalAuthProvider';
// Rate limiting map (in production, use Redis)
const registrationAttempts = new Map<string, { count: number; resetAt: number }>();
const MAX_ATTEMPTS = 5;
const WINDOW_MS = 60 * 60 * 1000; // 1 hour
function checkRateLimit(ip: string): boolean {
const now = Date.now();
const attempts = registrationAttempts.get(ip);
if (!attempts || now > attempts.resetAt) {
registrationAttempts.set(ip, { count: 1, resetAt: now + WINDOW_MS });
return true;
}
if (attempts.count >= MAX_ATTEMPTS) {
return false;
}
attempts.count++;
return true;
}
export async function POST(request: NextRequest) {
// Rate limiting
const ip = request.headers.get('x-forwarded-for') || 'unknown';
if (!checkRateLimit(ip)) {
return NextResponse.json(
{ error: 'Too many registration attempts. Please try again later.' },
{ status: 429 }
);
}
try {
const { username, password } = await request.json();
const provider = new LocalAuthProvider();
const result = await provider.register({ username, password });
if (!result.success) {
if (result.requiresApproval) {
return NextResponse.json({
success: false,
pendingApproval: true,
message: 'Account created. Waiting for admin approval.',
});
}
return NextResponse.json(
{ error: result.error },
{ status: 400 }
);
}
// Return tokens for auto-login
return NextResponse.json({
success: true,
user: result.user,
accessToken: result.tokens!.accessToken,
refreshToken: result.tokens!.refreshToken,
});
} catch (error) {
console.error('[Registration] Error:', error);
return NextResponse.json(
{ error: 'Registration failed' },
{ status: 500 }
);
}
}