1.0.13
This commit is contained in:
1 parent
a88d3d5788
commit
8f3a7eb435
96 files changed
+5235
-1870
No files matched your search
@@ -11,6 +11,7 @@ import {
|
||||
} from '$lib/server/db';
|
||||
import { hashPassword, createUserSession } from '$lib/server/auth';
|
||||
import { authorize } from '$lib/server/authorize';
|
||||
import { auditUser } from '$lib/server/audit';
|
||||
|
||||
// GET /api/users - List all users
|
||||
// Free for all - local users are needed for basic auth
|
||||
@@ -63,7 +64,8 @@ export const GET: RequestHandler = async ({ cookies }) => {
|
||||
|
||||
// POST /api/users - Create a new user
|
||||
// Free for all - local users are needed for basic auth
|
||||
export const POST: RequestHandler = async ({ request, cookies }) => {
|
||||
export const POST: RequestHandler = async (event) => {
|
||||
const { request, cookies } = event;
|
||||
const auth = await authorize(cookies);
|
||||
|
||||
// When auth is enabled and user is logged in, check they can manage users
|
||||
@@ -116,6 +118,9 @@ export const POST: RequestHandler = async ({ request, cookies }) => {
|
||||
autoLoggedIn = true;
|
||||
}
|
||||
|
||||
// Audit log
|
||||
await auditUser(event, 'create', user.id, user.username);
|
||||
|
||||
return json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
} from '$lib/server/db';
|
||||
import { hashPassword } from '$lib/server/auth';
|
||||
import { authorize } from '$lib/server/authorize';
|
||||
import { auditUser } from '$lib/server/audit';
|
||||
import { computeAuditDiff } from '$lib/utils/diff';
|
||||
|
||||
// GET /api/users/[id] - Get a specific user
|
||||
// Free for all - local users are needed for basic auth
|
||||
@@ -60,7 +62,8 @@ export const GET: RequestHandler = async ({ params, cookies }) => {
|
||||
|
||||
// PUT /api/users/[id] - Update a user
|
||||
// Free for all - local users are needed for basic auth
|
||||
export const PUT: RequestHandler = async ({ params, request, cookies }) => {
|
||||
export const PUT: RequestHandler = async (event) => {
|
||||
const { params, request, cookies } = event;
|
||||
const auth = await authorize(cookies);
|
||||
|
||||
if (!params.id) {
|
||||
@@ -203,6 +206,15 @@ export const PUT: RequestHandler = async ({ params, request, cookies }) => {
|
||||
// Compute final isAdmin status
|
||||
const finalIsAdmin = shouldPromote || (existingUserIsAdmin && !shouldDemote);
|
||||
|
||||
// Compute diff for audit (exclude sensitive fields)
|
||||
const diff = computeAuditDiff(
|
||||
{ username: existingUser.username, email: existingUser.email, displayName: existingUser.displayName, isActive: existingUser.isActive, isAdmin: existingUserIsAdmin },
|
||||
{ username: user.username, email: user.email, displayName: user.displayName, isActive: user.isActive, isAdmin: finalIsAdmin }
|
||||
);
|
||||
|
||||
// Audit log
|
||||
await auditUser(event, 'update', user.id, user.username, diff);
|
||||
|
||||
return json({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
@@ -226,7 +238,8 @@ export const PUT: RequestHandler = async ({ params, request, cookies }) => {
|
||||
|
||||
// DELETE /api/users/[id] - Delete a user
|
||||
// Free for all - local users are needed for basic auth
|
||||
export const DELETE: RequestHandler = async ({ params, url, cookies }) => {
|
||||
export const DELETE: RequestHandler = async (event) => {
|
||||
const { params, url, cookies } = event;
|
||||
const auth = await authorize(cookies);
|
||||
|
||||
// When auth is enabled, check permission (free edition allows all, enterprise checks RBAC)
|
||||
@@ -279,6 +292,9 @@ export const DELETE: RequestHandler = async ({ params, url, cookies }) => {
|
||||
// Disable authentication
|
||||
await updateAuthSettings({ authEnabled: false });
|
||||
|
||||
// Audit log
|
||||
await auditUser(event, 'delete', id, user.username);
|
||||
|
||||
return json({ success: true, authDisabled: true });
|
||||
}
|
||||
}
|
||||
@@ -291,6 +307,9 @@ export const DELETE: RequestHandler = async ({ params, url, cookies }) => {
|
||||
return json({ error: 'Failed to delete user' }, { status: 500 });
|
||||
}
|
||||
|
||||
// Audit log
|
||||
await auditUser(event, 'delete', id, user.username);
|
||||
|
||||
return json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Failed to delete user:', error);
|
||||
|
||||
@@ -6,9 +6,12 @@ import {
|
||||
verifyAndEnableMfa,
|
||||
disableMfa
|
||||
} from '$lib/server/auth';
|
||||
import { auditUser } from '$lib/server/audit';
|
||||
import { getUser } from '$lib/server/db';
|
||||
|
||||
// POST /api/users/[id]/mfa - Setup MFA (generate QR code)
|
||||
export const POST: RequestHandler = async ({ params, request, cookies }) => {
|
||||
export const POST: RequestHandler = async (event) => {
|
||||
const { params, request, cookies } = event;
|
||||
const currentUser = await validateSession(cookies);
|
||||
|
||||
if (!params.id) {
|
||||
@@ -36,6 +39,15 @@ export const POST: RequestHandler = async ({ params, request, cookies }) => {
|
||||
return json({ error: 'Invalid MFA code' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Audit log - MFA enabled
|
||||
const targetUser = await getUser(userId);
|
||||
if (targetUser) {
|
||||
await auditUser(event, 'update', userId, targetUser.username, {
|
||||
mfaEnabled: true,
|
||||
enabledBy: currentUser?.id === userId ? 'self' : currentUser?.username
|
||||
});
|
||||
}
|
||||
|
||||
return json({
|
||||
success: true,
|
||||
message: 'MFA enabled successfully',
|
||||
@@ -60,7 +72,8 @@ export const POST: RequestHandler = async ({ params, request, cookies }) => {
|
||||
};
|
||||
|
||||
// DELETE /api/users/[id]/mfa - Disable MFA
|
||||
export const DELETE: RequestHandler = async ({ params, cookies }) => {
|
||||
export const DELETE: RequestHandler = async (event) => {
|
||||
const { params, cookies } = event;
|
||||
const currentUser = await validateSession(cookies);
|
||||
|
||||
if (!params.id) {
|
||||
@@ -75,11 +88,23 @@ export const DELETE: RequestHandler = async ({ params, cookies }) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const success = await disableMfa(userId);
|
||||
if (!success) {
|
||||
// Get user info before disabling for audit
|
||||
const targetUser = await getUser(userId);
|
||||
if (!targetUser) {
|
||||
return json({ error: 'User not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const success = await disableMfa(userId);
|
||||
if (!success) {
|
||||
return json({ error: 'Failed to disable MFA' }, { status: 500 });
|
||||
}
|
||||
|
||||
// Audit log - MFA disabled
|
||||
await auditUser(event, 'update', userId, targetUser.username, {
|
||||
mfaDisabled: true,
|
||||
disabledBy: currentUser?.id === userId ? 'self' : currentUser?.username
|
||||
});
|
||||
|
||||
return json({ success: true, message: 'MFA disabled successfully' });
|
||||
} catch (error) {
|
||||
console.error('MFA disable error:', error);
|
||||
|
||||
@@ -6,8 +6,10 @@ import {
|
||||
getUserRoles,
|
||||
assignUserRole,
|
||||
removeUserRole,
|
||||
getUser
|
||||
getUser,
|
||||
getRole
|
||||
} from '$lib/server/db';
|
||||
import { auditUser } from '$lib/server/audit';
|
||||
|
||||
// GET /api/users/[id]/roles - Get roles assigned to a user
|
||||
export const GET: RequestHandler = async ({ params, cookies }) => {
|
||||
@@ -37,7 +39,8 @@ export const GET: RequestHandler = async ({ params, cookies }) => {
|
||||
};
|
||||
|
||||
// POST /api/users/[id]/roles - Assign a role to a user
|
||||
export const POST: RequestHandler = async ({ params, request, cookies }) => {
|
||||
export const POST: RequestHandler = async (event) => {
|
||||
const { params, request, cookies } = event;
|
||||
// Check enterprise license
|
||||
if (!(await isEnterprise())) {
|
||||
return json({ error: 'Enterprise license required' }, { status: 403 });
|
||||
@@ -66,6 +69,14 @@ export const POST: RequestHandler = async ({ params, request, cookies }) => {
|
||||
}
|
||||
|
||||
const userRole = await assignUserRole(userId, roleId, environmentId);
|
||||
|
||||
// Audit log - role assigned
|
||||
const role = await getRole(roleId);
|
||||
await auditUser(event, 'update', userId, user.username, {
|
||||
roleAssigned: role?.name || `Role #${roleId}`,
|
||||
roleId
|
||||
});
|
||||
|
||||
return json(userRole, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Failed to assign role:', error);
|
||||
@@ -74,7 +85,8 @@ export const POST: RequestHandler = async ({ params, request, cookies }) => {
|
||||
};
|
||||
|
||||
// DELETE /api/users/[id]/roles - Remove a role from a user
|
||||
export const DELETE: RequestHandler = async ({ params, request, cookies }) => {
|
||||
export const DELETE: RequestHandler = async (event) => {
|
||||
const { params, request, cookies } = event;
|
||||
// Check enterprise license
|
||||
if (!(await isEnterprise())) {
|
||||
return json({ error: 'Enterprise license required' }, { status: 403 });
|
||||
@@ -97,11 +109,23 @@ export const DELETE: RequestHandler = async ({ params, request, cookies }) => {
|
||||
return json({ error: 'Role ID is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Get user and role info before deletion for audit
|
||||
const user = await getUser(userId);
|
||||
const role = await getRole(roleId);
|
||||
|
||||
const deleted = await removeUserRole(userId, roleId, environmentId);
|
||||
if (!deleted) {
|
||||
return json({ error: 'Role assignment not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
// Audit log - role removed
|
||||
if (user) {
|
||||
await auditUser(event, 'update', userId, user.username, {
|
||||
roleRemoved: role?.name || `Role #${roleId}`,
|
||||
roleId
|
||||
});
|
||||
}
|
||||
|
||||
return json({ success: true });
|
||||
} catch (error) {
|
||||
console.error('Failed to remove role:', error);
|
||||
|
||||
Reference in new issue
Block a user