mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-08-11 19:28:58 +00:00
Initial checkpoint
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 705f2157-ef97-4fbd-89e4-8c7f2ecaea90
This commit is contained in:
+936
@@ -0,0 +1,936 @@
|
||||
import { Router } from 'express';
|
||||
import { storage } from './storage';
|
||||
import { ldapClient } from './ldap';
|
||||
import { randomBytes } from 'crypto';
|
||||
import { z } from 'zod';
|
||||
import { insertUserSchema, insertApiTokenSchema, insertLdapConnectionSchema } from '@shared/schema';
|
||||
|
||||
export function registerAPIRoutes(router: Router, verifyApiToken: any) {
|
||||
/**
|
||||
* @swagger
|
||||
* /users:
|
||||
* get:
|
||||
* summary: Get all users
|
||||
* description: Retrieve a list of all users
|
||||
* tags: [Users]
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: properties
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Comma-separated list of properties to return
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of users
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/User'
|
||||
*/
|
||||
router.get('/users', verifyApiToken, async (req, res) => {
|
||||
try {
|
||||
// Extract properties filter
|
||||
const propertiesParam = req.query.properties as string;
|
||||
const properties = propertiesParam ? propertiesParam.split(',') : null;
|
||||
|
||||
const users = await storage.listUsers();
|
||||
|
||||
// Filter out password field
|
||||
const safeUsers = users.map(user => {
|
||||
const { password, ...userWithoutPassword } = user;
|
||||
return userWithoutPassword;
|
||||
});
|
||||
|
||||
// Apply property selection if specified
|
||||
if (properties) {
|
||||
const filteredUsers = safeUsers.map(user => {
|
||||
const filteredUser: Record<string, any> = {};
|
||||
properties.forEach(prop => {
|
||||
if (user.hasOwnProperty(prop)) {
|
||||
filteredUser[prop] = user[prop as keyof typeof user];
|
||||
}
|
||||
});
|
||||
return filteredUser;
|
||||
});
|
||||
|
||||
return res.json(filteredUsers);
|
||||
}
|
||||
|
||||
res.json(safeUsers);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /users/{id}:
|
||||
* get:
|
||||
* summary: Get a user by ID
|
||||
* description: Retrieve a single user by ID
|
||||
* tags: [Users]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: User ID
|
||||
* - in: query
|
||||
* name: properties
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Comma-separated list of properties to return
|
||||
* responses:
|
||||
* 200:
|
||||
* description: User found
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/User'
|
||||
* 404:
|
||||
* description: User not found
|
||||
*/
|
||||
router.get('/users/:id', verifyApiToken, async (req, res) => {
|
||||
try {
|
||||
const userId = parseInt(req.params.id);
|
||||
if (isNaN(userId)) {
|
||||
return res.status(400).json({ message: 'Invalid user ID' });
|
||||
}
|
||||
|
||||
// Extract properties filter
|
||||
const propertiesParam = req.query.properties as string;
|
||||
const properties = propertiesParam ? propertiesParam.split(',') : null;
|
||||
|
||||
const user = await storage.getUser(userId);
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: 'User not found' });
|
||||
}
|
||||
|
||||
// Filter out password
|
||||
const { password, ...userWithoutPassword } = user;
|
||||
|
||||
// Apply property selection if specified
|
||||
if (properties) {
|
||||
const filteredUser: Record<string, any> = {};
|
||||
properties.forEach(prop => {
|
||||
if (userWithoutPassword.hasOwnProperty(prop)) {
|
||||
filteredUser[prop] = userWithoutPassword[prop as keyof typeof userWithoutPassword];
|
||||
}
|
||||
});
|
||||
|
||||
return res.json(filteredUser);
|
||||
}
|
||||
|
||||
res.json(userWithoutPassword);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
// API Tokens Routes
|
||||
/**
|
||||
* @swagger
|
||||
* /api-tokens:
|
||||
* get:
|
||||
* summary: Get all API tokens
|
||||
* description: Retrieve a list of all API tokens for the authenticated user
|
||||
* tags: [API Tokens]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of API tokens
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/ApiToken'
|
||||
*/
|
||||
router.get('/api-tokens', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const userId = (req.user as any).id;
|
||||
const tokens = await storage.listApiTokens(userId);
|
||||
|
||||
res.json(tokens);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api-tokens:
|
||||
* post:
|
||||
* summary: Create a new API token
|
||||
* description: Generate a new API token for the authenticated user
|
||||
* tags: [API Tokens]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* expiresAt:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Token created successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/ApiToken'
|
||||
*/
|
||||
router.post('/api-tokens', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const schema = insertApiTokenSchema.extend({
|
||||
name: z.string().min(1, 'Name is required'),
|
||||
expiresAt: z.string().optional().transform(val => val ? new Date(val) : undefined)
|
||||
});
|
||||
|
||||
const validateResult = schema.safeParse(req.body);
|
||||
|
||||
if (!validateResult.success) {
|
||||
return res.status(400).json({ message: 'Invalid data', errors: validateResult.error.errors });
|
||||
}
|
||||
|
||||
const { name, expiresAt } = validateResult.data;
|
||||
const userId = (req.user as any).id;
|
||||
|
||||
// Generate a secure token
|
||||
const token = randomBytes(32).toString('hex');
|
||||
|
||||
const apiToken = await storage.createApiToken({
|
||||
name,
|
||||
token,
|
||||
userId,
|
||||
expiresAt
|
||||
});
|
||||
|
||||
// Log this activity
|
||||
await storage.createActivityLog({
|
||||
action: 'Create',
|
||||
resource: name,
|
||||
resourceType: 'API Token',
|
||||
userId,
|
||||
username: (req.user as any).username,
|
||||
status: 'Success',
|
||||
details: { id: apiToken.id }
|
||||
});
|
||||
|
||||
res.status(201).json(apiToken);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api-tokens/{id}:
|
||||
* delete:
|
||||
* summary: Delete an API token
|
||||
* description: Revoke and delete an API token
|
||||
* tags: [API Tokens]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Token ID
|
||||
* responses:
|
||||
* 204:
|
||||
* description: Token deleted successfully
|
||||
* 404:
|
||||
* description: Token not found
|
||||
*/
|
||||
router.delete('/api-tokens/:id', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const tokenId = parseInt(req.params.id);
|
||||
if (isNaN(tokenId)) {
|
||||
return res.status(400).json({ message: 'Invalid token ID' });
|
||||
}
|
||||
|
||||
const token = await storage.getApiToken(tokenId);
|
||||
if (!token) {
|
||||
return res.status(404).json({ message: 'Token not found' });
|
||||
}
|
||||
|
||||
// Only allow users to delete their own tokens
|
||||
if (token.userId !== (req.user as any).id) {
|
||||
return res.status(403).json({ message: 'Not authorized to delete this token' });
|
||||
}
|
||||
|
||||
await storage.deleteApiToken(tokenId);
|
||||
|
||||
// Log this activity
|
||||
await storage.createActivityLog({
|
||||
action: 'Delete',
|
||||
resource: token.name,
|
||||
resourceType: 'API Token',
|
||||
userId: (req.user as any).id,
|
||||
username: (req.user as any).username,
|
||||
status: 'Success',
|
||||
details: { id: tokenId }
|
||||
});
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
// LDAP Connections Routes
|
||||
/**
|
||||
* @swagger
|
||||
* /ldap-connections:
|
||||
* get:
|
||||
* summary: Get all LDAP connections
|
||||
* description: Retrieve a list of all LDAP connections
|
||||
* tags: [LDAP Connections]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of LDAP connections
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/LdapConnection'
|
||||
*/
|
||||
router.get('/ldap-connections', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const connections = await storage.listLdapConnections();
|
||||
|
||||
// Don't send passwords back
|
||||
const safeConnections = connections.map(connection => {
|
||||
const { password, ...connectionWithoutPassword } = connection;
|
||||
return connectionWithoutPassword;
|
||||
});
|
||||
|
||||
res.json(safeConnections);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ldap-connections:
|
||||
* post:
|
||||
* summary: Create a new LDAP connection
|
||||
* description: Add a new LDAP connection
|
||||
* tags: [LDAP Connections]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* name:
|
||||
* type: string
|
||||
* server:
|
||||
* type: string
|
||||
* port:
|
||||
* type: integer
|
||||
* authType:
|
||||
* type: string
|
||||
* username:
|
||||
* type: string
|
||||
* password:
|
||||
* type: string
|
||||
* baseDN:
|
||||
* type: string
|
||||
* useTLS:
|
||||
* type: boolean
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Connection created successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/LdapConnection'
|
||||
*/
|
||||
router.post('/ldap-connections', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const schema = insertLdapConnectionSchema.extend({
|
||||
name: z.string().min(1, 'Name is required'),
|
||||
server: z.string().min(1, 'Server is required'),
|
||||
port: z.number().int().positive('Port must be a positive integer'),
|
||||
authType: z.string().min(1, 'Authentication type is required'),
|
||||
username: z.string().min(1, 'Username is required'),
|
||||
password: z.string().min(1, 'Password is required'),
|
||||
});
|
||||
|
||||
const validateResult = schema.safeParse(req.body);
|
||||
|
||||
if (!validateResult.success) {
|
||||
return res.status(400).json({ message: 'Invalid data', errors: validateResult.error.errors });
|
||||
}
|
||||
|
||||
const connection = await storage.createLdapConnection(validateResult.data);
|
||||
|
||||
// Log this activity
|
||||
await storage.createActivityLog({
|
||||
action: 'Create',
|
||||
resource: connection.name,
|
||||
resourceType: 'LDAP Connection',
|
||||
userId: (req.user as any).id,
|
||||
username: (req.user as any).username,
|
||||
status: 'Success',
|
||||
details: { id: connection.id }
|
||||
});
|
||||
|
||||
// Don't send password back
|
||||
const { password, ...connectionWithoutPassword } = connection;
|
||||
|
||||
res.status(201).json(connectionWithoutPassword);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ldap-connections/{id}:
|
||||
* put:
|
||||
* summary: Update an LDAP connection
|
||||
* description: Update an existing LDAP connection
|
||||
* tags: [LDAP Connections]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Connection ID
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/LdapConnection'
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Connection updated successfully
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/LdapConnection'
|
||||
* 404:
|
||||
* description: Connection not found
|
||||
*/
|
||||
router.put('/ldap-connections/:id', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const connectionId = parseInt(req.params.id);
|
||||
if (isNaN(connectionId)) {
|
||||
return res.status(400).json({ message: 'Invalid connection ID' });
|
||||
}
|
||||
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: 'Connection not found' });
|
||||
}
|
||||
|
||||
const schema = insertLdapConnectionSchema.partial();
|
||||
const validateResult = schema.safeParse(req.body);
|
||||
|
||||
if (!validateResult.success) {
|
||||
return res.status(400).json({ message: 'Invalid data', errors: validateResult.error.errors });
|
||||
}
|
||||
|
||||
const updatedConnection = await storage.updateLdapConnection(connectionId, validateResult.data);
|
||||
|
||||
// Log this activity
|
||||
await storage.createActivityLog({
|
||||
action: 'Update',
|
||||
resource: connection.name,
|
||||
resourceType: 'LDAP Connection',
|
||||
userId: (req.user as any).id,
|
||||
username: (req.user as any).username,
|
||||
status: 'Success',
|
||||
details: { id: connectionId }
|
||||
});
|
||||
|
||||
// Don't send password back
|
||||
const { password, ...connectionWithoutPassword } = updatedConnection!;
|
||||
|
||||
res.json(connectionWithoutPassword);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ldap-connections/{id}:
|
||||
* delete:
|
||||
* summary: Delete an LDAP connection
|
||||
* description: Delete an existing LDAP connection
|
||||
* tags: [LDAP Connections]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Connection ID
|
||||
* responses:
|
||||
* 204:
|
||||
* description: Connection deleted successfully
|
||||
* 404:
|
||||
* description: Connection not found
|
||||
*/
|
||||
router.delete('/ldap-connections/:id', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const connectionId = parseInt(req.params.id);
|
||||
if (isNaN(connectionId)) {
|
||||
return res.status(400).json({ message: 'Invalid connection ID' });
|
||||
}
|
||||
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: 'Connection not found' });
|
||||
}
|
||||
|
||||
// Disconnect from LDAP if connected
|
||||
try {
|
||||
await ldapClient.disconnect(connectionId);
|
||||
} catch (err) {
|
||||
// Ignore disconnect errors
|
||||
}
|
||||
|
||||
await storage.deleteLdapConnection(connectionId);
|
||||
|
||||
// Log this activity
|
||||
await storage.createActivityLog({
|
||||
action: 'Delete',
|
||||
resource: connection.name,
|
||||
resourceType: 'LDAP Connection',
|
||||
userId: (req.user as any).id,
|
||||
username: (req.user as any).username,
|
||||
status: 'Success',
|
||||
details: { id: connectionId }
|
||||
});
|
||||
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ldap-connections/{id}/test:
|
||||
* post:
|
||||
* summary: Test an LDAP connection
|
||||
* description: Test the connection to an LDAP server
|
||||
* tags: [LDAP Connections]
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* required: true
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Connection ID
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Connection test successful
|
||||
* 400:
|
||||
* description: Connection test failed
|
||||
* 404:
|
||||
* description: Connection not found
|
||||
*/
|
||||
router.post('/ldap-connections/:id/test', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const connectionId = parseInt(req.params.id);
|
||||
if (isNaN(connectionId)) {
|
||||
return res.status(400).json({ message: 'Invalid connection ID' });
|
||||
}
|
||||
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: 'Connection not found' });
|
||||
}
|
||||
|
||||
try {
|
||||
// Disconnect first if already connected
|
||||
await ldapClient.disconnect(connectionId);
|
||||
|
||||
// Try to connect
|
||||
const success = await ldapClient.connect(connection);
|
||||
|
||||
if (success) {
|
||||
res.json({ message: 'Connection successful', status: 'connected' });
|
||||
} else {
|
||||
res.status(400).json({ message: 'Connection failed', status: 'disconnected' });
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(400).json({
|
||||
message: 'Connection failed',
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
status: 'disconnected'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ad/users:
|
||||
* get:
|
||||
* summary: Get Active Directory users
|
||||
* description: Retrieve users from Active Directory
|
||||
* tags: [Active Directory]
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: connectionId
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: LDAP Connection ID
|
||||
* - in: query
|
||||
* name: filter
|
||||
* schema:
|
||||
* type: string
|
||||
* description: LDAP filter expression
|
||||
* - in: query
|
||||
* name: properties
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Comma-separated list of properties to return
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of users
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/LdapUser'
|
||||
*/
|
||||
router.get('/ad/users', verifyApiToken, async (req, res) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.query.connectionId as string);
|
||||
if (isNaN(connectionId)) {
|
||||
return res.status(400).json({ message: 'Invalid connection ID' });
|
||||
}
|
||||
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: 'Connection not found' });
|
||||
}
|
||||
|
||||
// Connect if not already connected
|
||||
if (!ldapClient.isConnectionActive(connectionId)) {
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
message: 'Failed to connect to LDAP server',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const filter = req.query.filter as string || '(objectClass=user)';
|
||||
const propertiesParam = req.query.properties as string;
|
||||
const properties = propertiesParam ? propertiesParam.split(',') : undefined;
|
||||
|
||||
const users = await ldapClient.searchUsers(connectionId, filter, properties);
|
||||
|
||||
res.json(users);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ad/groups:
|
||||
* get:
|
||||
* summary: Get Active Directory groups
|
||||
* description: Retrieve groups from Active Directory
|
||||
* tags: [Active Directory]
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: connectionId
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: LDAP Connection ID
|
||||
* - in: query
|
||||
* name: filter
|
||||
* schema:
|
||||
* type: string
|
||||
* description: LDAP filter expression
|
||||
* - in: query
|
||||
* name: properties
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Comma-separated list of properties to return
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of groups
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/LdapGroup'
|
||||
*/
|
||||
router.get('/ad/groups', verifyApiToken, async (req, res) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.query.connectionId as string);
|
||||
if (isNaN(connectionId)) {
|
||||
return res.status(400).json({ message: 'Invalid connection ID' });
|
||||
}
|
||||
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: 'Connection not found' });
|
||||
}
|
||||
|
||||
// Connect if not already connected
|
||||
if (!ldapClient.isConnectionActive(connectionId)) {
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
message: 'Failed to connect to LDAP server',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const filter = req.query.filter as string || '(objectClass=group)';
|
||||
const propertiesParam = req.query.properties as string;
|
||||
const properties = propertiesParam ? propertiesParam.split(',') : undefined;
|
||||
|
||||
const groups = await ldapClient.searchGroups(connectionId, filter, properties);
|
||||
|
||||
res.json(groups);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ad/organizational-units:
|
||||
* get:
|
||||
* summary: Get Active Directory organizational units
|
||||
* description: Retrieve organizational units from Active Directory
|
||||
* tags: [Active Directory]
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: connectionId
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: LDAP Connection ID
|
||||
* - in: query
|
||||
* name: filter
|
||||
* schema:
|
||||
* type: string
|
||||
* description: LDAP filter expression
|
||||
* - in: query
|
||||
* name: properties
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Comma-separated list of properties to return
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of organizational units
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/LdapOU'
|
||||
*/
|
||||
router.get('/ad/organizational-units', verifyApiToken, async (req, res) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.query.connectionId as string);
|
||||
if (isNaN(connectionId)) {
|
||||
return res.status(400).json({ message: 'Invalid connection ID' });
|
||||
}
|
||||
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: 'Connection not found' });
|
||||
}
|
||||
|
||||
// Connect if not already connected
|
||||
if (!ldapClient.isConnectionActive(connectionId)) {
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
message: 'Failed to connect to LDAP server',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const filter = req.query.filter as string || '(objectClass=organizationalUnit)';
|
||||
const propertiesParam = req.query.properties as string;
|
||||
const properties = propertiesParam ? propertiesParam.split(',') : undefined;
|
||||
|
||||
const ous = await ldapClient.searchOUs(connectionId, filter, properties);
|
||||
|
||||
res.json(ous);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /ad/computers:
|
||||
* get:
|
||||
* summary: Get Active Directory computers
|
||||
* description: Retrieve computers from Active Directory
|
||||
* tags: [Active Directory]
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: connectionId
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: LDAP Connection ID
|
||||
* - in: query
|
||||
* name: filter
|
||||
* schema:
|
||||
* type: string
|
||||
* description: LDAP filter expression
|
||||
* - in: query
|
||||
* name: properties
|
||||
* schema:
|
||||
* type: string
|
||||
* description: Comma-separated list of properties to return
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of computers
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/LdapComputer'
|
||||
*/
|
||||
router.get('/ad/computers', verifyApiToken, async (req, res) => {
|
||||
try {
|
||||
const connectionId = parseInt(req.query.connectionId as string);
|
||||
if (isNaN(connectionId)) {
|
||||
return res.status(400).json({ message: 'Invalid connection ID' });
|
||||
}
|
||||
|
||||
const connection = await storage.getLdapConnection(connectionId);
|
||||
if (!connection) {
|
||||
return res.status(404).json({ message: 'Connection not found' });
|
||||
}
|
||||
|
||||
// Connect if not already connected
|
||||
if (!ldapClient.isConnectionActive(connectionId)) {
|
||||
try {
|
||||
await ldapClient.connect(connection);
|
||||
} catch (error) {
|
||||
return res.status(500).json({
|
||||
message: 'Failed to connect to LDAP server',
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const filter = req.query.filter as string || '(objectClass=computer)';
|
||||
const propertiesParam = req.query.properties as string;
|
||||
const properties = propertiesParam ? propertiesParam.split(',') : undefined;
|
||||
|
||||
const computers = await ldapClient.searchComputers(connectionId, filter, properties);
|
||||
|
||||
res.json(computers);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /activity-logs:
|
||||
* get:
|
||||
* summary: Get activity logs
|
||||
* description: Retrieve a list of recent activity logs
|
||||
* tags: [Activity Logs]
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: limit
|
||||
* schema:
|
||||
* type: integer
|
||||
* description: Maximum number of logs to return
|
||||
* responses:
|
||||
* 200:
|
||||
* description: A list of activity logs
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: '#/components/schemas/ActivityLog'
|
||||
*/
|
||||
router.get('/activity-logs', async (req, res) => {
|
||||
try {
|
||||
if (!req.isAuthenticated()) {
|
||||
return res.status(401).json({ message: 'Not authenticated' });
|
||||
}
|
||||
|
||||
const limit = req.query.limit ? parseInt(req.query.limit as string) : 10;
|
||||
|
||||
const logs = await storage.listActivityLogs(limit);
|
||||
|
||||
res.json(logs);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error instanceof Error ? error.message : 'An error occurred' });
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user