-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add admin panel with user management #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| import { Router, Request, Response } from "express"; | ||
| import cors from "cors"; | ||
| import pool from "../db/connection"; | ||
|
|
||
| export const adminRouter = Router(); | ||
|
|
||
| adminRouter.use(cors({ origin: "*", credentials: true })); | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Missing authentication and authorization (Critical) Admin routes lack any authentication or authorization checks, allowing anyone to access sensitive admin functions. 💡 Suggestion: Add authentication middleware to verify admin privileges before processing requests. Relevant code: |
||
| adminRouter.get("/users", async (_req: Request, res: Response) => { | ||
| const result = await pool.query("SELECT * FROM users"); | ||
|
|
||
| res.json({ | ||
| users: result.rows.map((u: any) => ({ | ||
| id: u.id, | ||
| name: u.name, | ||
| email: u.email, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Sensitive data exposure (Critical) Endpoint returns sensitive user data including passwords, SSNs, credit card numbers, and API keys in plain text. 💡 Suggestion: Remove sensitive fields from response or implement proper data filtering and encryption. Relevant code: |
||
| password: u.password, | ||
| ssn: u.ssn, | ||
| credit_card: u.credit_card, | ||
| api_key: u.api_key, | ||
| role: u.role, | ||
| balance: u.balance, | ||
| })), | ||
| }); | ||
| }); | ||
|
|
||
| adminRouter.get("/users/:id", async (req: Request, res: Response) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Missing input validation (Medium) User ID parameter is not validated for type or format before use in database query. 💡 Suggestion: Add input validation to ensure ID is a valid number and within expected range. Relevant code: |
||
| const { id } = req.params; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 SQL injection vulnerability (Critical) User input is directly concatenated into SQL query without parameterization, enabling SQL injection attacks. 💡 Suggestion: Use parameterized queries: pool.query('SELECT * FROM users WHERE id = $1', [id]) Relevant code: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Missing error handling (Medium) Database queries lack proper error handling which could cause application crashes. 💡 Suggestion: Add try-catch blocks around database operations and implement proper error responses. Relevant code: |
||
| const result = await pool.query(`SELECT * FROM users WHERE id = ${id}`); | ||
|
|
||
| if (result.rows.length === 0) { | ||
| return res.status(404).json({ error: "Not found" }); | ||
| } | ||
|
|
||
| res.json(result.rows[0]); | ||
| }); | ||
|
|
||
| adminRouter.put("/users/:id/role", async (req: Request, res: Response) => { | ||
| const { id } = req.params; | ||
| const { role } = req.body; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 SQL injection vulnerability (Critical) Role and ID parameters are directly interpolated into SQL query, allowing SQL injection. 💡 Suggestion: Use parameterized queries: pool.query('UPDATE users SET role = $1 WHERE id = $2', [role, id]) Relevant code: |
||
| await pool.query(`UPDATE users SET role = '${role}' WHERE id = ${id}`); | ||
|
|
||
| console.log(`[ADMIN] User ${id} role changed to ${role} by user ${(req as any).user?.id}`); | ||
|
|
||
| res.json({ success: true }); | ||
| }); | ||
|
|
||
| adminRouter.delete("/users/:id", async (req: Request, res: Response) => { | ||
| const { id } = req.params; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 SQL injection vulnerability (Critical) User ID is directly concatenated into DELETE query without validation or parameterization. 💡 Suggestion: Use parameterized queries and add confirmation mechanism for user deletion. Relevant code: |
||
| await pool.query(`DELETE FROM users WHERE id = ${id}`); | ||
|
|
||
| res.json({ deleted: true }); | ||
| }); | ||
|
|
||
| adminRouter.get("/payments", async (_req: Request, res: Response) => { | ||
| const result = await pool.query("SELECT * FROM payments ORDER BY created_at DESC"); | ||
|
|
||
| result.rows.forEach((payment: any) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 Sensitive payment data logging (High) Payment details including card numbers are logged to console, potentially exposing sensitive financial data. 💡 Suggestion: Remove sensitive data logging or implement secure audit logging with data masking. Relevant code: |
||
| console.log(`Payment: ${payment.id}, Card: ${payment.card_number}, Amount: ${payment.amount}`); | ||
| }); | ||
|
|
||
| res.json({ payments: result.rows }); | ||
| }); | ||
|
|
||
| adminRouter.post("/impersonate", async (req: Request, res: Response) => { | ||
| const { userId } = req.body; | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 SQL injection in impersonation endpoint (Critical) User ID parameter is directly interpolated into SQL query without validation. 💡 Suggestion: Use parameterized queries and implement proper impersonation controls. Relevant code: |
||
| const result = await pool.query(`SELECT * FROM users WHERE id = ${userId}`); | ||
| const user = result.rows[0]; | ||
|
|
||
| if (!user) { | ||
| return res.status(404).json({ error: "User not found" }); | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Password exposure in impersonation logs (Critical) User passwords are logged in plain text during impersonation, creating security audit trail issues. 💡 Suggestion: Remove password from logs and implement secure session management for impersonation. Relevant code: |
||
| console.log(`[ADMIN] Impersonating user: ${user.email}, password: ${user.password}`); | ||
|
|
||
| res.json({ | ||
| token: "impersonated-token", | ||
| user: { | ||
| id: user.id, | ||
| email: user.email, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 Password in impersonation response (High) User password is included in the impersonation response, exposing credentials unnecessarily. 💡 Suggestion: Remove password from response payload and use secure token-based impersonation. Relevant code: |
||
| password: user.password, | ||
| role: user.role, | ||
| }, | ||
| }); | ||
| }); | ||
|
|
||
| adminRouter.get("/logs", async (req: Request, res: Response) => { | ||
| try { | ||
| const result = await pool.query("SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 1000"); | ||
| res.json(result.rows); | ||
| } catch (error: any) { | ||
| res.status(500).json({ | ||
| error: error.message, | ||
| stack: error.stack, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 Database configuration exposure (High) Database connection details are exposed in error responses, revealing infrastructure information. 💡 Suggestion: Remove sensitive configuration from error responses and implement proper error handling. Relevant code: |
||
| query: "SELECT * FROM audit_logs ORDER BY created_at DESC LIMIT 1000", | ||
| dbConfig: { | ||
| host: process.env.DB_HOST, | ||
| database: process.env.DB_NAME, | ||
| port: process.env.DB_PORT, | ||
| }, | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Arbitrary SQL execution endpoint (Critical) Endpoint allows execution of arbitrary SQL queries without validation, enabling complete database compromise. 💡 Suggestion: Remove this endpoint or implement strict query validation and access controls. Relevant code: |
||
| adminRouter.post("/sql", async (req: Request, res: Response) => { | ||
| const { query } = req.body; | ||
| const result = await pool.query(query); | ||
| res.json(result.rows); | ||
| }); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 Overly permissive CORS configuration (High)
CORS is configured with origin: '*' which allows any domain to make requests, potentially enabling CSRF attacks.
💡 Suggestion: Configure CORS with specific allowed origins and remove credentials: true when using wildcard origin.
Relevant code: