mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-15 08:49:59 +02:00
Move certificates
This commit is contained in:
@@ -1,9 +1,102 @@
|
||||
import { db, Transaction } from "@server/db";
|
||||
import { Certificate, certificates, db, domains } from "@server/db";
|
||||
import logger from "@server/logger";
|
||||
import { Transaction } from "@server/db";
|
||||
import { eq, or, and, like } from "drizzle-orm";
|
||||
|
||||
/**
|
||||
* Checks if a certificate exists for the given domain.
|
||||
* If not, creates a new certificate in 'pending' state.
|
||||
* Wildcard certs cover subdomains.
|
||||
*/
|
||||
export async function createCertificate(
|
||||
domainId: string,
|
||||
domain: string,
|
||||
trx: Transaction | typeof db
|
||||
) {
|
||||
return;
|
||||
const [domainRecord] = await trx
|
||||
.select()
|
||||
.from(domains)
|
||||
.where(eq(domains.domainId, domainId))
|
||||
.limit(1);
|
||||
|
||||
if (!domainRecord) {
|
||||
throw new Error(`Domain with ID ${domainId} not found`);
|
||||
}
|
||||
|
||||
let existing: Certificate[] = [];
|
||||
if (domainRecord.type == "ns" || domainRecord.type == "wildcard") {
|
||||
const domainLevelDown = domain.split(".").slice(1).join(".");
|
||||
const wildcardPrefixed = `*.${domainLevelDown}`;
|
||||
|
||||
existing = await trx
|
||||
.select()
|
||||
.from(certificates)
|
||||
.where(
|
||||
and(
|
||||
eq(certificates.domainId, domainId),
|
||||
or(
|
||||
eq(certificates.domain, domain),
|
||||
and(
|
||||
eq(certificates.wildcard, true),
|
||||
or(
|
||||
eq(certificates.domain, domainLevelDown),
|
||||
eq(certificates.domain, wildcardPrefixed)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// For non-NS domains, we only match exact domain names
|
||||
existing = await trx
|
||||
.select()
|
||||
.from(certificates)
|
||||
.where(
|
||||
and(
|
||||
eq(certificates.domainId, domainId),
|
||||
eq(certificates.domain, domain) // exact match for non-NS domains
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (existing.length > 0) {
|
||||
logger.info(`Certificate already exists for domain ${domain}`);
|
||||
return;
|
||||
}
|
||||
|
||||
let domainToWrite = domain;
|
||||
if (
|
||||
domainRecord.type == "wildcard" && // this is to fix the wildcard certs for traefik in self hosted NOT ON THE CLOUD
|
||||
domainRecord.preferWildcardCert &&
|
||||
!domain.startsWith("*.")
|
||||
) {
|
||||
// in this case traefik is going to generate a domain one level down so we need to store it that way
|
||||
const parts = domain.split(".");
|
||||
if (parts.length > 2) {
|
||||
domainToWrite = parts.slice(1).join(".");
|
||||
domainToWrite = `*.${domainToWrite}`;
|
||||
}
|
||||
} else if (domainRecord.type == "ns") {
|
||||
if (domain == domainRecord.baseDomain) {
|
||||
domainToWrite = domainRecord.baseDomain;
|
||||
} else {
|
||||
const parts = domain.split(".");
|
||||
if (parts.length > 2) {
|
||||
domainToWrite = parts.slice(1).join(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No cert found, create a new one in pending state
|
||||
await trx.insert(certificates).values({
|
||||
domain: domainToWrite,
|
||||
domainId,
|
||||
wildcard:
|
||||
domainRecord.type == "ns" ||
|
||||
(domainRecord.type == "wildcard" &&
|
||||
domainRecord.preferWildcardCert), // we can only create wildcard certs for NS domains
|
||||
status: "pending",
|
||||
updatedAt: Math.floor(Date.now() / 1000),
|
||||
createdAt: Math.floor(Date.now() / 1000)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
import { certificates, db, domainNamespaces, domains, orgDomains } from "@server/db";
|
||||
import response from "@server/lib/response";
|
||||
import logger from "@server/logger";
|
||||
import { type GetBatchedCertificateResponse } from "@server/routers/certificates/types";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { and, eq, inArray, isNotNull, or } from "drizzle-orm";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const getCertificateParamSchema = z.strictObject({
|
||||
orgId: z.string()
|
||||
});
|
||||
|
||||
const getCertificateQuerySchema = z.object({
|
||||
domains: z.preprocess(
|
||||
(val) => {
|
||||
if (val === undefined || val === null || val === "") {
|
||||
return undefined;
|
||||
}
|
||||
if (Array.isArray(val)) {
|
||||
return val;
|
||||
}
|
||||
// the array is returned as this
|
||||
if (typeof val === "string") {
|
||||
return val.split(",");
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
z.array(z.string().min(1).max(255))
|
||||
)
|
||||
});
|
||||
|
||||
async function query(orgId: string, domainList: string[]) {
|
||||
// Try to get CNAME certificates first
|
||||
const existingCertificates = await db
|
||||
.select({
|
||||
certId: certificates.certId,
|
||||
domain: certificates.domain,
|
||||
wildcard: certificates.wildcard,
|
||||
status: certificates.status,
|
||||
expiresAt: certificates.expiresAt,
|
||||
lastRenewalAttempt: certificates.lastRenewalAttempt,
|
||||
createdAt: certificates.createdAt,
|
||||
updatedAt: certificates.updatedAt,
|
||||
errorMessage: certificates.errorMessage,
|
||||
renewalCount: certificates.renewalCount,
|
||||
domainId: domains.domainId,
|
||||
domainType: domains.type
|
||||
})
|
||||
.from(certificates)
|
||||
.innerJoin(domains, eq(certificates.domainId, domains.domainId))
|
||||
.leftJoin(
|
||||
orgDomains,
|
||||
and(
|
||||
eq(domains.domainId, orgDomains.domainId),
|
||||
eq(orgDomains.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.leftJoin(
|
||||
domainNamespaces,
|
||||
eq(domains.domainId, domainNamespaces.domainId)
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
inArray(certificates.domain, domainList),
|
||||
// Namespace domains are shared across all orgs, so they skip
|
||||
// the org-ownership check (mirrors verifyCertificateAccess).
|
||||
or(
|
||||
isNotNull(orgDomains.orgId),
|
||||
isNotNull(domainNamespaces.domainNamespaceId)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// All non resolved domain certificates might be `ns` or `wildcard`,
|
||||
// which means exact domain certificates do not exist
|
||||
const foundDomains = new Set(
|
||||
existingCertificates.map((cert) => cert.domain)
|
||||
);
|
||||
const domainsWithMissingCertificates = domainList.filter(
|
||||
(domain) => !foundDomains.has(domain)
|
||||
);
|
||||
|
||||
if (domainsWithMissingCertificates.length > 0) {
|
||||
const domainLevelDownSet = new Set<string>();
|
||||
const wildcardDomainSet = new Set<string>();
|
||||
|
||||
for (const domain of domainsWithMissingCertificates) {
|
||||
const domainLevelDown = domain.split(".").slice(1).join(".");
|
||||
const wildcardPrefixed = `*.${domainLevelDown}`;
|
||||
domainLevelDownSet.add(domainLevelDown);
|
||||
wildcardDomainSet.add(wildcardPrefixed);
|
||||
}
|
||||
|
||||
// Need to map the certificates to each domain
|
||||
const wildcardCertificates = await db
|
||||
.select({
|
||||
certId: certificates.certId,
|
||||
domain: certificates.domain,
|
||||
wildcard: certificates.wildcard,
|
||||
status: certificates.status,
|
||||
expiresAt: certificates.expiresAt,
|
||||
lastRenewalAttempt: certificates.lastRenewalAttempt,
|
||||
createdAt: certificates.createdAt,
|
||||
updatedAt: certificates.updatedAt,
|
||||
errorMessage: certificates.errorMessage,
|
||||
renewalCount: certificates.renewalCount,
|
||||
domainId: domains.domainId,
|
||||
domainType: domains.type
|
||||
})
|
||||
.from(certificates)
|
||||
.innerJoin(domains, eq(certificates.domainId, domains.domainId))
|
||||
.leftJoin(
|
||||
orgDomains,
|
||||
and(
|
||||
eq(domains.domainId, orgDomains.domainId),
|
||||
eq(orgDomains.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.leftJoin(
|
||||
domainNamespaces,
|
||||
eq(domains.domainId, domainNamespaces.domainId)
|
||||
)
|
||||
.where(
|
||||
and(
|
||||
eq(certificates.wildcard, true),
|
||||
or(
|
||||
inArray(certificates.domain, [...domainLevelDownSet]),
|
||||
inArray(certificates.domain, [...wildcardDomainSet])
|
||||
),
|
||||
or(
|
||||
isNotNull(orgDomains.orgId),
|
||||
isNotNull(domainNamespaces.domainNamespaceId)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
existingCertificates.push(...wildcardCertificates);
|
||||
}
|
||||
|
||||
const certificateMap: Record<string, any> = {};
|
||||
for (const domain of domainList) {
|
||||
const domainLevelDown = domain.split(".").slice(1).join(".");
|
||||
const wildcardPrefixed = `*.${domainLevelDown}`;
|
||||
|
||||
certificateMap[domain] =
|
||||
existingCertificates.find(
|
||||
(cert) =>
|
||||
cert.domain === domain ||
|
||||
cert.domain === domainLevelDown ||
|
||||
cert.domain === wildcardPrefixed
|
||||
) ?? null;
|
||||
}
|
||||
|
||||
return certificateMap;
|
||||
}
|
||||
|
||||
export async function getBatchedCertificates(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedParams = getCertificateParamSchema.safeParse(req.params);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { orgId } = parsedParams.data;
|
||||
const parsedQuery = getCertificateQuerySchema.safeParse(req.query);
|
||||
if (!parsedQuery.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedQuery.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { domains } = parsedQuery.data;
|
||||
|
||||
const cert = await query(orgId, domains);
|
||||
|
||||
return response<GetBatchedCertificateResponse>(res, {
|
||||
data: cert,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Certificates retrieved successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { certificates, db, domains } from "@server/db";
|
||||
import { eq, and, or, like } from "drizzle-orm";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { registry } from "@server/openApi";
|
||||
import { GetCertificateResponse } from "@server/routers/certificates/types";
|
||||
|
||||
const getCertificateSchema = z.strictObject({
|
||||
domainId: z.string(),
|
||||
domain: z.string().min(1).max(255),
|
||||
orgId: z.string()
|
||||
});
|
||||
|
||||
async function query(domainId: string, domain: string) {
|
||||
const [domainRecord] = await db
|
||||
.select()
|
||||
.from(domains)
|
||||
.where(eq(domains.domainId, domainId))
|
||||
.limit(1);
|
||||
|
||||
if (!domainRecord) {
|
||||
throw new Error(`Domain with ID ${domainId} not found`);
|
||||
}
|
||||
|
||||
const domainType = domainRecord.type;
|
||||
|
||||
let existing: any[] = [];
|
||||
if (domainRecord.type == "ns" || domainRecord.type == "wildcard") {
|
||||
const domainLevelDown = domain.split(".").slice(1).join(".");
|
||||
const wildcardPrefixed = `*.${domainLevelDown}`;
|
||||
|
||||
existing = await db
|
||||
.select({
|
||||
certId: certificates.certId,
|
||||
domain: certificates.domain,
|
||||
wildcard: certificates.wildcard,
|
||||
status: certificates.status,
|
||||
expiresAt: certificates.expiresAt,
|
||||
lastRenewalAttempt: certificates.lastRenewalAttempt,
|
||||
createdAt: certificates.createdAt,
|
||||
updatedAt: certificates.updatedAt,
|
||||
errorMessage: certificates.errorMessage,
|
||||
renewalCount: certificates.renewalCount
|
||||
})
|
||||
.from(certificates)
|
||||
.where(
|
||||
and(
|
||||
eq(certificates.domainId, domainId),
|
||||
or(
|
||||
eq(certificates.domain, domain),
|
||||
and(
|
||||
eq(certificates.wildcard, true),
|
||||
or(
|
||||
eq(certificates.domain, domainLevelDown),
|
||||
eq(certificates.domain, wildcardPrefixed)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// For non-NS domains, we only match exact domain names
|
||||
existing = await db
|
||||
.select({
|
||||
certId: certificates.certId,
|
||||
domain: certificates.domain,
|
||||
wildcard: certificates.wildcard,
|
||||
status: certificates.status,
|
||||
expiresAt: certificates.expiresAt,
|
||||
lastRenewalAttempt: certificates.lastRenewalAttempt,
|
||||
createdAt: certificates.createdAt,
|
||||
updatedAt: certificates.updatedAt,
|
||||
errorMessage: certificates.errorMessage,
|
||||
renewalCount: certificates.renewalCount
|
||||
})
|
||||
.from(certificates)
|
||||
.where(
|
||||
and(
|
||||
eq(certificates.domainId, domainId),
|
||||
eq(certificates.domain, domain) // exact match for non-NS domains
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return existing.length > 0 ? { ...existing[0], domainType } : null;
|
||||
}
|
||||
|
||||
registry.registerPath({
|
||||
method: "get",
|
||||
path: "/org/{orgId}/certificate/{domainId}/{domain}",
|
||||
description: "Get a certificate by domain.",
|
||||
tags: ["Certificate"],
|
||||
request: {
|
||||
params: z.object({
|
||||
domainId: z.string(),
|
||||
domain: z.string().min(1).max(255),
|
||||
orgId: z.string()
|
||||
})
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "Successful response",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
data: z.record(z.string(), z.any()).nullable(),
|
||||
success: z.boolean(),
|
||||
error: z.boolean(),
|
||||
message: z.string(),
|
||||
status: z.number()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export async function getCertificate(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedParams = getCertificateSchema.safeParse(req.params);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { domainId, domain } = parsedParams.data;
|
||||
|
||||
const cert = await query(domainId, domain);
|
||||
|
||||
if (!cert) {
|
||||
logger.warn(`Certificate not found for domain: ${domainId}`);
|
||||
return next(
|
||||
createHttpError(HttpCode.NOT_FOUND, "Certificate not found")
|
||||
);
|
||||
}
|
||||
|
||||
return response<GetCertificateResponse>(res, {
|
||||
data: cert,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Certificate retrieved successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "./getCertificate";
|
||||
export * from "./restartCertificate";
|
||||
export * from "./syncCertToNewts";
|
||||
export * from "./getBatchedCertificates";
|
||||
export * from "./createCertificate";
|
||||
@@ -0,0 +1,111 @@
|
||||
import { certificates, db } from "@server/db";
|
||||
import response from "@server/lib/response";
|
||||
import logger from "@server/logger";
|
||||
import { registry } from "@server/openApi";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { NextFunction, Request, Response } from "express";
|
||||
import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const restartCertificateParamsSchema = z.strictObject({
|
||||
certId: z.coerce.number().int().positive(),
|
||||
orgId: z.string()
|
||||
});
|
||||
|
||||
registry.registerPath({
|
||||
method: "post",
|
||||
path: "/certificate/{certId}",
|
||||
description: "Restart a certificate by ID.",
|
||||
tags: ["Certificate"],
|
||||
request: {
|
||||
params: z.object({
|
||||
certId: z.coerce.number().int().positive(),
|
||||
orgId: z.string()
|
||||
})
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
description: "Successful response",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
data: z.record(z.string(), z.any()).nullable(),
|
||||
success: z.boolean(),
|
||||
error: z.boolean(),
|
||||
message: z.string(),
|
||||
status: z.number()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export async function restartCertificate(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<any> {
|
||||
try {
|
||||
const parsedParams = restartCertificateParamsSchema.safeParse(
|
||||
req.params
|
||||
);
|
||||
if (!parsedParams.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsedParams.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { certId } = parsedParams.data;
|
||||
|
||||
// get the certificate by ID
|
||||
const [cert] = await db
|
||||
.select()
|
||||
.from(certificates)
|
||||
.where(eq(certificates.certId, certId))
|
||||
.limit(1);
|
||||
|
||||
if (!cert) {
|
||||
return next(
|
||||
createHttpError(HttpCode.NOT_FOUND, "Certificate not found")
|
||||
);
|
||||
}
|
||||
|
||||
if (cert.status != "failed" && cert.status != "expired") {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Certificate is already valid, no need to restart"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// update the certificate status to 'pending'
|
||||
await db
|
||||
.update(certificates)
|
||||
.set({
|
||||
status: "pending",
|
||||
errorMessage: null,
|
||||
lastRenewalAttempt: Math.floor(Date.now() / 1000)
|
||||
})
|
||||
.where(eq(certificates.certId, certId));
|
||||
|
||||
return response<null>(res, {
|
||||
data: null,
|
||||
success: true,
|
||||
error: false,
|
||||
message: "Certificate restarted successfully",
|
||||
status: HttpCode.OK
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(error);
|
||||
return next(
|
||||
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { pushCertUpdateToAffectedNewts } from "@server/lib/acmeCertSync";
|
||||
import logger from "@server/logger";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
const bodySchema = z.object({
|
||||
domain: z.string().min(1),
|
||||
domainId: z.string().nullable().optional().default(null)
|
||||
});
|
||||
|
||||
export async function syncCertToNewts(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
): Promise<void> {
|
||||
const parsed = bodySchema.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
fromError(parsed.error).toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const { domain, domainId } = parsed.data;
|
||||
|
||||
logger.debug(
|
||||
`syncCertToNewts: received request to push cert update for domain "${domain}" (domainId: ${domainId ?? "none"})`
|
||||
);
|
||||
|
||||
try {
|
||||
await pushCertUpdateToAffectedNewts(domain, domainId, null, null);
|
||||
|
||||
res.status(HttpCode.OK).json({
|
||||
data: null,
|
||||
success: true,
|
||||
error: false,
|
||||
message: `Certificate update pushed to affected newts for domain "${domain}"`
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`syncCertToNewts: error pushing cert update for domain "${domain}": ${err}`
|
||||
);
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
"Failed to push certificate update to affected newts"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -50,20 +50,21 @@ import {
|
||||
verifyAiProviderAccess,
|
||||
verifyAiModelAccess,
|
||||
verifyAiBudgetAccess,
|
||||
verifyVirtualApiKeyAccess
|
||||
verifyVirtualApiKeyAccess,
|
||||
logActionAudit,
|
||||
verifyCertificateAccess
|
||||
} from "@server/middlewares";
|
||||
import { ActionsEnum } from "@server/auth/actions";
|
||||
import rateLimit, { ipKeyGenerator } from "express-rate-limit";
|
||||
import createHttpError from "http-errors";
|
||||
import { build } from "@server/build";
|
||||
import { createStore } from "#dynamic/lib/rateLimitStore";
|
||||
import { logActionAudit, verifyValidLicense } from "#dynamic/middlewares";
|
||||
import { checkRoundTripMessage } from "./ws";
|
||||
import * as labels from "@server/routers/labels";
|
||||
import * as aiProvider from "@server/routers/aiProvider";
|
||||
import * as aiBudget from "@server/routers/aiBudget";
|
||||
import * as virtualApiKey from "@server/routers/virtualApiKey";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import * as certificates from "@server/routers/certificates";
|
||||
|
||||
// Root routes
|
||||
export const unauthenticated = Router();
|
||||
@@ -1858,7 +1859,6 @@ authenticated.put(
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/ssh/sign-key",
|
||||
verifyValidLicense,
|
||||
verifyOrgAccess,
|
||||
verifyLimits,
|
||||
// verifyUserHasAction(ActionsEnum.signSshKey), // this check happens inside of the function now
|
||||
@@ -1878,6 +1878,31 @@ authenticated.post(
|
||||
client.rebuildClientAssociationsCacheRoute
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/certificate/:domainId/:domain",
|
||||
verifyOrgAccess,
|
||||
verifyCertificateAccess,
|
||||
verifyUserHasAction(ActionsEnum.getCertificate),
|
||||
certificates.getCertificate
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/batched-certificates",
|
||||
verifyOrgAccess,
|
||||
verifyUserHasAction(ActionsEnum.getCertificate),
|
||||
certificates.getBatchedCertificates
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/certificate/:certId/restart",
|
||||
verifyOrgAccess,
|
||||
verifyCertificateAccess,
|
||||
verifyLimits,
|
||||
verifyUserHasAction(ActionsEnum.restartCertificate),
|
||||
logActionAudit(ActionsEnum.restartCertificate),
|
||||
certificates.restartCertificate
|
||||
);
|
||||
|
||||
// Auth routes
|
||||
export const authRouter = Router();
|
||||
unauthenticated.use("/auth", authRouter);
|
||||
|
||||
@@ -24,7 +24,7 @@ import logger from "@server/logger";
|
||||
import { subdomainSchema, wildcardSubdomainSchema } from "@server/lib/schemas";
|
||||
import config from "@server/lib/config";
|
||||
import { OpenAPITags, registry } from "@server/openApi";
|
||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
||||
import { createCertificate } from "@server/routers/certificates";
|
||||
import {
|
||||
validateAndConstructDomain,
|
||||
checkWildcardDomainConflict
|
||||
|
||||
@@ -38,7 +38,7 @@ import {
|
||||
} from "@server/lib/schemas";
|
||||
import { registry } from "@server/openApi";
|
||||
import { OpenAPITags } from "@server/openApi";
|
||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
||||
import { createCertificate } from "@server/routers/certificates/createCertificate";
|
||||
import {
|
||||
validateAndConstructDomain,
|
||||
checkWildcardDomainConflict
|
||||
|
||||
@@ -32,7 +32,7 @@ import createHttpError from "http-errors";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { validateAndConstructDomain } from "@server/lib/domainUtils";
|
||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
||||
import { createCertificate } from "@server/routers/certificates/createCertificate";
|
||||
import { build } from "@server/build";
|
||||
import { usageService } from "@server/lib/billing/usageService";
|
||||
import { LimitId } from "@server/lib/billing";
|
||||
|
||||
Reference in New Issue
Block a user