mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-08-03 15:57:41 +00:00
Add audit log functionality to track user activity and data changes.
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7ed01c5f-a82d-405a-b728-b2e3d127c60c/3d6885b0-d066-41b0-8042-fa2b629d3709.jpg
This commit is contained in:
+582
-10
@@ -3,7 +3,14 @@ import { createServer, type Server } from "http";
|
||||
import { setupAuth } from "./auth";
|
||||
import { setupSwagger } from "./swagger";
|
||||
import { storage } from "./storage";
|
||||
import { apiQuerySchema, PERMISSIONS } from "@shared/schema";
|
||||
import {
|
||||
apiQuerySchema,
|
||||
PERMISSIONS,
|
||||
moveComputerSchema,
|
||||
moveUserSchema,
|
||||
addToGroupSchema,
|
||||
removeFromGroupSchema
|
||||
} from "@shared/schema";
|
||||
import { ZodError } from "zod";
|
||||
import rateLimit from "express-rate-limit";
|
||||
import {
|
||||
@@ -703,7 +710,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
*/
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-users/{id}:
|
||||
* /api/connections/{connectionId}/ad-users/{id}:
|
||||
* put:
|
||||
* summary: Update an AD user
|
||||
* tags: [AD Users]
|
||||
@@ -819,7 +826,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-groups/{id}:
|
||||
* /api/connections/{connectionId}/ad-groups/{id}:
|
||||
* put:
|
||||
* summary: Update an AD group
|
||||
* tags: [AD Groups]
|
||||
@@ -942,7 +949,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// Similar endpoints for AD Groups
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-groups:
|
||||
* /api/connections/{connectionId}/ad-groups:
|
||||
* get:
|
||||
* summary: List AD groups from the specified LDAP connection
|
||||
* tags: [AD Groups]
|
||||
@@ -999,7 +1006,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-org-units/{id}:
|
||||
* /api/connections/{connectionId}/ad-org-units/{id}:
|
||||
* put:
|
||||
* summary: Update an AD organizational unit
|
||||
* tags: [AD Organizational Units]
|
||||
@@ -1114,7 +1121,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// Organizational Units endpoints
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-org-units:
|
||||
* /api/connections/{connectionId}/ad-org-units:
|
||||
* get:
|
||||
* summary: List AD organizational units from the specified LDAP connection
|
||||
* tags: [AD Organizational Units]
|
||||
@@ -1171,7 +1178,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-computers/{id}:
|
||||
* /api/connections/{connectionId}/ad-computers/{id}:
|
||||
* put:
|
||||
* summary: Update an AD computer
|
||||
* tags: [AD Computers]
|
||||
@@ -1292,7 +1299,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// Computers endpoints
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-computers:
|
||||
* /api/connections/{connectionId}/ad-computers:
|
||||
* get:
|
||||
* summary: List AD computers from the specified LDAP connection
|
||||
* tags: [AD Computers]
|
||||
@@ -1349,7 +1356,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-domains/{id}:
|
||||
* /api/connections/{connectionId}/ad-domains/{id}:
|
||||
* put:
|
||||
* summary: Update an AD domain
|
||||
* tags: [AD Domains]
|
||||
@@ -1466,7 +1473,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
// Domains endpoints
|
||||
/**
|
||||
* @swagger
|
||||
* /connections/{connectionId}/ad-domains:
|
||||
* /api/connections/{connectionId}/ad-domains:
|
||||
* get:
|
||||
* summary: List AD domains from the specified LDAP connection
|
||||
* tags: [AD Domains]
|
||||
@@ -2262,6 +2269,571 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/move-computer:
|
||||
* post:
|
||||
* summary: Move a computer to a different OU
|
||||
* tags: [AD Computers]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - computerObjectGUID
|
||||
* - targetOUDistinguishedName
|
||||
* properties:
|
||||
* computerObjectGUID:
|
||||
* type: string
|
||||
* targetOUDistinguishedName:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Computer moved successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* message:
|
||||
* type: string
|
||||
* 400:
|
||||
* $ref: '#/components/responses/BadRequestError'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* $ref: '#/components/responses/NotFoundError'
|
||||
*/
|
||||
app.post("/api/connections/:connectionId/move-computer", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
try {
|
||||
const data = moveComputerSchema.parse(req.body);
|
||||
|
||||
// This would call a method in the LDAP client to move the computer
|
||||
// For now we'll return a mock success response
|
||||
// In a real implementation, this would interact with the Active Directory
|
||||
|
||||
// Record the action in the audit log
|
||||
const auditEntry = {
|
||||
action: "MOVE_COMPUTER",
|
||||
targetId: data.computerObjectGUID,
|
||||
details: {
|
||||
targetOU: data.targetOUDistinguishedName
|
||||
},
|
||||
userId: req.user?.id || null,
|
||||
connectionId: connectionId
|
||||
};
|
||||
|
||||
// Save the audit entry to storage
|
||||
await storage.createAuditLogEntry(auditEntry);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `Computer with GUID ${data.computerObjectGUID} moved to ${data.targetOUDistinguishedName}`
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return handleZodError(error, res);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/move-user:
|
||||
* post:
|
||||
* summary: Move a user to a different OU
|
||||
* tags: [AD Users]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - userObjectGUID
|
||||
* - targetOUDistinguishedName
|
||||
* properties:
|
||||
* userObjectGUID:
|
||||
* type: string
|
||||
* targetOUDistinguishedName:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: User moved successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* message:
|
||||
* type: string
|
||||
* 400:
|
||||
* $ref: '#/components/responses/BadRequestError'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* $ref: '#/components/responses/NotFoundError'
|
||||
*/
|
||||
app.post("/api/connections/:connectionId/move-user", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
try {
|
||||
const data = moveUserSchema.parse(req.body);
|
||||
|
||||
// This would call a method in the LDAP client to move the user
|
||||
// For now we'll return a mock success response
|
||||
// In a real implementation, this would interact with the Active Directory
|
||||
|
||||
// Record the action in the audit log
|
||||
const auditEntry = {
|
||||
action: "MOVE_USER",
|
||||
targetId: data.userObjectGUID,
|
||||
details: {
|
||||
targetOU: data.targetOUDistinguishedName
|
||||
},
|
||||
userId: req.user?.id || null,
|
||||
connectionId: connectionId
|
||||
};
|
||||
|
||||
// Save the audit entry to storage
|
||||
await storage.createAuditLogEntry(auditEntry);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `User with GUID ${data.userObjectGUID} moved to ${data.targetOUDistinguishedName}`
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return handleZodError(error, res);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/add-to-group:
|
||||
* post:
|
||||
* summary: Add a user or computer to a group
|
||||
* tags: [AD Groups]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - objectGUID
|
||||
* - groupObjectGUID
|
||||
* - objectType
|
||||
* properties:
|
||||
* objectGUID:
|
||||
* type: string
|
||||
* groupObjectGUID:
|
||||
* type: string
|
||||
* objectType:
|
||||
* type: string
|
||||
* enum: [user, computer]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Object added to group successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* message:
|
||||
* type: string
|
||||
* 400:
|
||||
* $ref: '#/components/responses/BadRequestError'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* $ref: '#/components/responses/NotFoundError'
|
||||
*/
|
||||
app.post("/api/connections/:connectionId/add-to-group", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
try {
|
||||
const data = addToGroupSchema.parse(req.body);
|
||||
|
||||
// This would call a method in the LDAP client to add the object to the group
|
||||
// For now we'll return a mock success response
|
||||
// In a real implementation, this would interact with the Active Directory
|
||||
|
||||
// Record the action in the audit log
|
||||
const auditEntry = {
|
||||
action: "ADD_TO_GROUP",
|
||||
targetId: data.objectGUID,
|
||||
details: {
|
||||
groupGUID: data.groupObjectGUID,
|
||||
objectType: data.objectType
|
||||
},
|
||||
userId: req.user?.id || null,
|
||||
connectionId: connectionId
|
||||
};
|
||||
|
||||
// Save the audit entry to storage
|
||||
await storage.createAuditLogEntry(auditEntry);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `${data.objectType} with GUID ${data.objectGUID} added to group with GUID ${data.groupObjectGUID}`
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return handleZodError(error, res);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/audit-logs:
|
||||
* get:
|
||||
* summary: Retrieve audit logs for a connection
|
||||
* tags: [Audit]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: List of audit logs
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* timestamp:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* userId:
|
||||
* type: integer
|
||||
* nullable: true
|
||||
* action:
|
||||
* type: string
|
||||
* targetId:
|
||||
* type: string
|
||||
* details:
|
||||
* type: object
|
||||
* connectionId:
|
||||
* type: integer
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* $ref: '#/components/responses/NotFoundError'
|
||||
*/
|
||||
app.get("/api/connections/:connectionId/audit-logs", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
const logs = await storage.getAuditLogs(connectionId);
|
||||
res.json(logs);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/audit-logs:
|
||||
* get:
|
||||
* summary: Retrieve all audit logs
|
||||
* tags: [Audit]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: List of all audit logs
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* timestamp:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* userId:
|
||||
* type: integer
|
||||
* nullable: true
|
||||
* action:
|
||||
* type: string
|
||||
* targetId:
|
||||
* type: string
|
||||
* details:
|
||||
* type: object
|
||||
* connectionId:
|
||||
* type: integer
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
*/
|
||||
app.get("/api/audit-logs", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const logs = await storage.getAuditLogs();
|
||||
res.json(logs);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/remove-from-group:
|
||||
* post:
|
||||
* summary: Remove a user or computer from a group
|
||||
* tags: [AD Groups]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - objectGUID
|
||||
* - groupObjectGUID
|
||||
* - objectType
|
||||
* properties:
|
||||
* objectGUID:
|
||||
* type: string
|
||||
* groupObjectGUID:
|
||||
* type: string
|
||||
* objectType:
|
||||
* type: string
|
||||
* enum: [user, computer]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Object removed from group successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* success:
|
||||
* type: boolean
|
||||
* message:
|
||||
* type: string
|
||||
* 400:
|
||||
* $ref: '#/components/responses/BadRequestError'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* $ref: '#/components/responses/NotFoundError'
|
||||
*/
|
||||
app.post("/api/connections/:connectionId/remove-from-group", authenticateApiToken, async (req, res, next) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId);
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "LDAP connection not found" });
|
||||
}
|
||||
|
||||
try {
|
||||
const data = removeFromGroupSchema.parse(req.body);
|
||||
|
||||
// This would call a method in the LDAP client to remove the object from the group
|
||||
// For now we'll return a mock success response
|
||||
// In a real implementation, this would interact with the Active Directory
|
||||
|
||||
// Record the action in the audit log
|
||||
const auditEntry = {
|
||||
action: "REMOVE_FROM_GROUP",
|
||||
targetId: data.objectGUID,
|
||||
details: {
|
||||
groupGUID: data.groupObjectGUID,
|
||||
objectType: data.objectType
|
||||
},
|
||||
userId: req.user?.id || null,
|
||||
connectionId: connectionId
|
||||
};
|
||||
|
||||
// Save the audit entry to storage
|
||||
await storage.createAuditLogEntry(auditEntry);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `${data.objectType} with GUID ${data.objectGUID} removed from group with GUID ${data.groupObjectGUID}`
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
return handleZodError(error, res);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/audit-logs:
|
||||
* get:
|
||||
* summary: Get all audit logs
|
||||
* tags: [Audit Logs]
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: List of all audit logs
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/AuditLog'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
*/
|
||||
app.get("/api/audit-logs", requireAuth, async (req: Request<any>, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const logs = await storage.getAuditLogs();
|
||||
res.json(logs);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/connections/{connectionId}/audit-logs:
|
||||
* get:
|
||||
* summary: Get audit logs for a specific connection
|
||||
* tags: [Audit Logs]
|
||||
* security:
|
||||
* - cookieAuth: []
|
||||
* parameters:
|
||||
* - name: connectionId
|
||||
* in: path
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* responses:
|
||||
* 200:
|
||||
* description: List of audit logs for the specified connection
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/AuditLog'
|
||||
* 401:
|
||||
* $ref: '#/components/responses/UnauthorizedError'
|
||||
* 404:
|
||||
* $ref: '#/components/responses/NotFoundError'
|
||||
*/
|
||||
app.get("/api/connections/:connectionId/audit-logs", requireAuth, async (req: Request<any>, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.params.connectionId, 10);
|
||||
|
||||
// Verify the connection exists
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: "Connection not found" });
|
||||
}
|
||||
|
||||
const logs = await storage.getAuditLogs(connectionId);
|
||||
res.json(logs);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
const httpServer = createServer(app);
|
||||
|
||||
return httpServer;
|
||||
|
||||
+41
-3
@@ -5,15 +5,15 @@ import {
|
||||
AdOrgUnit, InsertAdOrgUnit, AdComputer, InsertAdComputer,
|
||||
AdDomain, InsertAdDomain, Role, ApiQuery,
|
||||
LdapFilter, InsertLdapFilter, LdapFilterRevision, InsertLdapFilterRevision,
|
||||
LdapAttribute, InsertLdapAttribute,
|
||||
LdapAttribute, InsertLdapAttribute, AuditLog, InsertAuditLog,
|
||||
users, apiTokens, ldapConnections, adUsers, adGroups, adOrgUnits, adComputers, adDomains,
|
||||
roles, ldapFilters, ldapFilterRevisions, ldapAttributes
|
||||
roles, ldapFilters, ldapFilterRevisions, ldapAttributes, auditLogs
|
||||
} from "@shared/schema";
|
||||
import session from "express-session";
|
||||
import createMemoryStore from "memorystore";
|
||||
import crypto from "crypto";
|
||||
import { db } from "./db";
|
||||
import { eq, and, type SQL } from "drizzle-orm";
|
||||
import { eq, and, type SQL, desc } from "drizzle-orm";
|
||||
import connectPg from "connect-pg-simple";
|
||||
import { Pool } from "@neondatabase/serverless";
|
||||
import { applyQueryOptions } from "./query-parser";
|
||||
@@ -112,6 +112,10 @@ export interface IStorage {
|
||||
updateAdDomain(id: number, domain: Partial<AdDomain>): Promise<AdDomain | undefined>;
|
||||
deleteAdDomain(id: number): Promise<boolean>;
|
||||
listAdDomains(connectionId: number, query?: any): Promise<AdDomain[]>;
|
||||
|
||||
// Audit logging
|
||||
createAuditLogEntry(entry: InsertAuditLog): Promise<AuditLog>;
|
||||
getAuditLogs(connectionId?: number, userId?: number): Promise<AuditLog[]>;
|
||||
|
||||
// Session store
|
||||
sessionStore: any;
|
||||
@@ -855,6 +859,40 @@ export class DatabaseStorage implements IStorage {
|
||||
|
||||
return adDomainsQuery;
|
||||
}
|
||||
|
||||
// Audit logging
|
||||
async createAuditLogEntry(entry: InsertAuditLog): Promise<AuditLog> {
|
||||
debug(`Creating audit log entry: ${JSON.stringify(entry)}`);
|
||||
const result = await db.insert(auditLogs).values({
|
||||
...entry,
|
||||
timestamp: new Date() // Ensure timestamp is set
|
||||
}).returning();
|
||||
return result[0];
|
||||
}
|
||||
|
||||
async getAuditLogs(connectionId?: number, userId?: number): Promise<AuditLog[]> {
|
||||
debug(`Getting audit logs: connectionId=${connectionId}, userId=${userId}`);
|
||||
|
||||
// Define the base query
|
||||
let query = db.select().from(auditLogs);
|
||||
|
||||
// Apply filters if provided
|
||||
if (connectionId !== undefined && userId !== undefined) {
|
||||
query = query.where(
|
||||
and(
|
||||
eq(auditLogs.connectionId, connectionId),
|
||||
eq(auditLogs.userId, userId)
|
||||
)
|
||||
);
|
||||
} else if (connectionId !== undefined) {
|
||||
query = query.where(eq(auditLogs.connectionId, connectionId));
|
||||
} else if (userId !== undefined) {
|
||||
query = query.where(eq(auditLogs.userId, userId));
|
||||
}
|
||||
|
||||
// Sort by most recent first
|
||||
return await query.orderBy(desc(auditLogs.timestamp));
|
||||
}
|
||||
}
|
||||
|
||||
export const storage = new DatabaseStorage();
|
||||
|
||||
Reference in New Issue
Block a user