mirror of
https://github.com/freedbygrace/DynamoDNS.git
synced 2026-08-19 22:26:17 +00:00
Refactor: Improve authorization and access control for webhooks and domains by replacing organization IDs with customer IDs.
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/9d305f1a-cfc0-4985-9af8-152b65c738cb.jpg
This commit is contained in:
+47
-19
@@ -707,10 +707,10 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
app.get("/api/domains", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
|
app.get("/api/domains", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
|
||||||
try {
|
try {
|
||||||
let domains;
|
let domains;
|
||||||
const orgId = req.query.organizationId ? parseInt(req.query.organizationId as string) : undefined;
|
const customerId = req.query.customerId as string;
|
||||||
|
|
||||||
if (orgId) {
|
if (customerId) {
|
||||||
domains = await storage.getDomainsByOrganization(orgId);
|
domains = await storage.getDomainsByCustomer(customerId);
|
||||||
} else {
|
} else {
|
||||||
domains = await storage.getAllDomains();
|
domains = await storage.getAllDomains();
|
||||||
}
|
}
|
||||||
@@ -744,7 +744,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
// Create a custom validation schema for the API that makes providerId optional
|
// Create a custom validation schema for the API that makes providerId optional
|
||||||
const domainSchema = z.object({
|
const domainSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
organizationId: z.string().uuid(),
|
customerId: z.string().uuid(),
|
||||||
providerId: z.string().uuid().optional(),
|
providerId: z.string().uuid().optional(),
|
||||||
isActive: z.boolean().optional().default(true)
|
isActive: z.boolean().optional().default(true)
|
||||||
});
|
});
|
||||||
@@ -770,7 +770,7 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
// Create custom validation schema with optional providerId
|
// Create custom validation schema with optional providerId
|
||||||
const domainUpdateSchema = z.object({
|
const domainUpdateSchema = z.object({
|
||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
organizationId: z.string().uuid().optional(),
|
customerId: z.string().uuid().optional(),
|
||||||
providerId: z.string().uuid().optional().nullable(),
|
providerId: z.string().uuid().optional().nullable(),
|
||||||
isActive: z.boolean().optional()
|
isActive: z.boolean().optional()
|
||||||
});
|
});
|
||||||
@@ -1406,9 +1406,16 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ message: "Webhook not found" });
|
return res.status(404).json({ message: "Webhook not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check authorization
|
// Check authorization for non-admin users
|
||||||
if (req.user?.role !== "admin" && webhook.organizationId !== req.user?.organizationId) {
|
if (req.user?.role !== "admin") {
|
||||||
return res.status(403).json({ message: "Not authorized to access this webhook" });
|
// Get user's customers
|
||||||
|
const userCustomers = await storage.getUserCustomers(req.user?.id as string);
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
// Check if the user has access to the webhook's customer
|
||||||
|
if (!userCustomerIds.includes(webhook.customerId)) {
|
||||||
|
return res.status(403).json({ message: "Not authorized to access this webhook" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json(webhook);
|
res.json(webhook);
|
||||||
@@ -1430,8 +1437,15 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
const validatedData = insertWebhookSchema.parse(requestData);
|
const validatedData = insertWebhookSchema.parse(requestData);
|
||||||
|
|
||||||
// Check authorization for non-admin users
|
// Check authorization for non-admin users
|
||||||
if (req.user?.role !== "admin" && validatedData.organizationId !== req.user?.organizationId) {
|
if (req.user?.role !== "admin") {
|
||||||
return res.status(403).json({ message: "Not authorized to create webhooks for this organization" });
|
// Get user's customers
|
||||||
|
const userCustomers = await storage.getUserCustomers(req.user?.id as string);
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
// Check if the user has access to the customer
|
||||||
|
if (!userCustomerIds.includes(validatedData.customerId)) {
|
||||||
|
return res.status(403).json({ message: "Not authorized to create webhooks for this customer" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const webhook = await storage.createWebhook(validatedData);
|
const webhook = await storage.createWebhook(validatedData);
|
||||||
@@ -1455,16 +1469,23 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ message: "Webhook not found" });
|
return res.status(404).json({ message: "Webhook not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check authorization
|
// Check authorization for non-admin users
|
||||||
if (req.user?.role !== "admin" && webhook.organizationId !== req.user?.organizationId) {
|
if (req.user?.role !== "admin") {
|
||||||
return res.status(403).json({ message: "Not authorized to modify this webhook" });
|
// Get user's customers
|
||||||
|
const userCustomers = await storage.getUserCustomers(req.user?.id as string);
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
// Check if the user has access to the webhook's customer
|
||||||
|
if (!userCustomerIds.includes(webhook.customerId)) {
|
||||||
|
return res.status(403).json({ message: "Not authorized to modify this webhook" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedData = insertWebhookSchema.partial().parse(req.body);
|
const validatedData = insertWebhookSchema.partial().parse(req.body);
|
||||||
|
|
||||||
// Prevent changing organization for security reasons
|
// Prevent changing customer for security reasons
|
||||||
if (validatedData.organizationId && validatedData.organizationId !== webhook.organizationId) {
|
if (validatedData.customerId && validatedData.customerId !== webhook.customerId) {
|
||||||
return res.status(400).json({ message: "Cannot change webhook organization" });
|
return res.status(400).json({ message: "Cannot change webhook customer" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedWebhook = await storage.updateWebhook(req.params.id, validatedData);
|
const updatedWebhook = await storage.updateWebhook(req.params.id, validatedData);
|
||||||
@@ -1487,9 +1508,16 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
|||||||
return res.status(404).json({ message: "Webhook not found" });
|
return res.status(404).json({ message: "Webhook not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check authorization
|
// Check authorization for non-admin users
|
||||||
if (req.user?.role !== "admin" && webhook.organizationId !== req.user?.organizationId) {
|
if (req.user?.role !== "admin") {
|
||||||
return res.status(403).json({ message: "Not authorized to delete this webhook" });
|
// Get user's customers
|
||||||
|
const userCustomers = await storage.getUserCustomers(req.user?.id as string);
|
||||||
|
const userCustomerIds = userCustomers.map(c => c.id);
|
||||||
|
|
||||||
|
// Check if the user has access to the webhook's customer
|
||||||
|
if (!userCustomerIds.includes(webhook.customerId)) {
|
||||||
|
return res.status(403).json({ message: "Not authorized to delete this webhook" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleted = await storage.deleteWebhook(req.params.id);
|
const deleted = await storage.deleteWebhook(req.params.id);
|
||||||
|
|||||||
Reference in New Issue
Block a user