merge main

This commit is contained in:
Scott Wilson
2025-06-02 16:24:55 -07:00
722 changed files with 30947 additions and 13097 deletions
+6 -3
View File
@@ -1,9 +1,9 @@
/* eslint-disable no-console */
import { Redis } from "ioredis";
import { Knex } from "knex";
import { createTransport } from "nodemailer";
import { formatSmtpConfig, getConfig } from "@app/lib/config/env";
import { buildRedisFromConfig } from "@app/lib/config/redis";
import { logger } from "@app/lib/logger";
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
@@ -65,12 +65,15 @@ export const bootstrapCheck = async ({ db }: BootstrapOpt) => {
});
console.log("Testing redis connection");
const redis = new Redis(appCfg.REDIS_URL);
const redis = buildRedisFromConfig(appCfg);
const redisPing = await redis?.ping();
if (!redisPing) {
console.error("Redis - Failed to connect");
} else {
console.error("Redis successfully connected");
console.log("Redis successfully connected");
if (appCfg.isRedisSentinelMode) {
console.log("Redis Sentinel Mode");
}
redis.disconnect();
}
+2 -4
View File
@@ -1,14 +1,12 @@
import type { RateLimitOptions, RateLimitPluginOptions } from "@fastify/rate-limit";
import { Redis } from "ioredis";
import { getConfig } from "@app/lib/config/env";
import { buildRedisFromConfig } from "@app/lib/config/redis";
import { RateLimitError } from "@app/lib/errors";
export const globalRateLimiterCfg = (): RateLimitPluginOptions => {
const appCfg = getConfig();
const redis = appCfg.isRedisConfigured
? new Redis(appCfg.REDIS_URL, { connectTimeout: 500, maxRetriesPerRequest: 1 })
: null;
const redis = appCfg.isRedisConfigured ? buildRedisFromConfig(appCfg) : null;
return {
errorResponseBuilder: (_, context) => {
+1 -1
View File
@@ -9,7 +9,7 @@ interface SlugSchemaInputs {
field?: string;
}
export const slugSchema = ({ min = 1, max = 32, field = "Slug" }: SlugSchemaInputs = {}) => {
export const slugSchema = ({ min = 1, max = 64, field = "Slug" }: SlugSchemaInputs = {}) => {
return z
.string()
.trim()
@@ -123,6 +123,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
switch (authMode) {
case AuthMode.JWT: {
const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token);
requestContext.set("orgId", orgId);
req.auth = {
authMode: AuthMode.JWT,
user,
@@ -138,6 +139,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
case AuthMode.IDENTITY_ACCESS_TOKEN: {
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(token, req.realIp);
const serverCfg = await getServerCfg();
requestContext.set("orgId", identity.orgId);
req.auth = {
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
actor,
@@ -157,6 +159,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
}
case AuthMode.SERVICE_TOKEN: {
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token);
requestContext.set("orgId", serviceToken.orgId);
req.auth = {
orgId: serviceToken.orgId,
authMode: AuthMode.SERVICE_TOKEN as const,
@@ -181,6 +184,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
}
case AuthMode.SCIM_TOKEN: {
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
requestContext.set("orgId", orgId);
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId, authMethod: null };
break;
}
+154 -61
View File
@@ -6,7 +6,10 @@ import { z } from "zod";
import { registerCertificateEstRouter } from "@app/ee/routes/est/certificate-est-router";
import { registerV1EERoutes } from "@app/ee/routes/v1";
import { registerV2EERoutes } from "@app/ee/routes/v2";
import { accessApprovalPolicyApproverDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-approver-dal";
import {
accessApprovalPolicyApproverDALFactory,
accessApprovalPolicyBypasserDALFactory
} from "@app/ee/services/access-approval-policy/access-approval-policy-approver-dal";
import { accessApprovalPolicyDALFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-dal";
import { accessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-service";
import { accessApprovalRequestDALFactory } from "@app/ee/services/access-approval-request/access-approval-request-dal";
@@ -67,7 +70,10 @@ import { samlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-d
import { samlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-service";
import { scimDALFactory } from "@app/ee/services/scim/scim-dal";
import { scimServiceFactory } from "@app/ee/services/scim/scim-service";
import { secretApprovalPolicyApproverDALFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-approver-dal";
import {
secretApprovalPolicyApproverDALFactory,
secretApprovalPolicyBypasserDALFactory
} from "@app/ee/services/secret-approval-policy/secret-approval-policy-approver-dal";
import { secretApprovalPolicyDALFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-dal";
import { secretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
import { secretApprovalRequestDALFactory } from "@app/ee/services/secret-approval-request/secret-approval-request-dal";
@@ -136,6 +142,10 @@ import { certificateAuthorityDALFactory } from "@app/services/certificate-author
import { certificateAuthorityQueueFactory } from "@app/services/certificate-authority/certificate-authority-queue";
import { certificateAuthoritySecretDALFactory } from "@app/services/certificate-authority/certificate-authority-secret-dal";
import { certificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service";
import { externalCertificateAuthorityDALFactory } from "@app/services/certificate-authority/external-certificate-authority-dal";
import { internalCertificateAuthorityDALFactory } from "@app/services/certificate-authority/internal/internal-certificate-authority-dal";
import { InternalCertificateAuthorityFns } from "@app/services/certificate-authority/internal/internal-certificate-authority-fns";
import { internalCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/internal/internal-certificate-authority-service";
import { certificateTemplateDALFactory } from "@app/services/certificate-template/certificate-template-dal";
import { certificateTemplateEstConfigDALFactory } from "@app/services/certificate-template/certificate-template-est-config-dal";
import { certificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service";
@@ -203,7 +213,10 @@ import { pkiCollectionDALFactory } from "@app/services/pki-collection/pki-collec
import { pkiCollectionItemDALFactory } from "@app/services/pki-collection/pki-collection-item-dal";
import { pkiCollectionServiceFactory } from "@app/services/pki-collection/pki-collection-service";
import { pkiSubscriberDALFactory } from "@app/services/pki-subscriber/pki-subscriber-dal";
import { pkiSubscriberQueueServiceFactory } from "@app/services/pki-subscriber/pki-subscriber-queue";
import { pkiSubscriberServiceFactory } from "@app/services/pki-subscriber/pki-subscriber-service";
import { pkiTemplatesDALFactory } from "@app/services/pki-templates/pki-templates-dal";
import { pkiTemplatesServiceFactory } from "@app/services/pki-templates/pki-templates-service";
import { projectDALFactory } from "@app/services/project/project-dal";
import { projectQueueFactory } from "@app/services/project/project-queue";
import { projectServiceFactory } from "@app/services/project/project-service";
@@ -387,9 +400,11 @@ export const registerRoutes = async (
const accessApprovalPolicyDAL = accessApprovalPolicyDALFactory(db);
const accessApprovalRequestDAL = accessApprovalRequestDALFactory(db);
const accessApprovalPolicyApproverDAL = accessApprovalPolicyApproverDALFactory(db);
const accessApprovalPolicyBypasserDAL = accessApprovalPolicyBypasserDALFactory(db);
const accessApprovalRequestReviewerDAL = accessApprovalRequestReviewerDALFactory(db);
const sapApproverDAL = secretApprovalPolicyApproverDALFactory(db);
const sapBypasserDAL = secretApprovalPolicyBypasserDALFactory(db);
const secretApprovalPolicyDAL = secretApprovalPolicyDALFactory(db);
const secretApprovalRequestDAL = secretApprovalRequestDALFactory(db);
const secretApprovalRequestReviewerDAL = secretApprovalRequestReviewerDALFactory(db);
@@ -522,6 +537,7 @@ export const registerRoutes = async (
const secretApprovalPolicyService = secretApprovalPolicyServiceFactory({
projectEnvDAL,
secretApprovalPolicyApproverDAL: sapApproverDAL,
secretApprovalPolicyBypasserDAL: sapBypasserDAL,
permissionService,
secretApprovalPolicyDAL,
licenseService,
@@ -633,7 +649,6 @@ export const registerRoutes = async (
const userService = userServiceFactory({
userDAL,
userAliasDAL,
orgMembershipDAL,
tokenService,
permissionService,
@@ -734,12 +749,14 @@ export const registerRoutes = async (
userAliasDAL,
identityTokenAuthDAL,
identityAccessTokenDAL,
orgMembershipDAL,
identityOrgMembershipDAL,
authService: loginService,
serverCfgDAL: superAdminDAL,
kmsRootConfigDAL,
orgService,
keyStore,
orgDAL,
licenseService,
kmsService,
microsoftTeamsService,
@@ -798,7 +815,8 @@ export const registerRoutes = async (
const projectUserAdditionalPrivilegeService = projectUserAdditionalPrivilegeServiceFactory({
permissionService,
projectMembershipDAL,
projectUserAdditionalPrivilegeDAL
projectUserAdditionalPrivilegeDAL,
accessApprovalRequestDAL
});
const projectKeyService = projectKeyServiceFactory({
permissionService,
@@ -826,6 +844,8 @@ export const registerRoutes = async (
});
const certificateAuthorityDAL = certificateAuthorityDALFactory(db);
const internalCertificateAuthorityDAL = internalCertificateAuthorityDALFactory(db);
const externalCertificateAuthorityDAL = externalCertificateAuthorityDALFactory(db);
const certificateAuthorityCertDAL = certificateAuthorityCertDALFactory(db);
const certificateAuthoritySecretDAL = certificateAuthoritySecretDALFactory(db);
const certificateAuthorityCrlDAL = certificateAuthorityCrlDALFactory(db);
@@ -840,6 +860,7 @@ export const registerRoutes = async (
const pkiCollectionDAL = pkiCollectionDALFactory(db);
const pkiCollectionItemDAL = pkiCollectionItemDALFactory(db);
const pkiSubscriberDAL = pkiSubscriberDALFactory(db);
const pkiTemplatesDAL = pkiTemplatesDALFactory(db);
const certificateService = certificateServiceFactory({
certificateDAL,
@@ -851,17 +872,9 @@ export const registerRoutes = async (
certificateAuthoritySecretDAL,
projectDAL,
kmsService,
permissionService
});
const certificateAuthorityQueue = certificateAuthorityQueueFactory({
certificateAuthorityCrlDAL,
certificateAuthorityDAL,
certificateAuthoritySecretDAL,
certificateDAL,
projectDAL,
kmsService,
queueService
permissionService,
pkiCollectionDAL,
pkiCollectionItemDAL
});
const sshCertificateAuthorityService = sshCertificateAuthorityServiceFactory({
@@ -910,23 +923,6 @@ export const registerRoutes = async (
groupDAL
});
const certificateAuthorityService = certificateAuthorityServiceFactory({
certificateAuthorityDAL,
certificateAuthorityCertDAL,
certificateAuthoritySecretDAL,
certificateAuthorityCrlDAL,
certificateTemplateDAL,
certificateAuthorityQueue,
certificateDAL,
certificateBodyDAL,
certificateSecretDAL,
pkiCollectionDAL,
pkiCollectionItemDAL,
projectDAL,
kmsService,
permissionService
});
const certificateAuthorityCrlService = certificateAuthorityCrlServiceFactory({
certificateAuthorityDAL,
certificateAuthorityCrlDAL,
@@ -946,17 +942,6 @@ export const registerRoutes = async (
licenseService
});
const certificateEstService = certificateEstServiceFactory({
certificateAuthorityService,
certificateTemplateService,
certificateTemplateDAL,
certificateAuthorityCertDAL,
certificateAuthorityDAL,
projectDAL,
kmsService,
licenseService
});
const pkiAlertService = pkiAlertServiceFactory({
pkiAlertDAL,
pkiCollectionDAL,
@@ -974,20 +959,6 @@ export const registerRoutes = async (
projectDAL
});
const pkiSubscriberService = pkiSubscriberServiceFactory({
pkiSubscriberDAL,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
certificateAuthoritySecretDAL,
certificateAuthorityCrlDAL,
certificateDAL,
certificateBodyDAL,
certificateSecretDAL,
projectDAL,
kmsService,
permissionService
});
const projectTemplateService = projectTemplateServiceFactory({
licenseService,
permissionService,
@@ -1023,7 +994,8 @@ export const registerRoutes = async (
secretVersionV2BridgeDAL,
secretVersionTagV2BridgeDAL,
resourceMetadataDAL,
appConnectionDAL
appConnectionDAL,
licenseService
});
const secretQueueService = secretQueueFactory({
@@ -1269,6 +1241,7 @@ export const registerRoutes = async (
const accessApprovalPolicyService = accessApprovalPolicyServiceFactory({
accessApprovalPolicyDAL,
accessApprovalPolicyApproverDAL,
accessApprovalPolicyBypasserDAL,
groupDAL,
permissionService,
projectEnvDAL,
@@ -1277,7 +1250,8 @@ export const registerRoutes = async (
userDAL,
accessApprovalRequestDAL,
additionalPrivilegeDAL: projectUserAdditionalPrivilegeDAL,
accessApprovalRequestReviewerDAL
accessApprovalRequestReviewerDAL,
orgMembershipDAL
});
const accessApprovalRequestService = accessApprovalRequestServiceFactory({
@@ -1640,7 +1614,8 @@ export const registerRoutes = async (
const appConnectionService = appConnectionServiceFactory({
appConnectionDAL,
permissionService,
kmsService
kmsService,
licenseService
});
const secretSyncService = secretSyncServiceFactory({
@@ -1651,7 +1626,54 @@ export const registerRoutes = async (
folderDAL,
secretSyncQueue,
projectBotService,
keyStore
keyStore,
licenseService
});
const certificateAuthorityQueue = certificateAuthorityQueueFactory({
certificateAuthorityCrlDAL,
certificateAuthorityDAL,
certificateAuthoritySecretDAL,
certificateDAL,
projectDAL,
kmsService,
queueService,
pkiSubscriberDAL,
certificateBodyDAL,
certificateSecretDAL,
externalCertificateAuthorityDAL,
keyStore,
appConnectionDAL,
appConnectionService
});
const internalCertificateAuthorityService = internalCertificateAuthorityServiceFactory({
certificateAuthorityDAL,
certificateAuthorityCertDAL,
certificateAuthoritySecretDAL,
certificateAuthorityCrlDAL,
certificateTemplateDAL,
certificateAuthorityQueue,
certificateDAL,
certificateBodyDAL,
certificateSecretDAL,
pkiCollectionDAL,
pkiCollectionItemDAL,
projectDAL,
internalCertificateAuthorityDAL,
kmsService,
permissionService
});
const certificateEstService = certificateEstServiceFactory({
internalCertificateAuthorityService,
certificateTemplateService,
certificateTemplateDAL,
certificateAuthorityCertDAL,
certificateAuthorityDAL,
projectDAL,
kmsService,
licenseService
});
const kmipService = kmipServiceFactory({
@@ -1693,6 +1715,74 @@ export const registerRoutes = async (
appConnectionDAL
});
const certificateAuthorityService = certificateAuthorityServiceFactory({
certificateAuthorityDAL,
projectDAL,
permissionService,
appConnectionDAL,
appConnectionService,
externalCertificateAuthorityDAL,
internalCertificateAuthorityService,
certificateDAL,
certificateBodyDAL,
certificateSecretDAL,
kmsService,
pkiSubscriberDAL
});
const internalCaFns = InternalCertificateAuthorityFns({
certificateAuthorityDAL,
certificateAuthorityCertDAL,
certificateAuthoritySecretDAL,
certificateAuthorityCrlDAL,
certificateDAL,
certificateBodyDAL,
certificateSecretDAL,
projectDAL,
kmsService
});
const pkiSubscriberQueue = pkiSubscriberQueueServiceFactory({
queueService,
pkiSubscriberDAL,
certificateAuthorityDAL,
certificateAuthorityQueue,
certificateDAL,
auditLogService,
internalCaFns
});
const pkiSubscriberService = pkiSubscriberServiceFactory({
pkiSubscriberDAL,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
certificateAuthoritySecretDAL,
certificateAuthorityCrlDAL,
certificateDAL,
certificateBodyDAL,
certificateSecretDAL,
projectDAL,
kmsService,
permissionService,
certificateAuthorityQueue,
internalCaFns
});
const pkiTemplateService = pkiTemplatesServiceFactory({
pkiTemplatesDAL,
certificateAuthorityDAL,
certificateAuthorityCertDAL,
certificateAuthoritySecretDAL,
certificateAuthorityCrlDAL,
certificateDAL,
certificateBodyDAL,
certificateSecretDAL,
projectDAL,
kmsService,
permissionService,
internalCaFns
});
await secretRotationV2QueueServiceFactory({
secretRotationV2Service,
secretRotationV2DAL,
@@ -1733,6 +1823,7 @@ export const registerRoutes = async (
await telemetryQueue.startTelemetryCheck();
await dailyResourceCleanUp.startCleanUp();
await dailyExpiringPkiItemAlert.startSendingAlerts();
await pkiSubscriberQueue.startDailyAutoRenewalJob();
await kmsService.startService();
await microsoftTeamsService.start();
@@ -1798,12 +1889,14 @@ export const registerRoutes = async (
sshHost: sshHostService,
sshHostGroup: sshHostGroupService,
certificateAuthority: certificateAuthorityService,
internalCertificateAuthority: internalCertificateAuthorityService,
certificateTemplate: certificateTemplateService,
certificateAuthorityCrl: certificateAuthorityCrlService,
certificateEst: certificateEstService,
pkiAlert: pkiAlertService,
pkiCollection: pkiCollectionService,
pkiSubscriber: pkiSubscriberService,
pkiTemplate: pkiTemplateService,
secretScanning: secretScanningService,
license: licenseService,
trustedIp: trustedIpService,
+17 -5
View File
@@ -1,9 +1,11 @@
import { z } from "zod";
import {
CertificateAuthoritiesSchema,
DynamicSecretsSchema,
IdentityProjectAdditionalPrivilegeSchema,
IntegrationAuthsSchema,
InternalCertificateAuthoritiesSchema,
ProjectRolesSchema,
ProjectsSchema,
SecretApprovalPoliciesSchema,
@@ -233,11 +235,9 @@ export const SanitizedDynamicSecretSchema = DynamicSecretsSchema.omit({
inputIV: true,
inputTag: true,
algorithm: true
}).merge(
z.object({
metadata: ResourceMetadataSchema.optional()
})
);
}).extend({
metadata: ResourceMetadataSchema.optional()
});
export const SanitizedAuditLogStreamSchema = z.object({
id: z.string(),
@@ -272,3 +272,15 @@ export const SanitizedTagSchema = SecretTagsSchema.pick({
}).extend({
name: z.string()
});
export const InternalCertificateAuthorityResponseSchema = CertificateAuthoritiesSchema.merge(
InternalCertificateAuthoritiesSchema.omit({
caId: true,
notAfter: true,
notBefore: true
})
).extend({
requireTemplateForIssuance: z.boolean().optional(),
notAfter: z.string().optional(),
notBefore: z.string().optional()
});
+130 -1
View File
@@ -1,7 +1,13 @@
import DOMPurify from "isomorphic-dompurify";
import { z } from "zod";
import { IdentitiesSchema, OrganizationsSchema, SuperAdminSchema, UsersSchema } from "@app/db/schemas";
import {
IdentitiesSchema,
OrganizationsSchema,
OrgMembershipsSchema,
SuperAdminSchema,
UsersSchema
} from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
import { invalidateCacheLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
@@ -161,6 +167,129 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
}
});
server.route({
method: "GET",
url: "/organization-management/organizations",
config: {
rateLimit: readLimit
},
schema: {
querystring: z.object({
searchTerm: z.string().default(""),
offset: z.coerce.number().default(0),
limit: z.coerce.number().max(100).default(20)
}),
response: {
200: z.object({
organizations: OrganizationsSchema.extend({
members: z
.object({
user: z.object({
id: z.string(),
email: z.string().nullish(),
username: z.string(),
firstName: z.string().nullish(),
lastName: z.string().nullish()
}),
membershipId: z.string(),
role: z.string(),
roleId: z.string().nullish()
})
.array(),
projects: z
.object({
name: z.string(),
id: z.string(),
slug: z.string(),
createdAt: z.date()
})
.array()
}).array()
})
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
handler: async (req) => {
const organizations = await server.services.superAdmin.getOrganizations({
...req.query
});
return {
organizations
};
}
});
server.route({
method: "DELETE",
url: "/organization-management/organizations/:organizationId/memberships/:membershipId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
organizationId: z.string(),
membershipId: z.string()
}),
response: {
200: z.object({
organizationMembership: OrgMembershipsSchema
})
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
handler: async (req) => {
const organizationMembership = await server.services.superAdmin.deleteOrganizationMembership(
req.params.organizationId,
req.params.membershipId,
req.permission.id,
req.permission.type
);
return {
organizationMembership
};
}
});
server.route({
method: "DELETE",
url: "/organization-management/organizations/:organizationId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
organizationId: z.string()
}),
response: {
200: z.object({
organization: OrganizationsSchema
})
}
},
onRequest: (req, res, done) => {
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
verifySuperAdmin(req, res, done);
});
},
handler: async (req) => {
const organization = await server.services.superAdmin.deleteOrganization(req.params.organizationId);
return {
organization
};
}
});
server.route({
method: "GET",
url: "/identity-management/identities",
@@ -0,0 +1,60 @@
import z from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import {
CreateOnePassConnectionSchema,
SanitizedOnePassConnectionSchema,
UpdateOnePassConnectionSchema
} from "@app/services/app-connection/1password";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerOnePassConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.OnePass,
server,
sanitizedResponseSchema: SanitizedOnePassConnectionSchema,
createSchema: CreateOnePassConnectionSchema,
updateSchema: UpdateOnePassConnectionSchema
});
// The following endpoints are for internal Infisical App use only and not part of the public API
server.route({
method: "GET",
url: `/:connectionId/vaults`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string(),
name: z.string(),
type: z.string(),
items: z.number(),
attributeVersion: z.number(),
contentVersion: z.number(),
// Corresponds to ISO8601 date string
createdAt: z.string(),
updatedAt: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const vaults = await server.services.appConnection.onepass.listVaults(connectionId, req.permission);
return vaults;
}
});
};
@@ -1,9 +1,14 @@
import { z } from "zod";
import { OCIConnectionListItemSchema, SanitizedOCIConnectionSchema } from "@app/ee/services/app-connections/oci";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags } from "@app/lib/api-docs";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import {
OnePassConnectionListItemSchema,
SanitizedOnePassConnectionSchema
} from "@app/services/app-connection/1password";
import { Auth0ConnectionListItemSchema, SanitizedAuth0ConnectionSchema } from "@app/services/app-connection/auth0";
import { AwsConnectionListItemSchema, SanitizedAwsConnectionSchema } from "@app/services/app-connection/aws";
import {
@@ -42,7 +47,7 @@ import {
} from "@app/services/app-connection/humanitec";
import { LdapConnectionListItemSchema, SanitizedLdapConnectionSchema } from "@app/services/app-connection/ldap";
import { MsSqlConnectionListItemSchema, SanitizedMsSqlConnectionSchema } from "@app/services/app-connection/mssql";
import { OCIConnectionListItemSchema, SanitizedOCIConnectionSchema } from "@app/services/app-connection/oci";
import { MySqlConnectionListItemSchema, SanitizedMySqlConnectionSchema } from "@app/services/app-connection/mysql";
import {
PostgresConnectionListItemSchema,
SanitizedPostgresConnectionSchema
@@ -76,6 +81,7 @@ const SanitizedAppConnectionSchema = z.union([
...SanitizedVercelConnectionSchema.options,
...SanitizedPostgresConnectionSchema.options,
...SanitizedMsSqlConnectionSchema.options,
...SanitizedMySqlConnectionSchema.options,
...SanitizedCamundaConnectionSchema.options,
...SanitizedAuth0ConnectionSchema.options,
...SanitizedHCVaultConnectionSchema.options,
@@ -83,7 +89,8 @@ const SanitizedAppConnectionSchema = z.union([
...SanitizedWindmillConnectionSchema.options,
...SanitizedLdapConnectionSchema.options,
...SanitizedTeamCityConnectionSchema.options,
...SanitizedOCIConnectionSchema.options
...SanitizedOCIConnectionSchema.options,
...SanitizedOnePassConnectionSchema.options
]);
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
@@ -99,6 +106,7 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
VercelConnectionListItemSchema,
PostgresConnectionListItemSchema,
MsSqlConnectionListItemSchema,
MySqlConnectionListItemSchema,
CamundaConnectionListItemSchema,
Auth0ConnectionListItemSchema,
HCVaultConnectionListItemSchema,
@@ -106,7 +114,8 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
WindmillConnectionListItemSchema,
LdapConnectionListItemSchema,
TeamCityConnectionListItemSchema,
OCIConnectionListItemSchema
OCIConnectionListItemSchema,
OnePassConnectionListItemSchema
]);
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
@@ -1,5 +1,7 @@
import { registerOCIConnectionRouter } from "@app/ee/routes/v1/app-connection-routers/oci-connection-router";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { registerOnePassConnectionRouter } from "./1password-connection-router";
import { registerAuth0ConnectionRouter } from "./auth0-connection-router";
import { registerAwsConnectionRouter } from "./aws-connection-router";
import { registerAzureAppConfigurationConnectionRouter } from "./azure-app-configuration-connection-router";
@@ -14,7 +16,7 @@ import { registerHCVaultConnectionRouter } from "./hc-vault-connection-router";
import { registerHumanitecConnectionRouter } from "./humanitec-connection-router";
import { registerLdapConnectionRouter } from "./ldap-connection-router";
import { registerMsSqlConnectionRouter } from "./mssql-connection-router";
import { registerOCIConnectionRouter } from "./oci-connection-router";
import { registerMySqlConnectionRouter } from "./mysql-connection-router";
import { registerPostgresConnectionRouter } from "./postgres-connection-router";
import { registerTeamCityConnectionRouter } from "./teamcity-connection-router";
import { registerTerraformCloudConnectionRouter } from "./terraform-cloud-router";
@@ -38,11 +40,13 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
[AppConnection.Vercel]: registerVercelConnectionRouter,
[AppConnection.Postgres]: registerPostgresConnectionRouter,
[AppConnection.MsSql]: registerMsSqlConnectionRouter,
[AppConnection.MySql]: registerMySqlConnectionRouter,
[AppConnection.Camunda]: registerCamundaConnectionRouter,
[AppConnection.Windmill]: registerWindmillConnectionRouter,
[AppConnection.Auth0]: registerAuth0ConnectionRouter,
[AppConnection.HCVault]: registerHCVaultConnectionRouter,
[AppConnection.LDAP]: registerLdapConnectionRouter,
[AppConnection.TeamCity]: registerTeamCityConnectionRouter,
[AppConnection.OCI]: registerOCIConnectionRouter
[AppConnection.OCI]: registerOCIConnectionRouter,
[AppConnection.OnePass]: registerOnePassConnectionRouter
};
@@ -0,0 +1,18 @@
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateMySqlConnectionSchema,
SanitizedMySqlConnectionSchema,
UpdateMySqlConnectionSchema
} from "@app/services/app-connection/mysql";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerMySqlConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.MySql,
server,
sanitizedResponseSchema: SanitizedMySqlConnectionSchema,
createSchema: CreateMySqlConnectionSchema,
updateSchema: UpdateMySqlConnectionSchema
});
};
@@ -1,123 +0,0 @@
import z from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateOCIConnectionSchema,
SanitizedOCIConnectionSchema,
UpdateOCIConnectionSchema
} from "@app/services/app-connection/oci";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerOCIConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.OCI,
server,
sanitizedResponseSchema: SanitizedOCIConnectionSchema,
createSchema: CreateOCIConnectionSchema,
updateSchema: UpdateOCIConnectionSchema
});
// The following endpoints are for internal Infisical App use only and not part of the public API
server.route({
method: "GET",
url: `/:connectionId/compartments`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string(),
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const compartments = await server.services.appConnection.oci.listCompartments(connectionId, req.permission);
return compartments;
}
});
server.route({
method: "GET",
url: `/:connectionId/vaults`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
querystring: z.object({
compartmentOcid: z.string().min(1, "Compartment OCID required")
}),
response: {
200: z
.object({
id: z.string(),
displayName: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const { compartmentOcid } = req.query;
const vaults = await server.services.appConnection.oci.listVaults(
{ connectionId, compartmentOcid },
req.permission
);
return vaults;
}
});
server.route({
method: "GET",
url: `/:connectionId/vault-keys`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
querystring: z.object({
compartmentOcid: z.string().min(1, "Compartment OCID required"),
vaultOcid: z.string().min(1, "Vault OCID required")
}),
response: {
200: z
.object({
id: z.string(),
displayName: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const { compartmentOcid, vaultOcid } = req.query;
const keys = await server.services.appConnection.oci.listVaultKeys(
{ connectionId, compartmentOcid, vaultOcid },
req.permission
);
return keys;
}
});
};
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-floating-promises */
import { z } from "zod";
import { CertificateAuthoritiesSchema, CertificateTemplatesSchema } from "@app/db/schemas";
import { CertificateTemplatesSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags, CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms";
@@ -10,13 +10,19 @@ import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CertExtendedKeyUsage, CertKeyAlgorithm, CertKeyUsage } from "@app/services/certificate/certificate-types";
import { CaRenewalType, CaStatus, CaType } from "@app/services/certificate-authority/certificate-authority-types";
import {
CaRenewalType,
CaStatus,
InternalCaType
} from "@app/services/certificate-authority/certificate-authority-enums";
import {
validateAltNamesField,
validateCaDateField
} from "@app/services/certificate-authority/certificate-authority-validators";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { InternalCertificateAuthorityResponseSchema } from "../sanitizedSchemas";
export const registerCaRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
@@ -32,7 +38,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
body: z
.object({
projectSlug: z.string().trim().describe(CERTIFICATE_AUTHORITIES.CREATE.projectSlug),
type: z.nativeEnum(CaType).describe(CERTIFICATE_AUTHORITIES.CREATE.type),
type: z.nativeEnum(InternalCaType).describe(CERTIFICATE_AUTHORITIES.CREATE.type),
friendlyName: z.string().optional().describe(CERTIFICATE_AUTHORITIES.CREATE.friendlyName),
commonName: z.string().trim().describe(CERTIFICATE_AUTHORITIES.CREATE.commonName),
organization: z.string().trim().describe(CERTIFICATE_AUTHORITIES.CREATE.organization),
@@ -68,16 +74,18 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},
handler: async (req) => {
const ca = await server.services.certificateAuthority.createCa({
const ca = await server.services.internalCertificateAuthority.createCa({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
isInternal: false,
actorOrgId: req.permission.orgId,
enableDirectIssuance: !req.body.requireTemplateForIssuance,
...req.body
});
@@ -87,6 +95,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
event: {
type: EventType.CREATE_CA,
metadata: {
name: ca.name,
caId: ca.id,
dn: ca.dn
}
@@ -115,12 +124,12 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},
handler: async (req) => {
const ca = await server.services.certificateAuthority.getCaById({
const ca = await server.services.internalCertificateAuthority.getCaById({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -135,6 +144,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
type: EventType.GET_CA,
metadata: {
caId: ca.id,
name: ca.name,
dn: ca.dn
}
}
@@ -167,7 +177,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req, res) => {
const caCert = await server.services.certificateAuthority.getCaCertById(req.params);
const caCert = await server.services.internalCertificateAuthority.getCaCertById(req.params);
res.header("Content-Type", "application/pkix-cert");
@@ -198,17 +208,19 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},
handler: async (req) => {
const ca = await server.services.certificateAuthority.updateCaById({
const ca = await server.services.internalCertificateAuthority.updateCaById({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
isInternal: false,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
enableDirectIssuance: !req.body.requireTemplateForIssuance,
...req.body
});
@@ -220,6 +232,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
metadata: {
caId: ca.id,
dn: ca.dn,
name: ca.name,
status: ca.status as CaStatus
}
}
@@ -247,12 +260,12 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
ca: CertificateAuthoritiesSchema
ca: InternalCertificateAuthorityResponseSchema
})
}
},
handler: async (req) => {
const ca = await server.services.certificateAuthority.deleteCaById({
const ca = await server.services.internalCertificateAuthority.deleteCaById({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -266,6 +279,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
event: {
type: EventType.DELETE_CA,
metadata: {
name: ca.name,
caId: ca.id,
dn: ca.dn
}
@@ -299,7 +313,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { ca, csr } = await server.services.certificateAuthority.getCaCsr({
const { ca, csr } = await server.services.internalCertificateAuthority.getCaCsr({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -353,7 +367,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, serialNumber, ca } =
await server.services.certificateAuthority.renewCaCert({
await server.services.internalCertificateAuthority.renewCaCert({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -408,7 +422,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { caCerts, ca } = await server.services.certificateAuthority.getCaCerts({
const { caCerts, ca } = await server.services.internalCertificateAuthority.getCaCerts({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -455,13 +469,14 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { certificate, certificateChain, serialNumber, ca } = await server.services.certificateAuthority.getCaCert({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
const { certificate, certificateChain, serialNumber, ca } =
await server.services.internalCertificateAuthority.getCaCert({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
@@ -517,7 +532,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, issuingCaCertificate, serialNumber, ca } =
await server.services.certificateAuthority.signIntermediate({
await server.services.internalCertificateAuthority.signIntermediate({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -574,7 +589,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { ca } = await server.services.certificateAuthority.importCertToCa({
const { ca } = await server.services.internalCertificateAuthority.importCertToCa({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -653,7 +668,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, issuingCaCertificate, privateKey, serialNumber, ca } =
await server.services.certificateAuthority.issueCertFromCa({
await server.services.internalCertificateAuthority.issueCertFromCa({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
@@ -746,7 +761,7 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, issuingCaCertificate, serialNumber, ca, commonName } =
await server.services.certificateAuthority.signCertFromCa({
await server.services.internalCertificateAuthority.signCertFromCa({
isInternal: false,
caId: req.params.caId,
actor: req.permission.type,
@@ -809,13 +824,15 @@ export const registerCaRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { certificateTemplates, ca } = await server.services.certificateAuthority.getCaCertificateTemplates({
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
const { certificateTemplates, ca } = await server.services.internalCertificateAuthority.getCaCertificateTemplates(
{
caId: req.params.caId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
}
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
@@ -0,0 +1,18 @@
import {
AcmeCertificateAuthoritySchema,
CreateAcmeCertificateAuthoritySchema,
UpdateAcmeCertificateAuthoritySchema
} from "@app/services/certificate-authority/acme/acme-certificate-authority-schemas";
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import { registerCertificateAuthorityEndpoints } from "./certificate-authority-endpoints";
export const registerAcmeCertificateAuthorityRouter = async (server: FastifyZodProvider) => {
registerCertificateAuthorityEndpoints({
caType: CaType.ACME,
server,
responseSchema: AcmeCertificateAuthoritySchema,
createSchema: CreateAcmeCertificateAuthoritySchema,
updateSchema: UpdateAcmeCertificateAuthoritySchema
});
};
@@ -0,0 +1,258 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags } from "@app/lib/api-docs";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CaStatus, CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import {
TCertificateAuthority,
TCertificateAuthorityInput
} from "@app/services/certificate-authority/certificate-authority-types";
export const registerCertificateAuthorityEndpoints = <
T extends TCertificateAuthority,
I extends TCertificateAuthorityInput
>({
server,
caType,
createSchema,
updateSchema,
responseSchema
}: {
caType: CaType;
server: FastifyZodProvider;
createSchema: z.ZodType<{
name: string;
projectId: string;
status: CaStatus;
configuration: I["configuration"];
enableDirectIssuance: boolean;
}>;
updateSchema: z.ZodType<{
projectId: string;
name?: string;
status?: CaStatus;
configuration?: I["configuration"];
enableDirectIssuance?: boolean;
}>;
responseSchema: z.ZodTypeAny;
}) => {
server.route({
method: "GET",
url: `/`,
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
querystring: z.object({
projectId: z.string().trim().min(1, "Project ID required")
}),
response: {
200: responseSchema.array()
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const {
query: { projectId }
} = req;
const certificateAuthorities = (await server.services.certificateAuthority.listCertificateAuthoritiesByProjectId(
{ projectId, type: caType },
req.permission
)) as T[];
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId,
event: {
type: EventType.GET_CAS,
metadata: {
caIds: certificateAuthorities.map((ca) => ca.id)
}
}
});
return certificateAuthorities;
}
});
server.route({
method: "GET",
url: "/:caName",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
params: z.object({
caName: z.string()
}),
querystring: z.object({
projectId: z.string().uuid()
}),
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { caName } = req.params;
const { projectId } = req.query;
const certificateAuthority =
(await server.services.certificateAuthority.findCertificateAuthorityByNameAndProjectId(
{ caName, type: caType, projectId },
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.GET_CA,
metadata: {
caId: certificateAuthority.id,
name: certificateAuthority.name
}
}
});
return certificateAuthority;
}
});
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
body: createSchema,
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const certificateAuthority = (await server.services.certificateAuthority.createCertificateAuthority(
{ ...req.body, type: caType },
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.CREATE_CA,
metadata: {
name: certificateAuthority.name,
caId: certificateAuthority.id
}
}
});
return certificateAuthority;
}
});
server.route({
method: "PATCH",
url: "/:caName",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
params: z.object({
caName: z.string()
}),
body: updateSchema,
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { caName } = req.params;
const certificateAuthority = (await server.services.certificateAuthority.updateCertificateAuthority(
{
...req.body,
type: caType,
caName
},
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.UPDATE_CA,
metadata: {
name: certificateAuthority.name,
caId: certificateAuthority.id,
status: certificateAuthority.status
}
}
});
return certificateAuthority;
}
});
server.route({
method: "DELETE",
url: "/:caName",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
params: z.object({
caName: z.string()
}),
body: z.object({
projectId: z.string().uuid()
}),
response: {
200: responseSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { caName } = req.params;
const { projectId } = req.body;
const certificateAuthority = (await server.services.certificateAuthority.deleteCertificateAuthority(
{ caName, type: caType, projectId },
req.permission
)) as T;
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: certificateAuthority.projectId,
event: {
type: EventType.DELETE_CA,
metadata: {
name: certificateAuthority.name,
caId: certificateAuthority.id
}
}
});
return certificateAuthority;
}
});
};
@@ -0,0 +1,12 @@
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import { registerAcmeCertificateAuthorityRouter } from "./acme-certificate-authority-router";
import { registerInternalCertificateAuthorityRouter } from "./internal-certificate-authority-router";
export * from "./internal-certificate-authority-router";
export const CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP: Record<CaType, (server: FastifyZodProvider) => Promise<void>> =
{
[CaType.INTERNAL]: registerInternalCertificateAuthorityRouter,
[CaType.ACME]: registerAcmeCertificateAuthorityRouter
};
@@ -0,0 +1,18 @@
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import {
CreateInternalCertificateAuthoritySchema,
InternalCertificateAuthoritySchema,
UpdateInternalCertificateAuthoritySchema
} from "@app/services/certificate-authority/internal/internal-certificate-authority-schemas";
import { registerCertificateAuthorityEndpoints } from "./certificate-authority-endpoints";
export const registerInternalCertificateAuthorityRouter = async (server: FastifyZodProvider) => {
registerCertificateAuthorityEndpoints({
caType: CaType.INTERNAL,
server,
responseSchema: InternalCertificateAuthoritySchema,
createSchema: CreateInternalCertificateAuthoritySchema,
updateSchema: UpdateInternalCertificateAuthoritySchema
});
};
@@ -39,7 +39,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { cert, ca } = await server.services.certificate.getCert({
const { cert } = await server.services.certificate.getCert({
serialNumber: req.params.serialNumber,
actor: req.permission.type,
actorId: req.permission.id,
@@ -49,7 +49,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: ca.projectId,
projectId: cert.projectId,
event: {
type: EventType.GET_CERT,
metadata: {
@@ -86,7 +86,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req, reply) => {
const { ca, cert, certPrivateKey } = await server.services.certificate.getCertPrivateKey({
const { cert, certPrivateKey } = await server.services.certificate.getCertPrivateKey({
serialNumber: req.params.serialNumber,
actor: req.permission.type,
actorId: req.permission.id,
@@ -96,7 +96,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: ca.projectId,
projectId: cert.projectId,
event: {
type: EventType.GET_CERT_PRIVATE_KEY,
metadata: {
@@ -138,7 +138,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req, reply) => {
const { certificate, certificateChain, serialNumber, cert, ca, privateKey } =
const { certificate, certificateChain, serialNumber, cert, privateKey } =
await server.services.certificate.getCertBundle({
serialNumber: req.params.serialNumber,
actor: req.permission.type,
@@ -149,7 +149,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: ca.projectId,
projectId: cert.projectId,
event: {
type: EventType.GET_CERT_BUNDLE,
metadata: {
@@ -242,7 +242,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, issuingCaCertificate, privateKey, serialNumber, ca } =
await server.services.certificateAuthority.issueCertFromCa({
await server.services.internalCertificateAuthority.issueCertFromCa({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
@@ -284,6 +284,68 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
}
});
server.route({
method: "POST",
url: "/import-certificate",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificates],
description: "Import certificate",
body: z.object({
projectSlug: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.projectSlug),
certificatePem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.certificatePem),
privateKeyPem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.privateKeyPem),
chainPem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.chainPem),
friendlyName: z.string().trim().optional().describe(CERTIFICATES.IMPORT.friendlyName),
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATES.IMPORT.pkiCollectionId)
}),
response: {
200: z.object({
certificate: z.string().trim().describe(CERTIFICATES.IMPORT.certificate),
certificateChain: z.string().trim().describe(CERTIFICATES.IMPORT.certificateChain),
privateKey: z.string().trim().describe(CERTIFICATES.IMPORT.privateKey),
serialNumber: z.string().trim().describe(CERTIFICATES.IMPORT.serialNumber)
})
}
},
handler: async (req) => {
const { certificate, certificateChain, privateKey, serialNumber, cert } =
await server.services.certificate.importCert({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: cert.projectId,
event: {
type: EventType.IMPORT_CERT,
metadata: {
certId: cert.id,
cn: cert.commonName,
serialNumber
}
}
});
return {
certificate,
certificateChain,
privateKey,
serialNumber
};
}
});
server.route({
method: "POST",
url: "/sign-certificate",
@@ -355,7 +417,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
},
handler: async (req) => {
const { certificate, certificateChain, issuingCaCertificate, serialNumber, ca, commonName } =
await server.services.certificateAuthority.signCertFromCa({
await server.services.internalCertificateAuthority.signCertFromCa({
isInternal: false,
actor: req.permission.type,
actorId: req.permission.id,
@@ -474,7 +536,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { deletedCert, ca } = await server.services.certificate.deleteCert({
const { deletedCert } = await server.services.certificate.deleteCert({
serialNumber: req.params.serialNumber,
actor: req.permission.type,
actorId: req.permission.id,
@@ -484,7 +546,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: ca.projectId,
projectId: deletedCert.projectId,
event: {
type: EventType.DELETE_CERT,
metadata: {
@@ -524,7 +586,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { certificate, certificateChain, serialNumber, cert, ca } = await server.services.certificate.getCertBody({
const { certificate, certificateChain, serialNumber, cert } = await server.services.certificate.getCertBody({
serialNumber: req.params.serialNumber,
actor: req.permission.type,
actorId: req.permission.id,
@@ -534,7 +596,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: ca.projectId,
projectId: cert.projectId,
event: {
type: EventType.GET_CERT_BODY,
metadata: {
@@ -5,6 +5,7 @@ import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags, CERTIFICATE_TEMPLATES } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { slugSchema } from "@app/server/lib/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CertExtendedKeyUsage, CertKeyUsage } from "@app/services/certificate/certificate-types";
@@ -72,7 +73,7 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid
body: z.object({
caId: z.string().describe(CERTIFICATE_TEMPLATES.CREATE.caId),
pkiCollectionId: z.string().optional().describe(CERTIFICATE_TEMPLATES.CREATE.pkiCollectionId),
name: z.string().min(1).describe(CERTIFICATE_TEMPLATES.CREATE.name),
name: slugSchema().describe(CERTIFICATE_TEMPLATES.CREATE.name),
commonName: validateTemplateRegexField.describe(CERTIFICATE_TEMPLATES.CREATE.commonName),
subjectAlternativeName: validateTemplateRegexField.describe(
CERTIFICATE_TEMPLATES.CREATE.subjectAlternativeName
@@ -141,7 +142,7 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid
body: z.object({
caId: z.string().optional().describe(CERTIFICATE_TEMPLATES.UPDATE.caId),
pkiCollectionId: z.string().optional().describe(CERTIFICATE_TEMPLATES.UPDATE.pkiCollectionId),
name: z.string().min(1).optional().describe(CERTIFICATE_TEMPLATES.UPDATE.name),
name: slugSchema().optional().describe(CERTIFICATE_TEMPLATES.UPDATE.name),
commonName: validateTemplateRegexField.optional().describe(CERTIFICATE_TEMPLATES.UPDATE.commonName),
subjectAlternativeName: validateTemplateRegexField
.optional()
@@ -114,10 +114,12 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
CharacterType.Numbers,
CharacterType.Colon,
CharacterType.Period,
CharacterType.ForwardSlash
CharacterType.ForwardSlash,
CharacterType.Hyphen
])(val),
{
message: "Kubernetes host must only contain alphabets, numbers, colons, periods, and forward slashes."
message:
"Kubernetes host must only contain alphabets, numbers, colons, periods, hyphen, and forward slashes."
}
),
caCert: z.string().trim().default("").describe(KUBERNETES_AUTH.ATTACH.caCert),
@@ -234,11 +236,13 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
CharacterType.Numbers,
CharacterType.Colon,
CharacterType.Period,
CharacterType.ForwardSlash
CharacterType.ForwardSlash,
CharacterType.Hyphen
])(val);
},
{
message: "Kubernetes host must only contain alphabets, numbers, colons, periods, and forward slashes."
message:
"Kubernetes host must only contain alphabets, numbers, colons, periods, hyphen, and forward slashes."
}
),
caCert: z.string().trim().optional().describe(KUBERNETES_AUTH.UPDATE.caCert),
@@ -47,8 +47,15 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
},
handler: async (req) => {
const { identityUa, accessToken, identityAccessToken, validClientSecretInfo, identityMembershipOrg } =
await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
const {
identityUa,
accessToken,
identityAccessToken,
validClientSecretInfo,
identityMembershipOrg,
accessTokenTTL,
accessTokenMaxTTL
} = await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
@@ -63,11 +70,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
}
});
return {
accessToken,
tokenType: "Bearer" as const,
expiresIn: identityUa.accessTokenTTL,
accessTokenMaxTTL: identityUa.accessTokenMaxTTL
expiresIn: accessTokenTTL,
accessTokenMaxTTL
};
}
});
@@ -128,7 +136,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
.int()
.min(0)
.default(0)
.describe(UNIVERSAL_AUTH.ATTACH.accessTokenNumUsesLimit)
.describe(UNIVERSAL_AUTH.ATTACH.accessTokenNumUsesLimit),
accessTokenPeriod: z.number().int().min(0).default(0).describe(UNIVERSAL_AUTH.ATTACH.accessTokenPeriod)
})
.refine(
(val) => val.accessTokenTTL <= val.accessTokenMaxTTL,
@@ -227,7 +236,14 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
.min(0)
.max(315360000)
.optional()
.describe(UNIVERSAL_AUTH.UPDATE.accessTokenMaxTTL)
.describe(UNIVERSAL_AUTH.UPDATE.accessTokenMaxTTL),
accessTokenPeriod: z
.number()
.int()
.min(0)
.max(315360000)
.optional()
.describe(UNIVERSAL_AUTH.UPDATE.accessTokenPeriod)
})
.refine(
(val) => (val.accessTokenMaxTTL && val.accessTokenTTL ? val.accessTokenTTL <= val.accessTokenMaxTTL : true),
+11
View File
@@ -10,6 +10,7 @@ import { registerAdminRouter } from "./admin-router";
import { registerAuthRoutes } from "./auth-router";
import { registerProjectBotRouter } from "./bot-router";
import { registerCaRouter } from "./certificate-authority-router";
import { CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP } from "./certificate-authority-routers";
import { registerCertRouter } from "./certificate-router";
import { registerCertificateTemplateRouter } from "./certificate-template-router";
import { registerExternalGroupOrgRoleMappingRouter } from "./external-group-org-role-mapping-router";
@@ -104,6 +105,16 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
await server.register(
async (pkiRouter) => {
await pkiRouter.register(registerCaRouter, { prefix: "/ca" });
await pkiRouter.register(
async (caRouter) => {
for await (const [caType, router] of Object.entries(CERTIFICATE_AUTHORITY_REGISTER_ROUTER_MAP)) {
await caRouter.register(router, { prefix: `/${caType}` });
}
},
{
prefix: "/ca"
}
);
await pkiRouter.register(registerCertRouter, { prefix: "/certificates" });
await pkiRouter.register(registerCertificateTemplateRouter, { prefix: "/certificate-templates" });
await pkiRouter.register(registerPkiAlertRouter, { prefix: "/alerts" });
@@ -16,7 +16,12 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
method: "POST",
schema: {
body: z.object({
inviteeEmails: z.array(z.string().trim().email()),
inviteeEmails: z
.string()
.trim()
.email()
.array()
.refine((val) => val.every((el) => el === el.toLowerCase()), "Email must be lowercase"),
organizationId: z.string().trim(),
projects: z
.object({
@@ -115,7 +120,11 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
},
schema: {
body: z.object({
email: z.string().trim().email(),
email: z
.string()
.trim()
.email()
.refine((val) => val === val.toLowerCase(), "Email must be lowercase"),
organizationId: z.string().trim(),
code: z.string().trim()
}),
@@ -281,7 +281,18 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
kmsProductEnabled: z.boolean().optional(),
sshProductEnabled: z.boolean().optional(),
scannerProductEnabled: z.boolean().optional(),
shareSecretsProductEnabled: z.boolean().optional()
shareSecretsProductEnabled: z.boolean().optional(),
maxSharedSecretLifetime: z
.number()
.min(300, "Max Shared Secret lifetime cannot be under 5 minutes")
.max(2592000, "Max Shared Secret lifetime cannot exceed 30 days")
.optional(),
maxSharedSecretViewLimit: z
.number()
.min(1, "Max Shared Secret view count cannot be lower than 1")
.max(1000, "Max Shared Secret view count cannot exceed 1000")
.nullable()
.optional()
}),
response: {
200: z.object({
@@ -301,8 +312,17 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
data: req.body
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.UPDATE_ORG,
metadata: req.body
}
});
return {
message: "Successfully changed organization name",
message: "Successfully updated organization",
organization
};
}
@@ -5,6 +5,7 @@ import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags, PKI_SUBSCRIBERS } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { addNoCacheHeaders } from "@app/server/lib/caching";
import { slugSchema } from "@app/server/lib/schemas";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
@@ -90,7 +91,8 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
ttl: z
.string()
.trim()
.refine((val) => ms(val) > 0, "TTL must be a positive number")
.refine((val) => !val || ms(val) > 0, "TTL must be a positive number")
.optional()
.describe(PKI_SUBSCRIBERS.CREATE.ttl),
subjectAlternativeNames: validateAltNameField
.array()
@@ -108,7 +110,9 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
.array()
.default([])
.transform((arr) => Array.from(new Set(arr)))
.describe(PKI_SUBSCRIBERS.CREATE.extendedKeyUsages)
.describe(PKI_SUBSCRIBERS.CREATE.extendedKeyUsages),
enableAutoRenewal: z.boolean().optional().describe(PKI_SUBSCRIBERS.CREATE.enableAutoRenewal),
autoRenewalPeriodInDays: z.number().min(1).optional().describe(PKI_SUBSCRIBERS.CREATE.autoRenewalPeriodInDays)
}),
response: {
200: sanitizedPkiSubscriber
@@ -134,7 +138,7 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
caId: subscriber.caId ?? undefined,
name: subscriber.name,
commonName: subscriber.commonName,
ttl: subscriber.ttl,
ttl: subscriber.ttl ?? undefined,
subjectAlternativeNames: subscriber.subjectAlternativeNames,
keyUsages: subscriber.keyUsages as CertKeyUsage[],
extendedKeyUsages: subscriber.extendedKeyUsages as CertExtendedKeyUsage[]
@@ -179,7 +183,7 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
ttl: z
.string()
.trim()
.refine((val) => ms(val) > 0, "TTL must be a positive number")
.refine((val) => !val || ms(val) > 0, "TTL must be a positive number")
.optional()
.describe(PKI_SUBSCRIBERS.UPDATE.ttl),
keyUsages: z
@@ -193,7 +197,9 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
.array()
.transform((arr) => Array.from(new Set(arr)))
.optional()
.describe(PKI_SUBSCRIBERS.UPDATE.extendedKeyUsages)
.describe(PKI_SUBSCRIBERS.UPDATE.extendedKeyUsages),
enableAutoRenewal: z.boolean().optional().describe(PKI_SUBSCRIBERS.UPDATE.enableAutoRenewal),
autoRenewalPeriodInDays: z.number().min(1).optional().describe(PKI_SUBSCRIBERS.UPDATE.autoRenewalPeriodInDays)
}),
response: {
200: sanitizedPkiSubscriber
@@ -219,7 +225,7 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
caId: subscriber.caId ?? undefined,
name: subscriber.name,
commonName: subscriber.commonName,
ttl: subscriber.ttl,
ttl: subscriber.ttl ?? undefined,
subjectAlternativeNames: subscriber.subjectAlternativeNames,
keyUsages: subscriber.keyUsages as CertKeyUsage[],
extendedKeyUsages: subscriber.extendedKeyUsages as CertExtendedKeyUsage[]
@@ -278,6 +284,67 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
}
});
server.route({
method: "POST",
url: "/:subscriberName/order-certificate",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.PkiSubscribers],
description: "Order certificate",
params: z.object({
subscriberName: z.string().describe(PKI_SUBSCRIBERS.ISSUE_CERT.subscriberName)
}),
body: z.object({
projectId: z.string().trim().describe(PKI_SUBSCRIBERS.ISSUE_CERT.projectId)
}),
response: {
200: z.object({
message: z.string().trim()
})
}
},
handler: async (req) => {
const subscriber = await server.services.pkiSubscriber.orderSubscriberCert({
subscriberName: req.params.subscriberName,
projectId: req.body.projectId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: subscriber.projectId,
event: {
type: EventType.ISSUE_PKI_SUBSCRIBER_CERT,
metadata: {
subscriberId: subscriber.id,
name: subscriber.name
}
}
});
await server.services.telemetry.sendPostHogEvents({
event: PostHogEventTypes.IssueCert,
distinctId: getTelemetryDistinctId(req),
properties: {
subscriberId: subscriber.id,
commonName: subscriber.commonName,
...req.auditLogInfo
}
});
return {
message: "Successfully placed order for certificate"
};
}
});
server.route({
method: "POST",
url: "/:subscriberName/issue-certificate",
@@ -420,6 +487,72 @@ export const registerPkiSubscriberRouter = async (server: FastifyZodProvider) =>
}
});
server.route({
method: "GET",
url: "/:subscriberName/latest-certificate-bundle",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiSubscribers],
description: "Get latest certificate bundle of a subscriber",
params: z.object({
subscriberName: z.string().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.subscriberName)
}),
querystring: z.object({
projectId: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.projectId)
}),
response: {
200: z.object({
certificate: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.certificate),
certificateChain: z
.string()
.trim()
.nullable()
.describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.certificateChain),
privateKey: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.privateKey),
serialNumber: z.string().trim().describe(PKI_SUBSCRIBERS.GET_LATEST_CERT_BUNDLE.serialNumber)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req, reply) => {
const { certificate, certificateChain, serialNumber, cert, privateKey, subscriber } =
await server.services.pkiSubscriber.getSubscriberActiveCertBundle({
subscriberName: req.params.subscriberName,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: cert.projectId,
event: {
type: EventType.GET_SUBSCRIBER_ACTIVE_CERT_BUNDLE,
metadata: {
subscriberId: subscriber.id,
name: subscriber.name,
certId: cert.id,
serialNumber: cert.serialNumber
}
}
});
addNoCacheHeaders(reply);
return {
certificate,
certificateChain,
serialNumber,
privateKey
};
}
});
server.route({
method: "GET",
url: "/:subscriberName/certificates",
@@ -270,6 +270,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: req.params.workspaceId,
event: {
type: EventType.DELETE_PROJECT,
metadata: workspace
}
});
return { workspace };
}
});
@@ -304,6 +315,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
name: req.body.name
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: req.params.workspaceId,
event: {
type: EventType.UPDATE_PROJECT,
metadata: req.body
}
});
return {
message: "Successfully changed workspace name",
workspace
@@ -382,6 +404,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: req.params.workspaceId,
event: {
type: EventType.UPDATE_PROJECT,
metadata: req.body
}
});
return {
workspace
};
@@ -418,6 +451,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
autoCapitalization: req.body.autoCapitalization
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: req.params.workspaceId,
event: {
type: EventType.UPDATE_PROJECT,
metadata: req.body
}
});
return {
message: "Successfully changed workspace settings",
workspace
@@ -455,6 +499,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
hasDeleteProtection: req.body.hasDeleteProtection
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: req.params.workspaceId,
event: {
type: EventType.UPDATE_PROJECT,
metadata: req.body
}
});
return {
message: "Successfully changed workspace settings",
workspace
@@ -493,6 +548,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
workspaceSlug: req.params.workspaceSlug
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: workspace.id,
event: {
type: EventType.UPDATE_PROJECT,
metadata: req.body
}
});
return {
message: "Successfully changed workspace version limit",
workspace
@@ -531,6 +596,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
auditLogsRetentionDays: req.body.auditLogsRetentionDays
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: workspace.id,
event: {
type: EventType.UPDATE_PROJECT,
metadata: req.body
}
});
return {
message: "Successfully updated project's audit logs retention period",
workspace
@@ -62,9 +62,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
}),
body: z.object({
hashedHex: z.string().min(1).optional(),
password: z.string().optional(),
email: z.string().optional(),
hash: z.string().optional()
password: z.string().optional()
}),
response: {
200: z.object({
@@ -91,8 +89,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
hashedHex: req.body.hashedHex,
password: req.body.password,
orgId: req.permission?.orgId,
email: req.body.email,
hash: req.body.hash
actorId: req.permission?.id
});
if (sharedSecret.secret?.orgId) {
@@ -156,7 +153,13 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
expiresAt: z.string(),
expiresAfterViews: z.number().min(1).optional(),
accessType: z.nativeEnum(SecretSharingAccessType).default(SecretSharingAccessType.Organization),
emails: z.string().email().array().max(100).optional()
emails: z
.string()
.email()
.array()
.max(100)
.optional()
.transform((val) => (val ? [...new Set(val)] : undefined))
}),
response: {
200: z.object({
@@ -0,0 +1,17 @@
import {
CreateOnePassSyncSchema,
OnePassSyncSchema,
UpdateOnePassSyncSchema
} from "@app/services/secret-sync/1password";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerOnePassSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.OnePass,
server,
responseSchema: OnePassSyncSchema,
createSchema: CreateOnePassSyncSchema,
updateSchema: UpdateOnePassSyncSchema
});
@@ -1,5 +1,7 @@
import { registerOCIVaultSyncRouter } from "@app/ee/routes/v1/secret-sync-routers/oci-vault-sync-router";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerOnePassSyncRouter } from "./1password-sync-router";
import { registerAwsParameterStoreSyncRouter } from "./aws-parameter-store-sync-router";
import { registerAwsSecretsManagerSyncRouter } from "./aws-secrets-manager-sync-router";
import { registerAzureAppConfigurationSyncRouter } from "./azure-app-configuration-sync-router";
@@ -10,7 +12,6 @@ import { registerGcpSyncRouter } from "./gcp-sync-router";
import { registerGitHubSyncRouter } from "./github-sync-router";
import { registerHCVaultSyncRouter } from "./hc-vault-sync-router";
import { registerHumanitecSyncRouter } from "./humanitec-sync-router";
import { registerOCIVaultSyncRouter } from "./oci-vault-sync-router";
import { registerTeamCitySyncRouter } from "./teamcity-sync-router";
import { registerTerraformCloudSyncRouter } from "./terraform-cloud-sync-router";
import { registerVercelSyncRouter } from "./vercel-sync-router";
@@ -33,5 +34,6 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
[SecretSync.Windmill]: registerWindmillSyncRouter,
[SecretSync.HCVault]: registerHCVaultSyncRouter,
[SecretSync.TeamCity]: registerTeamCitySyncRouter,
[SecretSync.OCIVault]: registerOCIVaultSyncRouter
[SecretSync.OCIVault]: registerOCIVaultSyncRouter,
[SecretSync.OnePass]: registerOnePassSyncRouter
};
@@ -1,17 +0,0 @@
import {
CreateOCIVaultSyncSchema,
OCIVaultSyncSchema,
UpdateOCIVaultSyncSchema
} from "@app/services/secret-sync/oci-vault";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerOCIVaultSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.OCIVault,
server,
responseSchema: OCIVaultSyncSchema,
createSchema: CreateOCIVaultSyncSchema,
updateSchema: UpdateOCIVaultSyncSchema
});
@@ -1,10 +1,12 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { OCIVaultSyncListItemSchema, OCIVaultSyncSchema } from "@app/ee/services/secret-sync/oci-vault";
import { ApiDocsTags, SecretSyncs } from "@app/lib/api-docs";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { OnePassSyncListItemSchema, OnePassSyncSchema } from "@app/services/secret-sync/1password";
import {
AwsParameterStoreSyncListItemSchema,
AwsParameterStoreSyncSchema
@@ -24,7 +26,6 @@ import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
import { HCVaultSyncListItemSchema, HCVaultSyncSchema } from "@app/services/secret-sync/hc-vault";
import { HumanitecSyncListItemSchema, HumanitecSyncSchema } from "@app/services/secret-sync/humanitec";
import { OCIVaultSyncListItemSchema, OCIVaultSyncSchema } from "@app/services/secret-sync/oci-vault";
import { TeamCitySyncListItemSchema, TeamCitySyncSchema } from "@app/services/secret-sync/teamcity";
import { TerraformCloudSyncListItemSchema, TerraformCloudSyncSchema } from "@app/services/secret-sync/terraform-cloud";
import { VercelSyncListItemSchema, VercelSyncSchema } from "@app/services/secret-sync/vercel";
@@ -45,7 +46,8 @@ const SecretSyncSchema = z.discriminatedUnion("destination", [
WindmillSyncSchema,
HCVaultSyncSchema,
TeamCitySyncSchema,
OCIVaultSyncSchema
OCIVaultSyncSchema,
OnePassSyncSchema
]);
const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
@@ -63,7 +65,8 @@ const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
WindmillSyncListItemSchema,
HCVaultSyncListItemSchema,
TeamCitySyncListItemSchema,
OCIVaultSyncListItemSchema
OCIVaultSyncListItemSchema,
OnePassSyncListItemSchema
]);
export const registerSecretSyncRouter = async (server: FastifyZodProvider) => {
@@ -46,6 +46,54 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
}
});
server.route({
method: "GET",
url: "/duplicate-accounts",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.object({
users: UsersSchema.extend({
isMyAccount: z.boolean(),
organizations: z.object({ name: z.string(), slug: z.string() }).array()
}).array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT], { requireOrg: false }),
handler: async (req) => {
if (req.auth.authMode === AuthMode.JWT && req.auth.user.email) {
const users = await server.services.user.getAllMyAccounts(req.auth.user.email, req.permission.id);
return { users };
}
return { users: [] };
}
});
server.route({
method: "POST",
url: "/remove-duplicate-accounts",
config: {
rateLimit: writeLimit
},
schema: {
response: {
200: z.object({
message: z.string()
})
}
},
onRequest: verifyAuth([AuthMode.JWT], { requireOrg: false }),
handler: async (req) => {
if (req.auth.authMode === AuthMode.JWT && req.auth.user.email) {
await server.services.user.removeMyDuplicateAccounts(req.auth.user.email, req.permission.id);
}
return { message: "Removed all duplicate accounts" };
}
});
server.route({
method: "GET",
url: "/private-key",
@@ -0,0 +1,71 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ApiDocsTags } from "@app/lib/api-docs";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { AcmeCertificateAuthoritySchema } from "@app/services/certificate-authority/acme/acme-certificate-authority-schemas";
import { CaType } from "@app/services/certificate-authority/certificate-authority-enums";
import { InternalCertificateAuthoritySchema } from "@app/services/certificate-authority/internal/internal-certificate-authority-schemas";
const CertificateAuthoritySchema = z.discriminatedUnion("type", [
InternalCertificateAuthoritySchema,
AcmeCertificateAuthoritySchema
]);
export const registerCaRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateAuthorities],
description: "Get Certificate Authorities",
querystring: z.object({
projectId: z.string()
}),
response: {
200: z.object({
certificateAuthorities: CertificateAuthoritySchema.array()
})
}
},
handler: async (req) => {
const internalCas = await server.services.certificateAuthority.listCertificateAuthoritiesByProjectId(
{
projectId: req.query.projectId,
type: CaType.INTERNAL
},
req.permission
);
const acmeCas = await server.services.certificateAuthority.listCertificateAuthoritiesByProjectId(
{
projectId: req.query.projectId,
type: CaType.ACME
},
req.permission
);
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
projectId: req.query.projectId,
event: {
type: EventType.GET_CAS,
metadata: {
caIds: [...(internalCas ?? []).map((ca) => ca.id), ...(acmeCas ?? []).map((ca) => ca.id)]
}
}
});
return {
certificateAuthorities: [...(internalCas ?? []), ...(acmeCas ?? [])]
};
}
});
};
+11
View File
@@ -1,9 +1,11 @@
import { registerCaRouter } from "./certificate-authority-router";
import { registerGroupProjectRouter } from "./group-project-router";
import { registerIdentityOrgRouter } from "./identity-org-router";
import { registerIdentityProjectRouter } from "./identity-project-router";
import { registerMfaRouter } from "./mfa-router";
import { registerOrgRouter } from "./organization-router";
import { registerPasswordRouter } from "./password-router";
import { registerPkiTemplatesRouter } from "./pki-templates-router";
import { registerProjectMembershipRouter } from "./project-membership-router";
import { registerProjectRouter } from "./project-router";
import { registerServiceTokenRouter } from "./service-token-router";
@@ -14,6 +16,15 @@ export const registerV2Routes = async (server: FastifyZodProvider) => {
await server.register(registerUserRouter, { prefix: "/users" });
await server.register(registerServiceTokenRouter, { prefix: "/service-token" });
await server.register(registerPasswordRouter, { prefix: "/password" });
await server.register(
async (pkiRouter) => {
await pkiRouter.register(registerCaRouter, { prefix: "/ca" });
await pkiRouter.register(registerPkiTemplatesRouter, { prefix: "/certificate-templates" });
},
{ prefix: "/pki" }
);
await server.register(
async (orgRouter) => {
await orgRouter.register(registerOrgRouter);
@@ -0,0 +1,309 @@
import { z } from "zod";
import { CertificateTemplatesSchema } from "@app/db/schemas";
import { ApiDocsTags } from "@app/lib/api-docs";
import { ms } from "@app/lib/ms";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { slugSchema } from "@app/server/lib/schemas";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CertExtendedKeyUsage, CertKeyUsage } from "@app/services/certificate/certificate-types";
import {
validateAltNamesField,
validateCaDateField
} from "@app/services/certificate-authority/certificate-authority-validators";
import { validateTemplateRegexField } from "@app/services/certificate-template/certificate-template-validators";
export const registerPkiTemplatesRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateTemplates],
body: z.object({
name: slugSchema(),
caName: slugSchema({ field: "caName" }),
projectId: z.string(),
commonName: validateTemplateRegexField,
subjectAlternativeName: validateTemplateRegexField,
ttl: z.string().refine((val) => ms(val) > 0, "TTL must be a positive number"),
keyUsages: z
.nativeEnum(CertKeyUsage)
.array()
.optional()
.default([CertKeyUsage.DIGITAL_SIGNATURE, CertKeyUsage.KEY_ENCIPHERMENT]),
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional().default([])
}),
response: {
200: z.object({
certificateTemplate: CertificateTemplatesSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const certificateTemplate = await server.services.pkiTemplate.createTemplate({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body
});
return { certificateTemplate };
}
});
server.route({
method: "PATCH",
url: "/:templateName",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateTemplates],
params: z.object({
templateName: slugSchema()
}),
body: z.object({
name: slugSchema().optional(),
caName: slugSchema(),
projectId: z.string(),
commonName: validateTemplateRegexField.optional(),
subjectAlternativeName: validateTemplateRegexField.optional(),
ttl: z
.string()
.refine((val) => ms(val) > 0, "TTL must be a positive number")
.optional(),
keyUsages: z
.nativeEnum(CertKeyUsage)
.array()
.optional()
.default([CertKeyUsage.DIGITAL_SIGNATURE, CertKeyUsage.KEY_ENCIPHERMENT]),
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional().default([])
}),
response: {
200: z.object({
certificateTemplate: CertificateTemplatesSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const certificateTemplate = await server.services.pkiTemplate.updateTemplate({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
templateName: req.params.templateName,
...req.body
});
return { certificateTemplate };
}
});
server.route({
method: "DELETE",
url: "/:templateName",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateTemplates],
params: z.object({
templateName: z.string().min(1)
}),
body: z.object({
projectId: z.string()
}),
response: {
200: z.object({
certificateTemplate: CertificateTemplatesSchema
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const certificateTemplate = await server.services.pkiTemplate.deleteTemplate({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
templateName: req.params.templateName,
projectId: req.body.projectId
});
return { certificateTemplate };
}
});
server.route({
method: "GET",
url: "/:templateName",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateTemplates],
params: z.object({
templateName: slugSchema()
}),
querystring: z.object({
projectId: z.string()
}),
response: {
200: z.object({
certificateTemplate: CertificateTemplatesSchema.extend({
ca: z.object({ id: z.string(), name: z.string() })
})
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const certificateTemplate = await server.services.pkiTemplate.getTemplateByName({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
templateName: req.params.templateName,
projectId: req.query.projectId
});
return { certificateTemplate };
}
});
server.route({
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateTemplates],
querystring: z.object({
projectId: z.string(),
limit: z.coerce.number().default(100),
offset: z.coerce.number().default(0)
}),
response: {
200: z.object({
certificateTemplates: CertificateTemplatesSchema.extend({
ca: z.object({ id: z.string(), name: z.string() })
}).array(),
totalCount: z.number()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { certificateTemplates, totalCount } = await server.services.pkiTemplate.listTemplate({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query
});
return { certificateTemplates, totalCount };
}
});
server.route({
method: "POST",
url: "/:templateName/issue-certificate",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateTemplates],
params: z.object({
templateName: slugSchema()
}),
body: z.object({
projectId: z.string(),
commonName: validateTemplateRegexField,
ttl: z.string().refine((val) => ms(val) > 0, "TTL must be a positive number"),
keyUsages: z.nativeEnum(CertKeyUsage).array().optional(),
extendedKeyUsages: z.nativeEnum(CertExtendedKeyUsage).array().optional(),
notBefore: validateCaDateField.optional(),
notAfter: validateCaDateField.optional(),
altNames: validateAltNamesField
}),
response: {
200: z.object({
certificate: z.string().trim(),
issuingCaCertificate: z.string().trim(),
certificateChain: z.string().trim(),
privateKey: z.string().trim(),
serialNumber: z.string().trim()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const data = await server.services.pkiTemplate.issueCertificate({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
templateName: req.params.templateName,
...req.body
});
return data;
}
});
server.route({
method: "POST",
url: "/:templateName/sign-certificate",
config: {
rateLimit: writeLimit
},
schema: {
hide: false,
tags: [ApiDocsTags.PkiCertificateTemplates],
params: z.object({
templateName: slugSchema()
}),
body: z.object({
projectId: z.string(),
ttl: z.string().refine((val) => ms(val) > 0, "TTL must be a positive number"),
csr: z.string().trim().min(1).max(4096)
}),
response: {
200: z.object({
certificate: z.string().trim(),
issuingCaCertificate: z.string().trim(),
certificateChain: z.string().trim(),
serialNumber: z.string().trim()
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const data = await server.services.pkiTemplate.signCertificate({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
templateName: req.params.templateName,
...req.body
});
return data;
}
});
};
@@ -27,8 +27,19 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
projectId: z.string().describe(PROJECT_USERS.INVITE_MEMBER.projectId)
}),
body: z.object({
emails: z.string().email().array().default([]).describe(PROJECT_USERS.INVITE_MEMBER.emails),
usernames: z.string().array().default([]).describe(PROJECT_USERS.INVITE_MEMBER.usernames),
emails: z
.string()
.email()
.array()
.default([])
.describe(PROJECT_USERS.INVITE_MEMBER.emails)
.refine((val) => val.every((el) => el === el.toLowerCase()), "Email must be lowercase"),
usernames: z
.string()
.array()
.default([])
.describe(PROJECT_USERS.INVITE_MEMBER.usernames)
.refine((val) => val.every((el) => el === el.toLowerCase()), "Username must be lowercase"),
roleSlugs: z.string().array().min(1).optional().describe(PROJECT_USERS.INVITE_MEMBER.roleSlugs)
}),
response: {
@@ -92,8 +103,19 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
projectId: z.string().describe(PROJECT_USERS.REMOVE_MEMBER.projectId)
}),
body: z.object({
emails: z.string().email().array().default([]).describe(PROJECT_USERS.REMOVE_MEMBER.emails),
usernames: z.string().array().default([]).describe(PROJECT_USERS.REMOVE_MEMBER.usernames)
emails: z
.string()
.email()
.array()
.default([])
.describe(PROJECT_USERS.REMOVE_MEMBER.emails)
.refine((val) => val.every((el) => el === el.toLowerCase()), "Email must be lowercase"),
usernames: z
.string()
.array()
.default([])
.describe(PROJECT_USERS.REMOVE_MEMBER.usernames)
.refine((val) => val.every((el) => el === el.toLowerCase()), "Username must be lowercase")
}),
response: {
200: z.object({
+34 -16
View File
@@ -1,7 +1,6 @@
import { z } from "zod";
import {
CertificateAuthoritiesSchema,
CertificatesSchema,
PkiAlertsSchema,
PkiCollectionsSchema,
@@ -22,13 +21,13 @@ import { slugSchema } from "@app/server/lib/schemas";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { CaStatus } from "@app/services/certificate-authority/certificate-authority-types";
import { CaStatus } from "@app/services/certificate-authority/certificate-authority-enums";
import { sanitizedCertificateTemplate } from "@app/services/certificate-template/certificate-template-schema";
import { sanitizedPkiSubscriber } from "@app/services/pki-subscriber/pki-subscriber-schema";
import { ProjectFilterType } from "@app/services/project/project-types";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { SanitizedProjectSchema } from "../sanitizedSchemas";
import { InternalCertificateAuthorityResponseSchema, SanitizedProjectSchema } from "../sanitizedSchemas";
const projectWithEnv = SanitizedProjectSchema.extend({
_id: z.string(),
@@ -206,19 +205,18 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
}
});
if (req.body.template) {
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
event: {
type: EventType.APPLY_PROJECT_TEMPLATE,
metadata: {
template: req.body.template,
projectId: project.id
}
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: project.id,
event: {
type: EventType.CREATE_PROJECT,
metadata: {
...req.body,
name: req.body.projectName
}
});
}
}
});
return { project };
}
@@ -262,6 +260,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: project.id,
event: {
type: EventType.DELETE_PROJECT,
metadata: project
}
});
return project;
}
});
@@ -341,6 +349,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: req.permission.orgId,
projectId: project.id,
event: {
type: EventType.UPDATE_PROJECT,
metadata: req.body
}
});
return project;
}
});
@@ -366,7 +384,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
}),
response: {
200: z.object({
cas: z.array(CertificateAuthoritiesSchema)
cas: z.array(InternalCertificateAuthorityResponseSchema)
})
}
},