码桶
发现社区成员的开源项目
register.js3.1 KB
// Self-registration endpoint — only works when open registration is enabled.
// No authentication required.
import { hashPassword } from './_crypto.js';
export async function onRequestPost(context) {
const { request, env } = context;
const kv = env.CF_DNS_KV;
if (!kv) {
return new Response(JSON.stringify({ error: 'KV storage not configured.' }), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
// Check if open registration is enabled
const raw = await kv.get('APP_SETTINGS');
const settings = raw ? JSON.parse(raw) : {};
if (!settings.openRegistration) {
return new Response(JSON.stringify({ error: 'Registration is disabled. Contact an admin for an invitation.' }), {
status: 403,
headers: { 'Content-Type': 'application/json' }
});
}
const body = await request.json();
const { username, password } = body;
if (!username || !username.trim()) {
return new Response(JSON.stringify({ error: 'Username is required.' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
if (!password || !password.trim()) {
return new Response(JSON.stringify({ error: 'Password is required.' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const cleanUsername = username.trim().toLowerCase();
if (cleanUsername === 'admin') {
return new Response(JSON.stringify({ error: 'Cannot register with username "admin".' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
if (!/^[a-z0-9_-]+$/.test(cleanUsername)) {
return new Response(JSON.stringify({ error: 'Username must contain only lowercase letters, numbers, hyphens, and underscores.' }), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
const existing = await kv.get(`USER:${cleanUsername}`);
if (existing) {
return new Response(JSON.stringify({ error: 'Username already taken.' }), {
status: 409,
headers: { 'Content-Type': 'application/json' }
});
}
// Hash with PBKDF2 (client sends SHA-256, we add PBKDF2 on top)
const pbkdf2Hash = await hashPassword(password.trim());
const userData = {
username: cleanUsername,
passwordHash: pbkdf2Hash,
setupToken: null,
status: 'active',
role: 'user',
createdAt: new Date().toISOString()
};
await kv.put(`USER:${cleanUsername}`, JSON.stringify(userData));
await kv.put(`USER_TOKENS:${cleanUsername}`, JSON.stringify([]));
const listJson = await kv.get('USER_LIST');
const userList = listJson ? JSON.parse(listJson) : [];
if (!userList.includes(cleanUsername)) {
userList.push(cleanUsername);
await kv.put('USER_LIST', JSON.stringify(userList));
}
return new Response(JSON.stringify({ success: true, message: 'Registration complete. You can now log in.' }), {
headers: { 'Content-Type': 'application/json' }
});
}