mirror of
https://github.com/freedbygrace/DynamoDNS.git
synced 2026-08-19 14:16:16 +00:00
Update API to improve customer management and access control.
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/ed62e9a4-d893-4126-a108-546d113b5c99.jpg
This commit is contained in:
+99
-36
@@ -677,6 +677,29 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Legacy endpoint for backward compatibility
|
||||||
|
app.get("/api/organizations", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
|
||||||
|
try {
|
||||||
|
const customers = await storage.getCustomers();
|
||||||
|
res.json(customers);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching customers:", error);
|
||||||
|
res.status(500).json({ message: "Internal server error" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get all customers
|
||||||
|
app.get("/api/customers", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
|
||||||
|
try {
|
||||||
|
const customers = await storage.getCustomers();
|
||||||
|
res.json(customers);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching customers:", error);
|
||||||
|
res.status(500).json({ message: "Internal server error" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete a customer
|
||||||
app.delete("/api/customers/:id", requireRole(["admin"]), async (req, res) => {
|
app.delete("/api/customers/:id", requireRole(["admin"]), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const deleted = await storage.deleteCustomer(req.params.id);
|
const deleted = await storage.deleteCustomer(req.params.id);
|
||||||
@@ -685,20 +708,9 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ message: "Customer not found" });
|
return res.status(404).json({ message: "Customer not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// For backward compatibility - maintain the old API endpoints
|
|
||||||
app.get("/api/organizations", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
|
|
||||||
try {
|
|
||||||
const customers = await storage.getCustomers();
|
|
||||||
res.json(customers);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error fetching organizations (customers):", error);
|
|
||||||
res.status(500).json({ message: "Internal server error" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(204).end();
|
res.status(204).end();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error deleting organization:", error);
|
console.error("Error deleting customer:", error);
|
||||||
res.status(500).json({ message: "Internal server error" });
|
res.status(500).json({ message: "Internal server error" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1133,9 +1145,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ message: "API token not found" });
|
return res.status(404).json({ message: "API token not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify permission: only admin can modify any token, managers can only modify their org's tokens
|
// Verify permission: admins can modify any token, managers can only modify tokens for customers they have access to
|
||||||
if (req.user?.role !== "admin" && token.organizationId !== req.user?.organizationId) {
|
if (req.user?.role !== "admin") {
|
||||||
return res.status(403).json({ message: "Insufficient permissions" });
|
// Get the customers the user has access to
|
||||||
|
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
// Get the customers this token has access to
|
||||||
|
const tokenCustomerAccess = await storage.getApiTokenCustomerAccess(token.id);
|
||||||
|
const tokenCustomerIds = tokenCustomerAccess.map(a => a.customerId);
|
||||||
|
|
||||||
|
// Check if user has access to any of the same customers as the token
|
||||||
|
const hasAccess = tokenCustomerIds.some(id => userCustomerIds.includes(id));
|
||||||
|
|
||||||
|
if (!hasAccess) {
|
||||||
|
return res.status(403).json({ message: "Insufficient permissions" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate permissions
|
// Validate permissions
|
||||||
@@ -1182,9 +1207,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ message: "API token not found" });
|
return res.status(404).json({ message: "API token not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify permission: only admin can modify any token, managers can only modify their org's tokens
|
// Verify permission: admins can modify any token, managers can only modify tokens for customers they have access to
|
||||||
if (req.user?.role !== "admin" && token.organizationId !== req.user?.organizationId) {
|
if (req.user?.role !== "admin") {
|
||||||
return res.status(403).json({ message: "Insufficient permissions" });
|
// Get the customers the user has access to
|
||||||
|
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
// Get the customers this token has access to
|
||||||
|
const tokenCustomerAccess = await storage.getApiTokenCustomerAccess(token.id);
|
||||||
|
const tokenCustomerIds = tokenCustomerAccess.map(a => a.customerId);
|
||||||
|
|
||||||
|
// Check if user has access to any of the same customers as the token
|
||||||
|
const hasAccess = tokenCustomerIds.some(id => userCustomerIds.includes(id));
|
||||||
|
|
||||||
|
if (!hasAccess) {
|
||||||
|
return res.status(403).json({ message: "Insufficient permissions" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For PATCH, we'll allow a simpler validation specifically for isActive status changes
|
// For PATCH, we'll allow a simpler validation specifically for isActive status changes
|
||||||
@@ -1226,9 +1264,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ message: "API token not found" });
|
return res.status(404).json({ message: "API token not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify permission: only admin can delete any token, managers can only delete their org's tokens
|
// Verify permission: admins can delete any token, managers can only delete tokens for customers they have access to
|
||||||
if (req.user?.role !== "admin" && token.organizationId !== req.user?.organizationId) {
|
if (req.user?.role !== "admin") {
|
||||||
return res.status(403).json({ message: "Insufficient permissions" });
|
// Get the customers the user has access to
|
||||||
|
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
// Get the customers this token has access to
|
||||||
|
const tokenCustomerAccess = await storage.getApiTokenCustomerAccess(token.id);
|
||||||
|
const tokenCustomerIds = tokenCustomerAccess.map(a => a.customerId);
|
||||||
|
|
||||||
|
// Check if user has access to any of the same customers as the token
|
||||||
|
const hasAccess = tokenCustomerIds.some(id => userCustomerIds.includes(id));
|
||||||
|
|
||||||
|
if (!hasAccess) {
|
||||||
|
return res.status(403).json({ message: "Insufficient permissions" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleted = await storage.deleteApiToken(id);
|
const deleted = await storage.deleteApiToken(id);
|
||||||
@@ -1378,26 +1429,38 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(403).json({ message: "Insufficient permissions" });
|
return res.status(403).json({ message: "Insufficient permissions" });
|
||||||
}
|
}
|
||||||
|
|
||||||
let webhooks;
|
let webhooks = [];
|
||||||
const orgId = req.query.organizationId as string;
|
const customerId = req.query.customerId as string;
|
||||||
|
|
||||||
if (orgId) {
|
if (customerId) {
|
||||||
// For specific organization, check if user belongs to that org
|
// For specific customer, check if user has access to that customer
|
||||||
if (userRole !== "admin" && req.user?.organizationId !== orgId) {
|
if (userRole !== "admin") {
|
||||||
return res.status(403).json({ message: "Insufficient permissions" });
|
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
if (!userCustomerIds.includes(customerId)) {
|
||||||
|
return res.status(403).json({ message: "Insufficient permissions" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
webhooks = await storage.getWebhooksByOrganization(orgId);
|
|
||||||
|
webhooks = await storage.getWebhooksByCustomer(customerId);
|
||||||
} else if (userRole === "admin") {
|
} else if (userRole === "admin") {
|
||||||
// Admins can see all webhooks
|
// Admins can see all webhooks
|
||||||
const allOrgs = await storage.getOrganizations();
|
const allCustomers = await storage.getCustomers();
|
||||||
webhooks = await Promise.all(
|
const webhookArrays = await Promise.all(
|
||||||
allOrgs.map(org => storage.getWebhooksByOrganization(org.id))
|
allCustomers.map(customer => storage.getWebhooksByCustomer(customer.id))
|
||||||
).then(results => results.flat());
|
);
|
||||||
|
webhooks = webhookArrays.flat();
|
||||||
} else {
|
} else {
|
||||||
// Others can only see webhooks for their organization
|
// Others can only see webhooks for customers they have access to
|
||||||
webhooks = req.user?.organizationId
|
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
|
||||||
? await storage.getWebhooksByOrganization(req.user.organizationId)
|
|
||||||
: [];
|
if (userCustomers.length > 0) {
|
||||||
|
const webhookArrays = await Promise.all(
|
||||||
|
userCustomers.map(customer => storage.getWebhooksByCustomer(customer.id))
|
||||||
|
);
|
||||||
|
webhooks = webhookArrays.flat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json(webhooks);
|
res.json(webhooks);
|
||||||
|
|||||||
Reference in New Issue
Block a user