mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-22 20:20:29 +02:00
Resource policy api backward compatability
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, resources } from "@server/db";
|
import { db, resources } from "@server/db";
|
||||||
import { roleResources, roles } from "@server/db";
|
import { roleResources, roles, rolePolicies } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -131,31 +131,64 @@ export async function addRoleToResource(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if role already exists in resource
|
const isInlinePolicy =
|
||||||
const existingEntry = await db
|
resource.resourcePolicyId === null &&
|
||||||
.select()
|
resource.defaultResourcePolicyId !== null;
|
||||||
.from(roleResources)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(roleResources.resourceId, resourceId),
|
|
||||||
eq(roleResources.roleId, roleId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingEntry.length > 0) {
|
if (isInlinePolicy) {
|
||||||
return next(
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
createHttpError(
|
|
||||||
HttpCode.CONFLICT,
|
// Check if role already exists in the inline policy
|
||||||
"Role already assigned to resource"
|
const existingEntry = await db
|
||||||
)
|
.select()
|
||||||
);
|
.from(rolePolicies)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(rolePolicies.resourcePolicyId, policyId),
|
||||||
|
eq(rolePolicies.roleId, roleId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length > 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.CONFLICT,
|
||||||
|
"Role already assigned to resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.insert(rolePolicies).values({
|
||||||
|
roleId,
|
||||||
|
resourcePolicyId: policyId
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Check if role already exists in resource
|
||||||
|
const existingEntry = await db
|
||||||
|
.select()
|
||||||
|
.from(roleResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(roleResources.resourceId, resourceId),
|
||||||
|
eq(roleResources.roleId, roleId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length > 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.CONFLICT,
|
||||||
|
"Role already assigned to resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.insert(roleResources).values({
|
||||||
|
roleId,
|
||||||
|
resourceId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.insert(roleResources).values({
|
|
||||||
roleId,
|
|
||||||
resourceId
|
|
||||||
});
|
|
||||||
|
|
||||||
return response(res, {
|
return response(res, {
|
||||||
data: {},
|
data: {},
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, resources } from "@server/db";
|
import { db, resources } from "@server/db";
|
||||||
import { userResources } from "@server/db";
|
import { userResources, userPolicies } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -103,31 +103,64 @@ export async function addUserToResource(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user already exists in resource
|
const isInlinePolicy =
|
||||||
const existingEntry = await db
|
resource.resourcePolicyId === null &&
|
||||||
.select()
|
resource.defaultResourcePolicyId !== null;
|
||||||
.from(userResources)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(userResources.resourceId, resourceId),
|
|
||||||
eq(userResources.userId, userId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingEntry.length > 0) {
|
if (isInlinePolicy) {
|
||||||
return next(
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
createHttpError(
|
|
||||||
HttpCode.CONFLICT,
|
// Check if user already exists in the inline policy
|
||||||
"User already assigned to resource"
|
const existingEntry = await db
|
||||||
)
|
.select()
|
||||||
);
|
.from(userPolicies)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userPolicies.resourcePolicyId, policyId),
|
||||||
|
eq(userPolicies.userId, userId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length > 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.CONFLICT,
|
||||||
|
"User already assigned to resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.insert(userPolicies).values({
|
||||||
|
userId,
|
||||||
|
resourcePolicyId: policyId
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Check if user already exists in resource
|
||||||
|
const existingEntry = await db
|
||||||
|
.select()
|
||||||
|
.from(userResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userResources.resourceId, resourceId),
|
||||||
|
eq(userResources.userId, userId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length > 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.CONFLICT,
|
||||||
|
"User already assigned to resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.insert(userResources).values({
|
||||||
|
userId,
|
||||||
|
resourceId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.insert(userResources).values({
|
|
||||||
userId,
|
|
||||||
resourceId
|
|
||||||
});
|
|
||||||
|
|
||||||
return response(res, {
|
return response(res, {
|
||||||
data: {},
|
data: {},
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resourceRules, resources } from "@server/db";
|
import { resourceRules, resourcePolicyRules, resources } from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
@@ -153,6 +153,34 @@ export async function createResourceRule(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the new resource rule
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
|
if (isInlinePolicy) {
|
||||||
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
|
const [newRule] = await db
|
||||||
|
.insert(resourcePolicyRules)
|
||||||
|
.values({
|
||||||
|
resourcePolicyId: policyId,
|
||||||
|
action,
|
||||||
|
match,
|
||||||
|
value,
|
||||||
|
priority,
|
||||||
|
enabled
|
||||||
|
})
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: newRule,
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Resource rule created successfully",
|
||||||
|
status: HttpCode.CREATED
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Create the new resource rule
|
// Create the new resource rule
|
||||||
const [newRule] = await db
|
const [newRule] = await db
|
||||||
.insert(resourceRules)
|
.insert(resourceRules)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resourceRules, resources } from "@server/db";
|
import { resourceRules, resourcePolicyRules, resources } from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
@@ -59,6 +59,48 @@ export async function deleteResourceRule(
|
|||||||
|
|
||||||
const { ruleId } = parsedParams.data;
|
const { ruleId } = parsedParams.data;
|
||||||
|
|
||||||
|
// Look up resource to determine which table to use
|
||||||
|
const { resourceId } = parsedParams.data;
|
||||||
|
const [resource] = await db
|
||||||
|
.select()
|
||||||
|
.from(resources)
|
||||||
|
.where(eq(resources.resourceId, resourceId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
|
if (isInlinePolicy) {
|
||||||
|
const [deletedRule] = await db
|
||||||
|
.delete(resourcePolicyRules)
|
||||||
|
.where(eq(resourcePolicyRules.ruleId, ruleId))
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
if (!deletedRule) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
`Resource rule with ID ${ruleId} not found`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: null,
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Resource rule deleted successfully",
|
||||||
|
status: HttpCode.OK
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Delete the rule and return the deleted record
|
// Delete the rule and return the deleted record
|
||||||
const [deletedRule] = await db
|
const [deletedRule] = await db
|
||||||
.delete(resourceRules)
|
.delete(resourceRules)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resourceWhitelist, users } from "@server/db"; // Assuming these are the correct tables
|
import {
|
||||||
|
resourceWhitelist,
|
||||||
|
resourcePolicyWhiteList,
|
||||||
|
resources
|
||||||
|
} from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
@@ -23,6 +27,15 @@ async function queryWhitelist(resourceId: number) {
|
|||||||
.where(eq(resourceWhitelist.resourceId, resourceId));
|
.where(eq(resourceWhitelist.resourceId, resourceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function queryPolicyWhitelist(policyId: number) {
|
||||||
|
return await db
|
||||||
|
.select({
|
||||||
|
email: resourcePolicyWhiteList.email
|
||||||
|
})
|
||||||
|
.from(resourcePolicyWhiteList)
|
||||||
|
.where(eq(resourcePolicyWhiteList.resourcePolicyId, policyId));
|
||||||
|
}
|
||||||
|
|
||||||
export type GetResourceWhitelistResponse = {
|
export type GetResourceWhitelistResponse = {
|
||||||
whitelist: NonNullable<Awaited<ReturnType<typeof queryWhitelist>>>;
|
whitelist: NonNullable<Awaited<ReturnType<typeof queryWhitelist>>>;
|
||||||
};
|
};
|
||||||
@@ -71,7 +84,25 @@ export async function getResourceWhitelist(
|
|||||||
|
|
||||||
const { resourceId } = parsedParams.data;
|
const { resourceId } = parsedParams.data;
|
||||||
|
|
||||||
const whitelist = await queryWhitelist(resourceId);
|
const [resource] = await db
|
||||||
|
.select()
|
||||||
|
.from(resources)
|
||||||
|
.where(eq(resources.resourceId, resourceId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
|
const whitelist = isInlinePolicy
|
||||||
|
? await queryPolicyWhitelist(resource.defaultResourcePolicyId!)
|
||||||
|
: await queryWhitelist(resourceId);
|
||||||
|
|
||||||
return response<GetResourceWhitelistResponse>(res, {
|
return response<GetResourceWhitelistResponse>(res, {
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { roleResources, roles } from "@server/db";
|
import { roleResources, roles, rolePolicies, resources } from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
@@ -27,6 +27,19 @@ async function query(resourceId: number) {
|
|||||||
.where(eq(roleResources.resourceId, resourceId));
|
.where(eq(roleResources.resourceId, resourceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function queryInlinePolicy(policyId: number) {
|
||||||
|
return await db
|
||||||
|
.select({
|
||||||
|
roleId: roles.roleId,
|
||||||
|
name: roles.name,
|
||||||
|
description: roles.description,
|
||||||
|
isAdmin: roles.isAdmin
|
||||||
|
})
|
||||||
|
.from(rolePolicies)
|
||||||
|
.innerJoin(roles, eq(rolePolicies.roleId, roles.roleId))
|
||||||
|
.where(eq(rolePolicies.resourcePolicyId, policyId));
|
||||||
|
}
|
||||||
|
|
||||||
export type ListResourceRolesResponse = {
|
export type ListResourceRolesResponse = {
|
||||||
roles: NonNullable<Awaited<ReturnType<typeof query>>>;
|
roles: NonNullable<Awaited<ReturnType<typeof query>>>;
|
||||||
};
|
};
|
||||||
@@ -75,7 +88,25 @@ export async function listResourceRoles(
|
|||||||
|
|
||||||
const { resourceId } = parsedParams.data;
|
const { resourceId } = parsedParams.data;
|
||||||
|
|
||||||
const resourceRolesList = await query(resourceId);
|
const [resource] = await db
|
||||||
|
.select()
|
||||||
|
.from(resources)
|
||||||
|
.where(eq(resources.resourceId, resourceId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
|
const resourceRolesList = isInlinePolicy
|
||||||
|
? await queryInlinePolicy(resource.defaultResourcePolicyId!)
|
||||||
|
: await query(resourceId);
|
||||||
|
|
||||||
return response<ListResourceRolesResponse>(res, {
|
return response<ListResourceRolesResponse>(res, {
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resourceRules, resources } from "@server/db";
|
import { resourceRules, resourcePolicyRules, resources } from "@server/db";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import { eq, sql } from "drizzle-orm";
|
import { eq, sql } from "drizzle-orm";
|
||||||
@@ -47,6 +47,21 @@ function queryResourceRules(resourceId: number) {
|
|||||||
return baseQuery;
|
return baseQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function queryPolicyRules(policyId: number) {
|
||||||
|
return db
|
||||||
|
.select({
|
||||||
|
ruleId: resourcePolicyRules.ruleId,
|
||||||
|
resourceId: sql<number | null>`null`,
|
||||||
|
action: resourcePolicyRules.action,
|
||||||
|
match: resourcePolicyRules.match,
|
||||||
|
value: resourcePolicyRules.value,
|
||||||
|
priority: resourcePolicyRules.priority,
|
||||||
|
enabled: resourcePolicyRules.enabled
|
||||||
|
})
|
||||||
|
.from(resourcePolicyRules)
|
||||||
|
.where(eq(resourcePolicyRules.resourcePolicyId, policyId));
|
||||||
|
}
|
||||||
|
|
||||||
export type ListResourceRulesResponse = {
|
export type ListResourceRulesResponse = {
|
||||||
rules: Awaited<ReturnType<typeof queryResourceRules>>;
|
rules: Awaited<ReturnType<typeof queryResourceRules>>;
|
||||||
pagination: { total: number; limit: number; offset: number };
|
pagination: { total: number; limit: number; offset: number };
|
||||||
@@ -125,16 +140,34 @@ export async function listResourceRules(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseQuery = queryResourceRules(resourceId);
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
const countQuery = db
|
let rulesList: Awaited<ReturnType<typeof queryResourceRules>>;
|
||||||
.select({ count: sql<number>`cast(count(*) as integer)` })
|
let totalCount: number;
|
||||||
.from(resourceRules)
|
|
||||||
.where(eq(resourceRules.resourceId, resourceId));
|
|
||||||
|
|
||||||
let rulesList = await baseQuery.limit(limit).offset(offset);
|
if (isInlinePolicy) {
|
||||||
const totalCountResult = await countQuery;
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
const totalCount = totalCountResult[0].count;
|
const policyRules = await queryPolicyRules(policyId)
|
||||||
|
.limit(limit)
|
||||||
|
.offset(offset);
|
||||||
|
const countResult = await db
|
||||||
|
.select({ count: sql<number>`cast(count(*) as integer)` })
|
||||||
|
.from(resourcePolicyRules)
|
||||||
|
.where(eq(resourcePolicyRules.resourcePolicyId, policyId));
|
||||||
|
rulesList = policyRules as typeof rulesList;
|
||||||
|
totalCount = countResult[0].count;
|
||||||
|
} else {
|
||||||
|
const baseQuery = queryResourceRules(resourceId);
|
||||||
|
const countQuery = db
|
||||||
|
.select({ count: sql<number>`cast(count(*) as integer)` })
|
||||||
|
.from(resourceRules)
|
||||||
|
.where(eq(resourceRules.resourceId, resourceId));
|
||||||
|
rulesList = await baseQuery.limit(limit).offset(offset);
|
||||||
|
const totalCountResult = await countQuery;
|
||||||
|
totalCount = totalCountResult[0].count;
|
||||||
|
}
|
||||||
|
|
||||||
// sort rules list by the priority in ascending order
|
// sort rules list by the priority in ascending order
|
||||||
rulesList = rulesList.sort((a, b) => a.priority - b.priority);
|
rulesList = rulesList.sort((a, b) => a.priority - b.priority);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, resources } from "@server/db";
|
import { db, resources } from "@server/db";
|
||||||
import { roleResources, roles } from "@server/db";
|
import { roleResources, roles, rolePolicies } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -130,35 +130,71 @@ export async function removeRoleFromResource(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if role exists in resource
|
const isInlinePolicy =
|
||||||
const existingEntry = await db
|
resource.resourcePolicyId === null &&
|
||||||
.select()
|
resource.defaultResourcePolicyId !== null;
|
||||||
.from(roleResources)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(roleResources.resourceId, resourceId),
|
|
||||||
eq(roleResources.roleId, roleId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingEntry.length === 0) {
|
if (isInlinePolicy) {
|
||||||
return next(
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
createHttpError(
|
|
||||||
HttpCode.NOT_FOUND,
|
const existingEntry = await db
|
||||||
"Role not found in resource"
|
.select()
|
||||||
)
|
.from(rolePolicies)
|
||||||
);
|
.where(
|
||||||
|
and(
|
||||||
|
eq(rolePolicies.resourcePolicyId, policyId),
|
||||||
|
eq(rolePolicies.roleId, roleId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
"Role not found in resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db
|
||||||
|
.delete(rolePolicies)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(rolePolicies.resourcePolicyId, policyId),
|
||||||
|
eq(rolePolicies.roleId, roleId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Check if role exists in resource
|
||||||
|
const existingEntry = await db
|
||||||
|
.select()
|
||||||
|
.from(roleResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(roleResources.resourceId, resourceId),
|
||||||
|
eq(roleResources.roleId, roleId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
"Role not found in resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db
|
||||||
|
.delete(roleResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(roleResources.resourceId, resourceId),
|
||||||
|
eq(roleResources.roleId, roleId)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db
|
|
||||||
.delete(roleResources)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(roleResources.resourceId, resourceId),
|
|
||||||
eq(roleResources.roleId, roleId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return response(res, {
|
return response(res, {
|
||||||
data: {},
|
data: {},
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, resources } from "@server/db";
|
import { db, resources } from "@server/db";
|
||||||
import { userResources } from "@server/db";
|
import { userResources, userPolicies } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -103,35 +103,71 @@ export async function removeUserFromResource(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user exists in resource
|
const isInlinePolicy =
|
||||||
const existingEntry = await db
|
resource.resourcePolicyId === null &&
|
||||||
.select()
|
resource.defaultResourcePolicyId !== null;
|
||||||
.from(userResources)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(userResources.resourceId, resourceId),
|
|
||||||
eq(userResources.userId, userId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingEntry.length === 0) {
|
if (isInlinePolicy) {
|
||||||
return next(
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
createHttpError(
|
|
||||||
HttpCode.NOT_FOUND,
|
const existingEntry = await db
|
||||||
"User not found in resource"
|
.select()
|
||||||
)
|
.from(userPolicies)
|
||||||
);
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userPolicies.resourcePolicyId, policyId),
|
||||||
|
eq(userPolicies.userId, userId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
"User not found in resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db
|
||||||
|
.delete(userPolicies)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userPolicies.resourcePolicyId, policyId),
|
||||||
|
eq(userPolicies.userId, userId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Check if user exists in resource
|
||||||
|
const existingEntry = await db
|
||||||
|
.select()
|
||||||
|
.from(userResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userResources.resourceId, resourceId),
|
||||||
|
eq(userResources.userId, userId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingEntry.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
"User not found in resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await db
|
||||||
|
.delete(userResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userResources.resourceId, resourceId),
|
||||||
|
eq(userResources.userId, userId)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await db
|
|
||||||
.delete(userResources)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(userResources.resourceId, resourceId),
|
|
||||||
eq(userResources.userId, userId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return response(res, {
|
return response(res, {
|
||||||
data: {},
|
data: {},
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import { z } from "zod";
|
|||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
resourceHeaderAuth,
|
resourceHeaderAuth,
|
||||||
resourceHeaderAuthExtendedCompatibility
|
resourceHeaderAuthExtendedCompatibility,
|
||||||
|
resourcePolicyHeaderAuth,
|
||||||
|
resources
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
@@ -89,36 +91,73 @@ export async function setResourceHeaderAuth(
|
|||||||
const { resourceId } = parsedParams.data;
|
const { resourceId } = parsedParams.data;
|
||||||
const { user, password, extendedCompatibility } = parsedBody.data;
|
const { user, password, extendedCompatibility } = parsedBody.data;
|
||||||
|
|
||||||
|
const [resource] = await db
|
||||||
|
.select()
|
||||||
|
.from(resources)
|
||||||
|
.where(eq(resources.resourceId, resourceId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
await trx
|
if (isInlinePolicy) {
|
||||||
.delete(resourceHeaderAuth)
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
.where(eq(resourceHeaderAuth.resourceId, resourceId));
|
await trx
|
||||||
await trx
|
.delete(resourcePolicyHeaderAuth)
|
||||||
.delete(resourceHeaderAuthExtendedCompatibility)
|
.where(
|
||||||
.where(
|
eq(resourcePolicyHeaderAuth.resourcePolicyId, policyId)
|
||||||
eq(
|
);
|
||||||
resourceHeaderAuthExtendedCompatibility.resourceId,
|
|
||||||
resourceId
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (user && password && extendedCompatibility !== null) {
|
if (user && password && extendedCompatibility !== null) {
|
||||||
const headerAuthHash = await hashPassword(
|
const headerAuthHash = await hashPassword(
|
||||||
Buffer.from(`${user}:${password}`).toString("base64")
|
Buffer.from(`${user}:${password}`).toString("base64")
|
||||||
);
|
);
|
||||||
|
|
||||||
await Promise.all([
|
await trx.insert(resourcePolicyHeaderAuth).values({
|
||||||
trx
|
resourcePolicyId: policyId,
|
||||||
.insert(resourceHeaderAuth)
|
headerAuthHash,
|
||||||
.values({ resourceId, headerAuthHash }),
|
extendedCompatibility: extendedCompatibility!
|
||||||
trx
|
});
|
||||||
.insert(resourceHeaderAuthExtendedCompatibility)
|
}
|
||||||
.values({
|
} else {
|
||||||
resourceId,
|
await trx
|
||||||
extendedCompatibilityIsActivated:
|
.delete(resourceHeaderAuth)
|
||||||
extendedCompatibility
|
.where(eq(resourceHeaderAuth.resourceId, resourceId));
|
||||||
})
|
await trx
|
||||||
]);
|
.delete(resourceHeaderAuthExtendedCompatibility)
|
||||||
|
.where(
|
||||||
|
eq(
|
||||||
|
resourceHeaderAuthExtendedCompatibility.resourceId,
|
||||||
|
resourceId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (user && password && extendedCompatibility !== null) {
|
||||||
|
const headerAuthHash = await hashPassword(
|
||||||
|
Buffer.from(`${user}:${password}`).toString("base64")
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
trx
|
||||||
|
.insert(resourceHeaderAuth)
|
||||||
|
.values({ resourceId, headerAuthHash }),
|
||||||
|
trx
|
||||||
|
.insert(resourceHeaderAuthExtendedCompatibility)
|
||||||
|
.values({
|
||||||
|
resourceId,
|
||||||
|
extendedCompatibilityIsActivated:
|
||||||
|
extendedCompatibility
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resourcePassword } from "@server/db";
|
import {
|
||||||
|
resourcePassword,
|
||||||
|
resourcePolicyPassword,
|
||||||
|
resources
|
||||||
|
} from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -85,17 +89,49 @@ export async function setResourcePassword(
|
|||||||
const { resourceId } = parsedParams.data;
|
const { resourceId } = parsedParams.data;
|
||||||
const { password } = parsedBody.data;
|
const { password } = parsedBody.data;
|
||||||
|
|
||||||
|
const [resource] = await db
|
||||||
|
.select()
|
||||||
|
.from(resources)
|
||||||
|
.where(eq(resources.resourceId, resourceId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
await trx
|
if (isInlinePolicy) {
|
||||||
.delete(resourcePassword)
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
.where(eq(resourcePassword.resourceId, resourceId));
|
|
||||||
|
|
||||||
if (password) {
|
|
||||||
const passwordHash = await hashPassword(password);
|
|
||||||
|
|
||||||
await trx
|
await trx
|
||||||
.insert(resourcePassword)
|
.delete(resourcePolicyPassword)
|
||||||
.values({ resourceId, passwordHash });
|
.where(
|
||||||
|
eq(resourcePolicyPassword.resourcePolicyId, policyId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (password) {
|
||||||
|
const passwordHash = await hashPassword(password);
|
||||||
|
await trx
|
||||||
|
.insert(resourcePolicyPassword)
|
||||||
|
.values({ resourcePolicyId: policyId, passwordHash });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await trx
|
||||||
|
.delete(resourcePassword)
|
||||||
|
.where(eq(resourcePassword.resourceId, resourceId));
|
||||||
|
|
||||||
|
if (password) {
|
||||||
|
const passwordHash = await hashPassword(password);
|
||||||
|
|
||||||
|
await trx
|
||||||
|
.insert(resourcePassword)
|
||||||
|
.values({ resourceId, passwordHash });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resourcePincode } from "@server/db";
|
import { resourcePincode, resourcePolicyPincode, resources } from "@server/db";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -89,17 +89,51 @@ export async function setResourcePincode(
|
|||||||
const { resourceId } = parsedParams.data;
|
const { resourceId } = parsedParams.data;
|
||||||
const { pincode } = parsedBody.data;
|
const { pincode } = parsedBody.data;
|
||||||
|
|
||||||
|
const [resource] = await db
|
||||||
|
.select()
|
||||||
|
.from(resources)
|
||||||
|
.where(eq(resources.resourceId, resourceId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
return next(
|
||||||
|
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
await trx
|
if (isInlinePolicy) {
|
||||||
.delete(resourcePincode)
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
.where(eq(resourcePincode.resourceId, resourceId));
|
|
||||||
|
|
||||||
if (pincode) {
|
|
||||||
const pincodeHash = await hashPassword(pincode);
|
|
||||||
|
|
||||||
await trx
|
await trx
|
||||||
.insert(resourcePincode)
|
.delete(resourcePolicyPincode)
|
||||||
.values({ resourceId, pincodeHash, digitLength: 6 });
|
.where(
|
||||||
|
eq(resourcePolicyPincode.resourcePolicyId, policyId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pincode) {
|
||||||
|
const pincodeHash = await hashPassword(pincode);
|
||||||
|
await trx.insert(resourcePolicyPincode).values({
|
||||||
|
resourcePolicyId: policyId,
|
||||||
|
pincodeHash,
|
||||||
|
digitLength: 6
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await trx
|
||||||
|
.delete(resourcePincode)
|
||||||
|
.where(eq(resourcePincode.resourceId, resourceId));
|
||||||
|
|
||||||
|
if (pincode) {
|
||||||
|
const pincodeHash = await hashPassword(pincode);
|
||||||
|
|
||||||
|
await trx
|
||||||
|
.insert(resourcePincode)
|
||||||
|
.values({ resourceId, pincodeHash, digitLength: 6 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db, resources } from "@server/db";
|
import { db, resources } from "@server/db";
|
||||||
import { apiKeys, roleResources, roles } from "@server/db";
|
import { apiKeys, roleResources, roles, rolePolicies } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -129,28 +129,61 @@ export async function setResourceRoles(
|
|||||||
);
|
);
|
||||||
const adminRoleIds = adminRoles.map((role) => role.roleId);
|
const adminRoleIds = adminRoles.map((role) => role.roleId);
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
await db.transaction(async (trx) => {
|
await db.transaction(async (trx) => {
|
||||||
if (adminRoleIds.length > 0) {
|
if (isInlinePolicy) {
|
||||||
await trx.delete(roleResources).where(
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
and(
|
|
||||||
eq(roleResources.resourceId, resourceId),
|
// For inline policy, preserve admin roles by only deleting non-admin entries
|
||||||
ne(roleResources.roleId, adminRoleIds[0]) // delete all but the admin role
|
if (adminRoleIds.length > 0) {
|
||||||
|
await trx
|
||||||
|
.delete(rolePolicies)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(rolePolicies.resourcePolicyId, policyId),
|
||||||
|
ne(rolePolicies.roleId, adminRoleIds[0])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await trx
|
||||||
|
.delete(rolePolicies)
|
||||||
|
.where(eq(rolePolicies.resourcePolicyId, policyId));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
roleIds.map((roleId) =>
|
||||||
|
trx
|
||||||
|
.insert(rolePolicies)
|
||||||
|
.values({ roleId, resourcePolicyId: policyId })
|
||||||
|
.returning()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await trx
|
if (adminRoleIds.length > 0) {
|
||||||
.delete(roleResources)
|
await trx.delete(roleResources).where(
|
||||||
.where(eq(roleResources.resourceId, resourceId));
|
and(
|
||||||
}
|
eq(roleResources.resourceId, resourceId),
|
||||||
|
ne(roleResources.roleId, adminRoleIds[0]) // delete all but the admin role
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await trx
|
||||||
|
.delete(roleResources)
|
||||||
|
.where(eq(roleResources.resourceId, resourceId));
|
||||||
|
}
|
||||||
|
|
||||||
const newRoleResources = await Promise.all(
|
await Promise.all(
|
||||||
roleIds.map((roleId) =>
|
roleIds.map((roleId) =>
|
||||||
trx
|
trx
|
||||||
.insert(roleResources)
|
.insert(roleResources)
|
||||||
.values({ roleId, resourceId })
|
.values({ roleId, resourceId })
|
||||||
.returning()
|
.returning()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return response(res, {
|
return response(res, {
|
||||||
data: {},
|
data: {},
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { userResources } from "@server/db";
|
import { userResources, userPolicies, resources } from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -82,19 +82,51 @@ export async function setResourceUsers(
|
|||||||
|
|
||||||
const { resourceId } = parsedParams.data;
|
const { resourceId } = parsedParams.data;
|
||||||
|
|
||||||
await db.transaction(async (trx) => {
|
const [resource] = await db
|
||||||
await trx
|
.select()
|
||||||
.delete(userResources)
|
.from(resources)
|
||||||
.where(eq(userResources.resourceId, resourceId));
|
.where(eq(resources.resourceId, resourceId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
const newUserResources = await Promise.all(
|
if (!resource) {
|
||||||
userIds.map((userId) =>
|
return next(
|
||||||
trx
|
createHttpError(HttpCode.NOT_FOUND, "Resource not found")
|
||||||
.insert(userResources)
|
|
||||||
.values({ userId, resourceId })
|
|
||||||
.returning()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
|
await db.transaction(async (trx) => {
|
||||||
|
if (isInlinePolicy) {
|
||||||
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
|
await trx
|
||||||
|
.delete(userPolicies)
|
||||||
|
.where(eq(userPolicies.resourcePolicyId, policyId));
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
userIds.map((userId) =>
|
||||||
|
trx
|
||||||
|
.insert(userPolicies)
|
||||||
|
.values({ userId, resourcePolicyId: policyId })
|
||||||
|
.returning()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await trx
|
||||||
|
.delete(userResources)
|
||||||
|
.where(eq(userResources.resourceId, resourceId));
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
userIds.map((userId) =>
|
||||||
|
trx
|
||||||
|
.insert(userResources)
|
||||||
|
.values({ userId, resourceId })
|
||||||
|
.returning()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return response(res, {
|
return response(res, {
|
||||||
data: {},
|
data: {},
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import { Request, Response, NextFunction } from "express";
|
import { Request, Response, NextFunction } from "express";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { resources, resourceWhitelist } from "@server/db";
|
import {
|
||||||
|
resources,
|
||||||
|
resourceWhitelist,
|
||||||
|
resourcePolicies,
|
||||||
|
resourcePolicyWhiteList
|
||||||
|
} from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
@@ -104,57 +109,135 @@ export async function setResourceWhitelist(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resource.emailWhitelistEnabled) {
|
const isInlinePolicy =
|
||||||
return next(
|
resource.resourcePolicyId === null &&
|
||||||
createHttpError(
|
resource.defaultResourcePolicyId !== null;
|
||||||
HttpCode.BAD_REQUEST,
|
|
||||||
"Email whitelist is not enabled for this resource"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const whitelist = await db
|
if (isInlinePolicy) {
|
||||||
.select()
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
.from(resourceWhitelist)
|
|
||||||
.where(eq(resourceWhitelist.resourceId, resourceId));
|
|
||||||
|
|
||||||
await db.transaction(async (trx) => {
|
const [policy] = await db
|
||||||
// diff the emails
|
.select()
|
||||||
const existingEmails = whitelist.map((w) => w.email);
|
.from(resourcePolicies)
|
||||||
|
.where(eq(resourcePolicies.resourcePolicyId, policyId));
|
||||||
|
|
||||||
const emailsToAdd = emails.filter(
|
if (!policy) {
|
||||||
(e) => !existingEmails.includes(e)
|
return next(
|
||||||
);
|
createHttpError(
|
||||||
const emailsToRemove = existingEmails.filter(
|
HttpCode.NOT_FOUND,
|
||||||
(e) => !emails.includes(e)
|
"Resource policy not found"
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for (const email of emailsToAdd) {
|
if (!policy.emailWhitelistEnabled) {
|
||||||
await trx.insert(resourceWhitelist).values({
|
return next(
|
||||||
email,
|
createHttpError(
|
||||||
resourceId
|
HttpCode.BAD_REQUEST,
|
||||||
|
"Email whitelist is not enabled for this resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingPolicyWhitelist = await db
|
||||||
|
.select()
|
||||||
|
.from(resourcePolicyWhiteList)
|
||||||
|
.where(eq(resourcePolicyWhiteList.resourcePolicyId, policyId));
|
||||||
|
|
||||||
|
await db.transaction(async (trx) => {
|
||||||
|
const existingEmails = existingPolicyWhitelist.map(
|
||||||
|
(w) => w.email
|
||||||
|
);
|
||||||
|
|
||||||
|
const emailsToAdd = emails.filter(
|
||||||
|
(e) => !existingEmails.includes(e)
|
||||||
|
);
|
||||||
|
const emailsToRemove = existingEmails.filter(
|
||||||
|
(e) => !emails.includes(e)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const email of emailsToAdd) {
|
||||||
|
await trx.insert(resourcePolicyWhiteList).values({
|
||||||
|
email,
|
||||||
|
resourcePolicyId: policyId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const email of emailsToRemove) {
|
||||||
|
await trx
|
||||||
|
.delete(resourcePolicyWhiteList)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(
|
||||||
|
resourcePolicyWhiteList.resourcePolicyId,
|
||||||
|
policyId
|
||||||
|
),
|
||||||
|
eq(resourcePolicyWhiteList.email, email)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: {},
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Whitelist set for resource successfully",
|
||||||
|
status: HttpCode.CREATED
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
for (const email of emailsToRemove) {
|
|
||||||
await trx
|
|
||||||
.delete(resourceWhitelist)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(resourceWhitelist.resourceId, resourceId),
|
|
||||||
eq(resourceWhitelist.email, email)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response(res, {
|
|
||||||
data: {},
|
|
||||||
success: true,
|
|
||||||
error: false,
|
|
||||||
message: "Whitelist set for resource successfully",
|
|
||||||
status: HttpCode.CREATED
|
|
||||||
});
|
});
|
||||||
});
|
} else {
|
||||||
|
if (!resource.emailWhitelistEnabled) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.BAD_REQUEST,
|
||||||
|
"Email whitelist is not enabled for this resource"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const whitelist = await db
|
||||||
|
.select()
|
||||||
|
.from(resourceWhitelist)
|
||||||
|
.where(eq(resourceWhitelist.resourceId, resourceId));
|
||||||
|
|
||||||
|
await db.transaction(async (trx) => {
|
||||||
|
// diff the emails
|
||||||
|
const existingEmails = whitelist.map((w) => w.email);
|
||||||
|
|
||||||
|
const emailsToAdd = emails.filter(
|
||||||
|
(e) => !existingEmails.includes(e)
|
||||||
|
);
|
||||||
|
const emailsToRemove = existingEmails.filter(
|
||||||
|
(e) => !emails.includes(e)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const email of emailsToAdd) {
|
||||||
|
await trx.insert(resourceWhitelist).values({
|
||||||
|
email,
|
||||||
|
resourceId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const email of emailsToRemove) {
|
||||||
|
await trx
|
||||||
|
.delete(resourceWhitelist)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resourceWhitelist.resourceId, resourceId),
|
||||||
|
eq(resourceWhitelist.email, email)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: {},
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "Whitelist set for resource successfully",
|
||||||
|
status: HttpCode.CREATED
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
return next(
|
return next(
|
||||||
|
|||||||
@@ -549,6 +549,58 @@ async function updateHttpResource(
|
|||||||
updateData.maintenanceEstimatedTime = undefined;
|
updateData.maintenanceEstimatedTime = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isInlinePolicy =
|
||||||
|
resource.resourcePolicyId === null &&
|
||||||
|
resource.defaultResourcePolicyId !== null;
|
||||||
|
|
||||||
|
if (isInlinePolicy) {
|
||||||
|
const policyId = resource.defaultResourcePolicyId!;
|
||||||
|
const {
|
||||||
|
sso,
|
||||||
|
emailWhitelistEnabled,
|
||||||
|
applyRules,
|
||||||
|
skipToIdpId,
|
||||||
|
...resourceOnlyData
|
||||||
|
} = updateData;
|
||||||
|
|
||||||
|
const policyUpdate: Record<string, unknown> = {};
|
||||||
|
if (sso !== undefined) policyUpdate.sso = sso;
|
||||||
|
if (emailWhitelistEnabled !== undefined)
|
||||||
|
policyUpdate.emailWhitelistEnabled = emailWhitelistEnabled;
|
||||||
|
if (applyRules !== undefined) policyUpdate.applyRules = applyRules;
|
||||||
|
if (skipToIdpId !== undefined) policyUpdate.idpId = skipToIdpId;
|
||||||
|
|
||||||
|
if (Object.keys(policyUpdate).length > 0) {
|
||||||
|
await db
|
||||||
|
.update(resourcePolicies)
|
||||||
|
.set(policyUpdate)
|
||||||
|
.where(eq(resourcePolicies.resourcePolicyId, policyId));
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedResource = await db
|
||||||
|
.update(resources)
|
||||||
|
.set({ ...resourceOnlyData, headers })
|
||||||
|
.where(eq(resources.resourceId, resource.resourceId))
|
||||||
|
.returning();
|
||||||
|
|
||||||
|
if (updatedResource.length === 0) {
|
||||||
|
return next(
|
||||||
|
createHttpError(
|
||||||
|
HttpCode.NOT_FOUND,
|
||||||
|
`Resource with ID ${resource.resourceId} not found`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response(res, {
|
||||||
|
data: updatedResource[0],
|
||||||
|
success: true,
|
||||||
|
error: false,
|
||||||
|
message: "HTTP resource updated successfully",
|
||||||
|
status: HttpCode.OK
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const updatedResource = await db
|
const updatedResource = await db
|
||||||
.update(resources)
|
.update(resources)
|
||||||
.set({ ...updateData, headers })
|
.set({ ...updateData, headers })
|
||||||
|
|||||||
Reference in New Issue
Block a user