Add ability to update and delete Active Directory domains

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/10f17668-d1aa-4b91-b921-61237e6fe8f5.jpg
This commit is contained in:
alphaeusmote
2025-04-11 14:40:04 +00:00
2 changed files with 185 additions and 0 deletions
+147
View File
@@ -2764,6 +2764,153 @@ export async function registerRoutes(app: Express): Promise<Server> {
* description: Server error
*/
// Domain PATCH endpoint
app.patch("/api/connections/:connectionId/ad-domains/:objectGUID", authenticateApiToken, async (req, res, next) => {
try {
// Check permissions
const hasPermission = await checkPermission(req, PERMISSIONS.UPDATE_AD_DOMAINS);
if (!hasPermission) {
return res.status(403).json({ message: "Not authorized to update domains" });
}
const connectionId = parseInt(req.params.connectionId);
const objectGUID = req.params.objectGUID;
// Verify the connection exists
const connection = await storage.getLdapConnection(connectionId);
if (!connection) {
return res.status(404).json({ message: "LDAP connection not found" });
}
// Get domain to update
const domain = await storage.getAdDomain(connectionId, objectGUID);
if (!domain) {
return res.status(404).json({ message: "Domain not found" });
}
try {
// Connect to LDAP server
const ldapClient = await connectToLdap(connection);
// Create modification object based on the request body
const changes = {};
if (req.body.description !== undefined) {
changes.description = req.body.description;
}
if (req.body.netBIOSName !== undefined) {
changes.netBIOSName = req.body.netBIOSName;
}
// Skip modification if no changes
if (Object.keys(changes).length === 0) {
return res.status(400).json({ message: "No valid attributes provided for update" });
}
// Modify domain in LDAP
await ldapClient.modify(domain.distinguishedName, changes);
// Update domain in database
const updatedDomain = await storage.updateAdDomain(connectionId, objectGUID, {
...req.body,
adProperties: { ...domain.adProperties, ...changes }
});
// Add audit log
await storage.createAuditLogEntry({
action: "update_domain",
targetId: objectGUID,
userId: req.user?.id,
connectionId: connectionId,
details: {
domain: domain.name,
distinguishedName: domain.distinguishedName,
changes: changes
}
});
res.json({
...updatedDomain,
objectType: 'domain'
});
} catch (err) {
console.error("Error updating domain:", err);
return res.status(500).json({ message: `Error updating domain: ${err.message}` });
}
} catch (error) {
next(error);
}
});
// Domain DELETE endpoint
app.delete("/api/connections/:connectionId/ad-domains/:objectGUID", authenticateApiToken, async (req, res, next) => {
try {
// Check permissions
const hasPermission = await checkPermission(req, PERMISSIONS.DELETE_AD_DOMAINS);
if (!hasPermission) {
return res.status(403).json({ message: "Not authorized to delete domains" });
}
const connectionId = parseInt(req.params.connectionId);
const objectGUID = req.params.objectGUID;
// Verify the connection exists
const connection = await storage.getLdapConnection(connectionId);
if (!connection) {
return res.status(404).json({ message: "LDAP connection not found" });
}
// Get domain to delete
const domain = await storage.getAdDomain(connectionId, objectGUID);
if (!domain) {
return res.status(404).json({ message: "Domain not found" });
}
try {
// Connect to LDAP server
const ldapClient = await connectToLdap(connection);
// First check if there are any children under this domain
const searchResults = await ldapClient.search(domain.distinguishedName, {
scope: 'one',
filter: '(objectClass=*)'
});
if (searchResults.searchEntries && searchResults.searchEntries.length > 0) {
return res.status(409).json({
message: "Cannot delete domain with child objects. Remove all child objects first."
});
}
// Delete domain from LDAP
await ldapClient.del(domain.distinguishedName);
// Delete domain from database
await storage.deleteAdDomain(connectionId, objectGUID);
// Add audit log
await storage.createAuditLogEntry({
action: "delete_domain",
targetId: objectGUID,
userId: req.user?.id,
connectionId: connectionId,
details: {
domain: domain.name,
distinguishedName: domain.distinguishedName
}
});
res.json({ success: true });
} catch (err) {
console.error("Error deleting domain:", err);
return res.status(500).json({ message: `Error deleting domain: ${err.message}` });
}
} catch (error) {
next(error);
}
});
app.post("/api/connections/:connectionId/ad-domains", authenticateApiToken, async (req, res, next) => {
try {
// Check permissions
+38
View File
@@ -142,9 +142,12 @@ export interface IStorage {
// AD Domains
getAdDomain(id: number): Promise<AdDomain | undefined>;
getAdDomainByGuid(connectionId: number, objectGUID: string): Promise<AdDomain | undefined>;
createAdDomain(domain: InsertAdDomain): Promise<AdDomain>;
updateAdDomain(id: number, domain: Partial<AdDomain>): Promise<AdDomain | undefined>;
updateAdDomainByGuid(connectionId: number, objectGUID: string, domain: Partial<AdDomain>): Promise<AdDomain | undefined>;
deleteAdDomain(id: number): Promise<boolean>;
deleteAdDomainByGuid(connectionId: number, objectGUID: string): Promise<boolean>;
listAdDomains(connectionId: number, query?: any): Promise<AdDomain[]>;
// AD Sites
@@ -1027,6 +1030,16 @@ export class DatabaseStorage implements IStorage {
const result = await db.select().from(adDomains).where(eq(adDomains.id, id));
return result.length > 0 ? result[0] : undefined;
}
async getAdDomainByGuid(connectionId: number, objectGUID: string): Promise<AdDomain | undefined> {
const result = await db.select().from(adDomains).where(
and(
eq(adDomains.connectionId, connectionId),
eq(adDomains.objectGUID, objectGUID)
)
);
return result.length > 0 ? result[0] : undefined;
}
async createAdDomain(domain: InsertAdDomain): Promise<AdDomain> {
const result = await db.insert(adDomains).values(domain).returning();
@@ -1037,11 +1050,36 @@ export class DatabaseStorage implements IStorage {
const result = await db.update(adDomains).set(domainData).where(eq(adDomains.id, id)).returning();
return result.length > 0 ? result[0] : undefined;
}
async updateAdDomainByGuid(connectionId: number, objectGUID: string, domainData: Partial<AdDomain>): Promise<AdDomain | undefined> {
const result = await db.update(adDomains)
.set(domainData)
.where(
and(
eq(adDomains.connectionId, connectionId),
eq(adDomains.objectGUID, objectGUID)
)
)
.returning();
return result.length > 0 ? result[0] : undefined;
}
async deleteAdDomain(id: number): Promise<boolean> {
const result = await db.delete(adDomains).where(eq(adDomains.id, id)).returning({ id: adDomains.id });
return result.length > 0;
}
async deleteAdDomainByGuid(connectionId: number, objectGUID: string): Promise<boolean> {
const result = await db.delete(adDomains)
.where(
and(
eq(adDomains.connectionId, connectionId),
eq(adDomains.objectGUID, objectGUID)
)
)
.returning({ id: adDomains.id });
return result.length > 0;
}
async listAdDomains(connectionId: number, query?: any): Promise<AdDomain[]> {
let adDomainsQuery = db.select().from(adDomains).where(eq(adDomains.connectionId, connectionId));