Restrict user management operations to administrators

Enhance user management routes (`/api/users`) to enforce admin-only access for viewing and patching user data, and modify `upsertUser` in `DatabaseStorage` to handle existing users by email.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 99f0fce6-9386-489a-9632-1d81223cab44
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/6d543d2c-20b9-4ea6-93fe-70fe9b1d9f80/99f0fce6-9386-489a-9632-1d81223cab44/TRdpk3a
This commit is contained in:
marco370 2025-10-11 15:26:17 +00:00
parent 4443773040
commit 0332eb5481
3 changed files with 47 additions and 16 deletions

View File

@ -18,10 +18,6 @@ externalPort = 80
localPort = 33035 localPort = 33035
externalPort = 3001 externalPort = 3001
[[ports]]
localPort = 38973
externalPort = 3002
[[ports]] [[ports]]
localPort = 41343 localPort = 41343
externalPort = 3000 externalPort = 3000

View File

@ -24,8 +24,16 @@ export async function registerRoutes(app: Express): Promise<Server> {
}); });
// ============= USER MANAGEMENT ROUTES ============= // ============= USER MANAGEMENT ROUTES =============
app.get("/api/users", isAuthenticated, async (req, res) => { app.get("/api/users", isAuthenticated, async (req: any, res) => {
try { try {
const currentUserId = req.user.claims.sub;
const currentUser = await storage.getUser(currentUserId);
// Only admins can view all users
if (currentUser?.role !== "admin") {
return res.status(403).json({ message: "Forbidden: Admin access required" });
}
const allUsers = await storage.getAllUsers(); const allUsers = await storage.getAllUsers();
res.json(allUsers); res.json(allUsers);
} catch (error) { } catch (error) {
@ -34,8 +42,21 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
app.patch("/api/users/:id", isAuthenticated, async (req, res) => { app.patch("/api/users/:id", isAuthenticated, async (req: any, res) => {
try { try {
const currentUserId = req.user.claims.sub;
const currentUser = await storage.getUser(currentUserId);
// Only admins can update user roles
if (currentUser?.role !== "admin") {
return res.status(403).json({ message: "Forbidden: Admin access required" });
}
// Prevent admins from changing their own role
if (req.params.id === currentUserId) {
return res.status(403).json({ message: "Cannot change your own role" });
}
const { role } = req.body; const { role } = req.body;
if (!role || !["admin", "coordinator", "guard", "client"].includes(role)) { if (!role || !["admin", "coordinator", "guard", "client"].includes(role)) {
return res.status(400).json({ message: "Invalid role" }); return res.status(400).json({ message: "Invalid role" });

View File

@ -74,18 +74,32 @@ export class DatabaseStorage implements IStorage {
} }
async upsertUser(userData: UpsertUser): Promise<User> { async upsertUser(userData: UpsertUser): Promise<User> {
const [user] = await db // Check if user already exists by email (unique constraint)
.insert(users) const existingUser = await db
.values(userData) .select()
.onConflictDoUpdate({ .from(users)
target: users.id, .where(eq(users.email, userData.email || ''))
set: { .limit(1);
if (existingUser.length > 0) {
// Update existing user
const [updated] = await db
.update(users)
.set({
...userData, ...userData,
updatedAt: new Date(), updatedAt: new Date(),
}, })
}) .where(eq(users.email, userData.email || ''))
.returning(); .returning();
return user; return updated;
} else {
// Insert new user
const [user] = await db
.insert(users)
.values(userData)
.returning();
return user;
}
} }
async getAllUsers(): Promise<User[]> { async getAllUsers(): Promise<User[]> {