Accept resource as either niceId or alias

This commit is contained in:
Owen
2026-02-16 15:29:23 -08:00
parent 9cf59c409e
commit f0b9240575
3 changed files with 29 additions and 16 deletions

View File

@@ -20,7 +20,7 @@ import createHttpError from "http-errors";
import logger from "@server/logger"; import logger from "@server/logger";
import { fromError } from "zod-validation-error"; import { fromError } from "zod-validation-error";
import { OpenAPITags, registry } from "@server/openApi"; import { OpenAPITags, registry } from "@server/openApi";
import { eq, or } from "drizzle-orm"; import { eq, or, and } from "drizzle-orm";
import { canUserAccessSiteResource } from "@server/auth/canUserAccessSiteResource"; import { canUserAccessSiteResource } from "@server/auth/canUserAccessSiteResource";
import { signPublicKey, getOrgCAKeys } from "#private/lib/sshCA"; import { signPublicKey, getOrgCAKeys } from "#private/lib/sshCA";
import config from "@server/lib/config"; import config from "@server/lib/config";
@@ -33,12 +33,11 @@ const bodySchema = z
.strictObject({ .strictObject({
publicKey: z.string().nonempty(), publicKey: z.string().nonempty(),
resourceId: z.number().int().positive().optional(), resourceId: z.number().int().positive().optional(),
niceId: z.string().nonempty().optional(), resource: z.string().nonempty().optional() // this is either the nice id or the alias
alias: z.string().nonempty().optional()
}) })
.refine( .refine(
(data) => { (data) => {
const fields = [data.resourceId, data.niceId, data.alias]; const fields = [data.resourceId, data.resource];
const definedFields = fields.filter((field) => field !== undefined); const definedFields = fields.filter((field) => field !== undefined);
return definedFields.length === 1; return definedFields.length === 1;
}, },
@@ -105,7 +104,11 @@ export async function signSshKey(
} }
const { orgId } = parsedParams.data; const { orgId } = parsedParams.data;
const { publicKey, resourceId, niceId, alias } = parsedBody.data; const {
publicKey,
resourceId,
resource: resourceQueryString
} = parsedBody.data;
const userId = req.user?.userId; const userId = req.user?.userId;
const roleId = req.userOrgRoleId!; const roleId = req.userOrgRoleId!;
@@ -135,10 +138,11 @@ export async function signSshKey(
let whereClause; let whereClause;
if (resourceId !== undefined) { if (resourceId !== undefined) {
whereClause = eq(siteResources.siteResourceId, resourceId); whereClause = eq(siteResources.siteResourceId, resourceId);
} else if (niceId !== undefined) { } else if (resourceQueryString !== undefined) {
whereClause = eq(siteResources.niceId, niceId); whereClause = or(
} else if (alias !== undefined) { eq(siteResources.niceId, resourceQueryString),
whereClause = eq(siteResources.alias, alias); eq(siteResources.alias, resourceQueryString)
);
} else { } else {
// This should never happen due to the schema validation, but TypeScript doesn't know that // This should never happen due to the schema validation, but TypeScript doesn't know that
return next( return next(
@@ -149,21 +153,29 @@ export async function signSshKey(
); );
} }
const [resource] = await db const resources = await db
.select() .select()
.from(siteResources) .from(siteResources)
.where(whereClause) .where(and(whereClause, eq(siteResources.orgId, orgId)));
.limit(1);
if (!resource) { if (!resources || resources.length === 0) {
return next(
createHttpError(HttpCode.NOT_FOUND, `Resource not found`)
);
}
if (resources.length > 1) {
// error but this should not happen because the nice id cant contain a dot and the alias has to have a dot and both have to be unique within the org so there should never be multiple matches
return next( return next(
createHttpError( createHttpError(
HttpCode.NOT_FOUND, HttpCode.BAD_REQUEST,
`Resource not found` `Multiple resources found matching the criteria`
) )
); );
} }
const resource = resources[0];
if (resource.orgId !== orgId) { if (resource.orgId !== orgId) {
return next( return next(
createHttpError( createHttpError(

View File

@@ -33,7 +33,7 @@ const updateResourceParamsSchema = z.strictObject({
const updateHttpResourceBodySchema = z const updateHttpResourceBodySchema = z
.strictObject({ .strictObject({
name: z.string().min(1).max(255).optional(), name: z.string().min(1).max(255).optional(),
niceId: z.string().min(1).max(255).optional(), niceId: z.string().min(1).max(255).regex(/^[a-zA-Z0-9-]+$/, "niceId can only contain letters, numbers, and dashes").optional(),
subdomain: subdomainSchema.nullable().optional(), subdomain: subdomainSchema.nullable().optional(),
ssl: z.boolean().optional(), ssl: z.boolean().optional(),
sso: z.boolean().optional(), sso: z.boolean().optional(),

View File

@@ -41,6 +41,7 @@ const updateSiteResourceSchema = z
.strictObject({ .strictObject({
name: z.string().min(1).max(255).optional(), name: z.string().min(1).max(255).optional(),
siteId: z.int(), siteId: z.int(),
// niceId: z.string().min(1).max(255).regex(/^[a-zA-Z0-9-]+$/, "niceId can only contain letters, numbers, and dashes").optional(),
// mode: z.enum(["host", "cidr", "port"]).optional(), // mode: z.enum(["host", "cidr", "port"]).optional(),
mode: z.enum(["host", "cidr"]).optional(), mode: z.enum(["host", "cidr"]).optional(),
// protocol: z.enum(["tcp", "udp"]).nullish(), // protocol: z.enum(["tcp", "udp"]).nullish(),