Merge dev into fix/log-analytics-adjustments

This commit is contained in:
Fred KISSIE
2025-12-10 03:19:14 +01:00
parent 9db2feff77
commit d490cab48c
555 changed files with 9375 additions and 9287 deletions

View File

@@ -11,21 +11,19 @@ import { and, eq } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi";
const addEmailToResourceWhitelistBodySchema = z.strictObject({
email: z.email()
.or(
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
error: "Invalid email address. Wildcard (*) must be the entire local part."
})
)
.transform((v) => v.toLowerCase())
});
email: z
.email()
.or(
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
error: "Invalid email address. Wildcard (*) must be the entire local part."
})
)
.transform((v) => v.toLowerCase())
});
const addEmailToResourceWhitelistParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",

View File

@@ -93,10 +93,7 @@ export async function addRoleToResource(
.select()
.from(roles)
.where(
and(
eq(roles.roleId, roleId),
eq(roles.orgId, resource.orgId)
)
and(eq(roles.roleId, roleId), eq(roles.orgId, resource.orgId))
)
.limit(1);
@@ -158,4 +155,3 @@ export async function addRoleToResource(
);
}
}

View File

@@ -127,4 +127,3 @@ export async function addUserToResource(
);
}
}

View File

@@ -16,17 +16,17 @@ import stoi from "@server/lib/stoi";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
const authWithAccessTokenBodySchema = z.strictObject({
accessToken: z.string(),
accessTokenId: z.string().optional()
});
accessToken: z.string(),
accessTokenId: z.string().optional()
});
const authWithAccessTokenParamsSchema = z.strictObject({
resourceId: z
.string()
.optional()
.transform(stoi)
.pipe(z.int().positive().optional())
});
resourceId: z
.string()
.optional()
.transform(stoi)
.pipe(z.int().positive().optional())
});
export type AuthWithAccessTokenResponse = {
session?: string;

View File

@@ -16,15 +16,12 @@ import config from "@server/lib/config";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
export const authWithPasswordBodySchema = z.strictObject({
password: z.string()
});
password: z.string()
});
export const authWithPasswordParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
export type AuthWithPasswordResponse = {
session?: string;

View File

@@ -15,15 +15,12 @@ import config from "@server/lib/config";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
export const authWithPincodeBodySchema = z.strictObject({
pincode: z.string()
});
pincode: z.string()
});
export const authWithPincodeParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
export type AuthWithPincodeResponse = {
session?: string;

View File

@@ -15,16 +15,13 @@ import config from "@server/lib/config";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
const authWithWhitelistBodySchema = z.strictObject({
email: z.email().toLowerCase(),
otp: z.string().optional()
});
email: z.email().toLowerCase(),
otp: z.string().optional()
});
const authWithWhitelistParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
export type AuthWithWhitelistResponse = {
otpSent?: boolean;

View File

@@ -26,16 +26,17 @@ import { getUniqueResourceName } from "@server/db/names";
import { validateAndConstructDomain } from "@server/lib/domainUtils";
const createResourceParamsSchema = z.strictObject({
orgId: z.string()
});
orgId: z.string()
});
const createHttpResourceSchema = z.strictObject({
const createHttpResourceSchema = z
.strictObject({
name: z.string().min(1).max(255),
subdomain: z.string().nullable().optional(),
http: z.boolean(),
protocol: z.enum(["tcp", "udp"]),
domainId: z.string(),
stickySession: z.boolean().optional(),
stickySession: z.boolean().optional()
})
.refine(
(data) => {
@@ -49,7 +50,8 @@ const createHttpResourceSchema = z.strictObject({
}
);
const createRawResourceSchema = z.strictObject({
const createRawResourceSchema = z
.strictObject({
name: z.string().min(1).max(255),
http: z.boolean(),
protocol: z.enum(["tcp", "udp"]),
@@ -188,7 +190,7 @@ async function createHttpResource(
const { name, domainId } = parsedBody.data;
const subdomain = parsedBody.data.subdomain;
const stickySession=parsedBody.data.stickySession;
const stickySession = parsedBody.data.stickySession;
// Validate domain and construct full domain
const domainResult = await validateAndConstructDomain(

View File

@@ -16,19 +16,16 @@ import {
import { OpenAPITags, registry } from "@server/openApi";
const createResourceRuleSchema = z.strictObject({
action: z.enum(["ACCEPT", "DROP", "PASS"]),
match: z.enum(["CIDR", "IP", "PATH", "COUNTRY"]),
value: z.string().min(1),
priority: z.int(),
enabled: z.boolean().optional()
});
action: z.enum(["ACCEPT", "DROP", "PASS"]),
match: z.enum(["CIDR", "IP", "PATH", "COUNTRY"]),
value: z.string().min(1),
priority: z.int(),
enabled: z.boolean().optional()
});
const createResourceRuleParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "put",

View File

@@ -15,11 +15,8 @@ import { OpenAPITags, registry } from "@server/openApi";
// Define Zod schema for request parameters validation
const deleteResourceSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "delete",

View File

@@ -11,12 +11,9 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
const deleteResourceRuleSchema = z.strictObject({
ruleId: z.string().transform(Number).pipe(z.int().positive()),
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
ruleId: z.string().transform(Number).pipe(z.int().positive()),
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "delete",

View File

@@ -17,11 +17,8 @@ import { checkOrgAccessPolicy } from "#dynamic/lib/checkOrgAccessPolicy";
import { logAccessAudit } from "#dynamic/lib/logAccessAudit";
const getExchangeTokenParams = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
export type GetExchangeTokenResponse = {
requestToken: string;

View File

@@ -12,15 +12,15 @@ import stoi from "@server/lib/stoi";
import { OpenAPITags, registry } from "@server/openApi";
const getResourceSchema = z.strictObject({
resourceId: z
.string()
.optional()
.transform(stoi)
.pipe(z.int().positive().optional())
.optional(),
niceId: z.string().optional(),
orgId: z.string().optional()
});
resourceId: z
.string()
.optional()
.transform(stoi)
.pipe(z.int().positive().optional())
.optional(),
niceId: z.string().optional(),
orgId: z.string().optional()
});
async function query(resourceId?: number, niceId?: string, orgId?: string) {
if (resourceId) {
@@ -34,13 +34,18 @@ async function query(resourceId?: number, niceId?: string, orgId?: string) {
const [res] = await db
.select()
.from(resources)
.where(and(eq(resources.niceId, niceId), eq(resources.orgId, orgId)))
.where(
and(eq(resources.niceId, niceId), eq(resources.orgId, orgId))
)
.limit(1);
return res;
}
}
export type GetResourceResponse = Omit<NonNullable<Awaited<ReturnType<typeof query>>>, 'headers'> & {
export type GetResourceResponse = Omit<
NonNullable<Awaited<ReturnType<typeof query>>>,
"headers"
> & {
headers: { name: string; value: string }[] | null;
};
@@ -101,7 +106,9 @@ export async function getResource(
return response<GetResourceResponse>(res, {
data: {
...resource,
headers: resource.headers ? JSON.parse(resource.headers) : resource.headers
headers: resource.headers
? JSON.parse(resource.headers)
: resource.headers
},
success: true,
error: false,

View File

@@ -16,8 +16,8 @@ import logger from "@server/logger";
import { build } from "@server/build";
const getResourceAuthInfoSchema = z.strictObject({
resourceGuid: z.string()
});
resourceGuid: z.string()
});
export type GetResourceAuthInfoResponse = {
resourceId: number;

View File

@@ -11,11 +11,8 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
const getResourceWhitelistSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
async function queryWhitelist(resourceId: number) {
return await db

View File

@@ -11,11 +11,8 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
const listResourceRolesSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
async function query(resourceId: number) {
return await db

View File

@@ -11,11 +11,8 @@ import logger from "@server/logger";
import { OpenAPITags, registry } from "@server/openApi";
const listResourceRulesParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
const listResourceRulesSchema = z.object({
limit: z

View File

@@ -11,11 +11,8 @@ import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi";
const listResourceUsersSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
async function queryUsers(resourceId: number) {
return await db

View File

@@ -11,21 +11,19 @@ import { and, eq } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi";
const removeEmailFromResourceWhitelistBodySchema = z.strictObject({
email: z.email()
.or(
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
error: "Invalid email address. Wildcard (*) must be the entire local part."
})
)
.transform((v) => v.toLowerCase())
});
email: z
.email()
.or(
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
error: "Invalid email address. Wildcard (*) must be the entire local part."
})
)
.transform((v) => v.toLowerCase())
});
const removeEmailFromResourceWhitelistParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",

View File

@@ -49,9 +49,7 @@ export async function removeRoleFromResource(
next: NextFunction
): Promise<any> {
try {
const parsedBody = removeRoleFromResourceBodySchema.safeParse(
req.body
);
const parsedBody = removeRoleFromResourceBodySchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
@@ -95,10 +93,7 @@ export async function removeRoleFromResource(
.select()
.from(roles)
.where(
and(
eq(roles.roleId, roleId),
eq(roles.orgId, resource.orgId)
)
and(eq(roles.roleId, roleId), eq(roles.orgId, resource.orgId))
)
.limit(1);
@@ -163,4 +158,3 @@ export async function removeRoleFromResource(
);
}
}

View File

@@ -49,9 +49,7 @@ export async function removeUserFromResource(
next: NextFunction
): Promise<any> {
try {
const parsedBody = removeUserFromResourceBodySchema.safeParse(
req.body
);
const parsedBody = removeUserFromResourceBodySchema.safeParse(req.body);
if (!parsedBody.success) {
return next(
createHttpError(
@@ -133,4 +131,3 @@ export async function removeUserFromResource(
);
}
}

View File

@@ -15,9 +15,9 @@ const setResourceAuthMethodsParamsSchema = z.object({
});
const setResourceAuthMethodsBodySchema = z.strictObject({
user: z.string().min(4).max(100).nullable(),
password: z.string().min(4).max(100).nullable()
});
user: z.string().min(4).max(100).nullable(),
password: z.string().min(4).max(100).nullable()
});
registry.registerPath({
method: "post",
@@ -75,7 +75,9 @@ export async function setResourceHeaderAuth(
.where(eq(resourceHeaderAuth.resourceId, resourceId));
if (user && password) {
const headerAuthHash = await hashPassword(Buffer.from(`${user}:${password}`).toString("base64"));
const headerAuthHash = await hashPassword(
Buffer.from(`${user}:${password}`).toString("base64")
);
await trx
.insert(resourceHeaderAuth)

View File

@@ -17,8 +17,8 @@ const setResourceAuthMethodsParamsSchema = z.object({
});
const setResourceAuthMethodsBodySchema = z.strictObject({
password: z.string().min(4).max(100).nullable()
});
password: z.string().min(4).max(100).nullable()
});
registry.registerPath({
method: "post",

View File

@@ -18,11 +18,11 @@ const setResourceAuthMethodsParamsSchema = z.object({
});
const setResourceAuthMethodsBodySchema = z.strictObject({
pincode: z
.string()
.regex(/^\d{6}$/)
.or(z.null())
});
pincode: z
.string()
.regex(/^\d{6}$/)
.or(z.null())
});
registry.registerPath({
method: "post",

View File

@@ -11,15 +11,12 @@ import { eq, and, ne, inArray } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi";
const setResourceRolesBodySchema = z.strictObject({
roleIds: z.array(z.int().positive())
});
roleIds: z.array(z.int().positive())
});
const setResourceRolesParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",
@@ -113,10 +110,7 @@ export async function setResourceRoles(
.select()
.from(roles)
.where(
and(
eq(roles.isAdmin, true),
eq(roles.orgId, resource.orgId)
)
and(eq(roles.isAdmin, true), eq(roles.orgId, resource.orgId))
);
const adminRoleIds = adminRoles.map((role) => role.roleId);
@@ -129,9 +123,9 @@ export async function setResourceRoles(
)
);
} else {
await trx.delete(roleResources).where(
eq(roleResources.resourceId, resourceId)
);
await trx
.delete(roleResources)
.where(eq(roleResources.resourceId, resourceId));
}
const newRoleResources = await Promise.all(
@@ -158,4 +152,3 @@ export async function setResourceRoles(
);
}
}

View File

@@ -11,15 +11,12 @@ import { eq } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi";
const setUserResourcesBodySchema = z.strictObject({
userIds: z.array(z.string())
});
userIds: z.array(z.string())
});
const setUserResourcesParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",

View File

@@ -11,25 +11,21 @@ import { and, eq } from "drizzle-orm";
import { OpenAPITags, registry } from "@server/openApi";
const setResourceWhitelistBodySchema = z.strictObject({
emails: z
.array(
z.email()
.or(
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
error: "Invalid email address. Wildcard (*) must be the entire local part."
})
)
emails: z
.array(
z.email().or(
z.string().regex(/^\*@[\w.-]+\.[a-zA-Z]{2,}$/, {
error: "Invalid email address. Wildcard (*) must be the entire local part."
})
)
.max(50)
.transform((v) => v.map((e) => e.toLowerCase()))
});
)
.max(50)
.transform((v) => v.map((e) => e.toLowerCase()))
});
const setResourceWhitelistParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
registry.registerPath({
method: "post",

View File

@@ -26,13 +26,11 @@ import { validateHeaders } from "@server/lib/validators";
import { build } from "@server/build";
const updateResourceParamsSchema = z.strictObject({
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
const updateHttpResourceBodySchema = z.strictObject({
const updateHttpResourceBodySchema = z
.strictObject({
name: z.string().min(1).max(255).optional(),
niceId: z.string().min(1).max(255).optional(),
subdomain: subdomainSchema.nullable().optional(),
@@ -91,7 +89,8 @@ const updateHttpResourceBodySchema = z.strictObject({
export type UpdateResourceResponse = Resource;
const updateRawResourceBodySchema = z.strictObject({
const updateRawResourceBodySchema = z
.strictObject({
name: z.string().min(1).max(255).optional(),
niceId: z.string().min(1).max(255).optional(),
proxyPort: z.int().min(1).max(65535).optional(),
@@ -239,11 +238,11 @@ async function updateHttpResource(
.select()
.from(resources)
.where(
and(
eq(resources.niceId, updateData.niceId),
eq(resources.orgId, resource.orgId)
)
);
and(
eq(resources.niceId, updateData.niceId),
eq(resources.orgId, resource.orgId)
)
);
if (
existingResource &&
@@ -391,11 +390,11 @@ async function updateRawResource(
.select()
.from(resources)
.where(
and(
eq(resources.niceId, updateData.niceId),
eq(resources.orgId, resource.orgId)
)
);
and(
eq(resources.niceId, updateData.niceId),
eq(resources.orgId, resource.orgId)
)
);
if (
existingResource &&

View File

@@ -17,15 +17,13 @@ import { OpenAPITags, registry } from "@server/openApi";
// Define Zod schema for request parameters validation
const updateResourceRuleParamsSchema = z.strictObject({
ruleId: z.string().transform(Number).pipe(z.int().positive()),
resourceId: z
.string()
.transform(Number)
.pipe(z.int().positive())
});
ruleId: z.string().transform(Number).pipe(z.int().positive()),
resourceId: z.string().transform(Number).pipe(z.int().positive())
});
// Define Zod schema for request body validation
const updateResourceRuleSchema = z.strictObject({
const updateResourceRuleSchema = z
.strictObject({
action: z.enum(["ACCEPT", "DROP", "PASS"]).optional(),
match: z.enum(["CIDR", "IP", "PATH", "COUNTRY"]).optional(),
value: z.string().min(1).optional(),