mirror of
https://github.com/khoaliber/dockhand.git
synced 2026-03-05 21:29:04 +00:00
Initial commit
This commit is contained in:
136
routes/api/users/+server.ts
Normal file
136
routes/api/users/+server.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import type { RequestHandler } from '@sveltejs/kit';
|
||||
import {
|
||||
getUsers,
|
||||
createUser as dbCreateUser,
|
||||
assignUserRole,
|
||||
hasAdminUser,
|
||||
getUserRoles,
|
||||
userHasAdminRole,
|
||||
getRoleByName
|
||||
} from '$lib/server/db';
|
||||
import { hashPassword, createUserSession } from '$lib/server/auth';
|
||||
import { authorize } from '$lib/server/authorize';
|
||||
|
||||
// GET /api/users - List all users
|
||||
// Free for all - local users are needed for basic auth
|
||||
export const GET: RequestHandler = async ({ cookies }) => {
|
||||
const auth = await authorize(cookies);
|
||||
|
||||
// When auth is enabled, require valid session (no specific permission needed to view users list)
|
||||
if (auth.authEnabled && !auth.isAuthenticated) {
|
||||
return json({ error: 'Authentication required' }, { status: 401 });
|
||||
}
|
||||
// Any authenticated user can view the users list
|
||||
// Admin permissions are only needed for create/edit/delete operations
|
||||
|
||||
try {
|
||||
const allUsers = await getUsers();
|
||||
const users = await Promise.all(allUsers.map(async user => {
|
||||
// Derive isAdmin from role assignment
|
||||
const isAdmin = await userHasAdminRole(user.id);
|
||||
const isSso = !user.passwordHash;
|
||||
const userData: any = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
mfaEnabled: user.mfaEnabled,
|
||||
isAdmin,
|
||||
isActive: user.isActive,
|
||||
isSso,
|
||||
authProvider: user.authProvider || 'local',
|
||||
lastLogin: user.lastLogin,
|
||||
createdAt: user.createdAt
|
||||
};
|
||||
// Include roles for enterprise users
|
||||
if (auth.isEnterprise) {
|
||||
const userRoles = await getUserRoles(user.id);
|
||||
userData.roles = userRoles.map(ur => ({
|
||||
id: ur.roleId,
|
||||
name: ur.role?.name,
|
||||
environmentId: ur.environmentId
|
||||
}));
|
||||
}
|
||||
return userData;
|
||||
}));
|
||||
return json(users);
|
||||
} catch (error) {
|
||||
console.error('Failed to get users:', error);
|
||||
return json({ error: 'Failed to get users' }, { status: 500 });
|
||||
}
|
||||
};
|
||||
|
||||
// POST /api/users - Create a new user
|
||||
// Free for all - local users are needed for basic auth
|
||||
export const POST: RequestHandler = async ({ request, cookies }) => {
|
||||
const auth = await authorize(cookies);
|
||||
|
||||
// When auth is enabled and user is logged in, check they can manage users
|
||||
// (allow if no user logged in for initial setup when no users exist)
|
||||
if (auth.authEnabled && auth.isAuthenticated && !await auth.canManageUsers()) {
|
||||
return json({ error: 'Permission denied' }, { status: 403 });
|
||||
}
|
||||
|
||||
try {
|
||||
const { username, email, password, displayName } = await request.json();
|
||||
|
||||
if (!username || !password) {
|
||||
return json({ error: 'Username and password are required' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Validate password strength
|
||||
if (password.length < 8) {
|
||||
return json({ error: 'Password must be at least 8 characters' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Hash password
|
||||
const passwordHash = await hashPassword(password);
|
||||
|
||||
// Check if this is the first user
|
||||
const isFirstUser = !(await hasAdminUser());
|
||||
|
||||
// Create user
|
||||
const user = await dbCreateUser({
|
||||
username,
|
||||
email,
|
||||
passwordHash,
|
||||
displayName
|
||||
});
|
||||
|
||||
// Role assignment logic:
|
||||
// - Enterprise: Roles are managed via syncUserRoles() from the modal (no auto-assignment here)
|
||||
// - Free edition: All users get Admin role (no RBAC)
|
||||
// - First user: Always gets Admin role (regardless of edition)
|
||||
if (!auth.isEnterprise || isFirstUser) {
|
||||
const adminRole = await getRoleByName('Admin');
|
||||
if (adminRole) {
|
||||
await assignUserRole(user.id, adminRole.id, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-login if this is the first user being created (and auth is enabled)
|
||||
let autoLoggedIn = false;
|
||||
if (isFirstUser && auth.authEnabled) {
|
||||
await createUserSession(user.id, 'local', cookies);
|
||||
autoLoggedIn = true;
|
||||
}
|
||||
|
||||
return json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
isAdmin: !auth.isEnterprise || isFirstUser,
|
||||
isActive: user.isActive,
|
||||
createdAt: user.createdAt,
|
||||
autoLoggedIn: autoLoggedIn
|
||||
}, { status: 201 });
|
||||
} catch (error: any) {
|
||||
console.error('Failed to create user:', error);
|
||||
if (error.message?.includes('UNIQUE constraint failed')) {
|
||||
return json({ error: 'Username already exists' }, { status: 409 });
|
||||
}
|
||||
return json({ error: 'Failed to create user' }, { status: 500 });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user