Merge remote-tracking branch 'origin/main' into feat-secret-input-autocomplete

This commit is contained in:
Sheen Capadngan
2024-04-23 11:02:45 +08:00
939 changed files with 30576 additions and 10095 deletions
+3
View File
@@ -24,6 +24,7 @@ import { fastifyErrHandler } from "./plugins/error-handler";
import { registerExternalNextjs } from "./plugins/external-nextjs";
import { serializerCompiler, validatorCompiler, ZodTypeProvider } from "./plugins/fastify-zod";
import { fastifyIp } from "./plugins/ip";
import { maintenanceMode } from "./plugins/maintenanceMode";
import { fastifySwagger } from "./plugins/swagger";
import { registerRoutes } from "./routes";
@@ -72,6 +73,8 @@ export const main = async ({ db, smtp, logger, queue, keyStore }: TMain) => {
}
await server.register(helmet, { contentSecurityPolicy: false });
await server.register(maintenanceMode);
await server.register(registerRoutes, { smtp, queue, db, keyStore });
if (appCfg.isProductionMode) {
+31 -2
View File
@@ -18,14 +18,43 @@ export const globalRateLimiterCfg = (): RateLimitPluginOptions => {
};
};
export const authRateLimit: RateLimitOptions = {
// GET endpoints
export const readLimit: RateLimitOptions = {
timeWindow: 60 * 1000,
max: 600,
keyGenerator: (req) => req.realIp
};
export const passwordRateLimit: RateLimitOptions = {
// POST, PATCH, PUT, DELETE endpoints
export const writeLimit: RateLimitOptions = {
timeWindow: 60 * 1000,
max: 50,
keyGenerator: (req) => req.realIp
};
// special endpoints
export const secretsLimit: RateLimitOptions = {
// secrets, folders, secret imports
timeWindow: 60 * 1000,
max: 600,
keyGenerator: (req) => req.realIp
};
export const authRateLimit: RateLimitOptions = {
timeWindow: 60 * 1000,
max: 60,
keyGenerator: (req) => req.realIp
};
export const inviteUserRateLimit: RateLimitOptions = {
timeWindow: 60 * 1000,
max: 30,
keyGenerator: (req) => req.realIp
};
export const creationLimit: RateLimitOptions = {
// identity, project, org
timeWindow: 60 * 1000,
max: 30,
keyGenerator: (req) => req.realIp
};
@@ -6,42 +6,49 @@ import { TServiceTokens, TUsers } from "@app/db/schemas";
import { TScimTokenJwtPayload } from "@app/ee/services/scim/scim-types";
import { getConfig } from "@app/lib/config/env";
import { UnauthorizedError } from "@app/lib/errors";
import { ActorType, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
import { ActorType, AuthMethod, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
export type TAuthMode =
| {
orgId?: string;
authMode: AuthMode.JWT;
actor: ActorType.USER;
userId: string;
tokenVersionId: string; // the session id of token used
user: TUsers;
orgId: string;
authMethod: AuthMethod;
}
| {
authMode: AuthMode.API_KEY;
authMethod: null;
actor: ActorType.USER;
userId: string;
user: TUsers;
orgId?: string;
orgId: string;
}
| {
authMode: AuthMode.SERVICE_TOKEN;
serviceToken: TServiceTokens & { createdByEmail: string };
actor: ActorType.SERVICE;
serviceTokenId: string;
orgId: string;
authMethod: null;
}
| {
authMode: AuthMode.IDENTITY_ACCESS_TOKEN;
actor: ActorType.IDENTITY;
identityId: string;
identityName: string;
orgId: string;
authMethod: null;
}
| {
authMode: AuthMode.SCIM_TOKEN;
actor: ActorType.SCIM_CLIENT;
scimTokenId: string;
orgId: string;
authMethod: null;
};
const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
@@ -50,6 +57,7 @@ const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
return { authMode: AuthMode.API_KEY, token: apiKey, actor: ActorType.USER } as const;
}
const authHeader = req.headers?.authorization;
if (!authHeader) return { authMode: null, token: null };
const authTokenValue = authHeader.slice(7); // slice of after Bearer
@@ -71,6 +79,7 @@ const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
actor: ActorType.USER
} as const;
case AuthTokenType.API_KEY:
// throw new Error("API Key auth is no longer supported.");
return { authMode: AuthMode.API_KEY, token: decodedToken, actor: ActorType.USER } as const;
case AuthTokenType.IDENTITY_ACCESS_TOKEN:
return {
@@ -89,17 +98,30 @@ const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
}
};
// ! Important: You can only 100% count on the `req.permission.orgId` field being present when the auth method is Identity Access Token (Machine Identity).
export const injectIdentity = fp(async (server: FastifyZodProvider) => {
server.decorateRequest("auth", null);
server.addHook("onRequest", async (req) => {
const appCfg = getConfig();
const { authMode, token, actor } = await extractAuth(req, appCfg.AUTH_SECRET);
if (req.url.includes("/api/v3/auth/")) {
return;
}
if (!authMode) return;
switch (authMode) {
case AuthMode.JWT: {
const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token);
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor, orgId };
req.auth = {
authMode: AuthMode.JWT,
user,
userId: user.id,
tokenVersionId,
actor,
orgId: orgId as string,
authMethod: token.authMethod
};
break;
}
case AuthMode.IDENTITY_ACCESS_TOKEN: {
@@ -107,29 +129,40 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
req.auth = {
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
actor,
orgId: identity.orgId,
identityId: identity.identityId,
identityName: identity.name
identityName: identity.name,
authMethod: null
};
break;
}
case AuthMode.SERVICE_TOKEN: {
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token);
req.auth = {
orgId: serviceToken.orgId,
authMode: AuthMode.SERVICE_TOKEN as const,
serviceToken,
serviceTokenId: serviceToken.id,
actor
actor,
authMethod: null
};
break;
}
case AuthMode.API_KEY: {
const user = await server.services.apiKey.fnValidateApiKey(token as string);
req.auth = { authMode: AuthMode.API_KEY as const, userId: user.id, actor, user };
req.auth = {
authMode: AuthMode.API_KEY as const,
userId: user.id,
actor,
user,
orgId: "API_KEY", // We set the orgId to an arbitrary value, since we can't link an API key to a specific org. We have to deprecate API keys soon!
authMethod: null
};
break;
}
case AuthMode.SCIM_TOKEN: {
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId };
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId, authMethod: null };
break;
}
default:
@@ -9,13 +9,33 @@ export const injectPermission = fp(async (server) => {
if (!req.auth) return;
if (req.auth.actor === ActorType.USER) {
req.permission = { type: ActorType.USER, id: req.auth.userId, orgId: req.auth?.orgId };
req.permission = {
type: ActorType.USER,
id: req.auth.userId,
orgId: req.auth.orgId, // if the req.auth.authMode is AuthMode.API_KEY, the orgId will be "API_KEY"
authMethod: req.auth.authMethod // if the req.auth.authMode is AuthMode.API_KEY, the authMethod will be null
};
} else if (req.auth.actor === ActorType.IDENTITY) {
req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId };
req.permission = {
type: ActorType.IDENTITY,
id: req.auth.identityId,
orgId: req.auth.orgId,
authMethod: null
};
} else if (req.auth.actor === ActorType.SERVICE) {
req.permission = { type: ActorType.SERVICE, id: req.auth.serviceTokenId };
req.permission = {
type: ActorType.SERVICE,
id: req.auth.serviceTokenId,
orgId: req.auth.orgId,
authMethod: null
};
} else if (req.auth.actor === ActorType.SCIM_CLIENT) {
req.permission = { type: ActorType.SCIM_CLIENT, id: req.auth.scimTokenId, orgId: req.auth.orgId };
req.permission = {
type: ActorType.SCIM_CLIENT,
id: req.auth.scimTokenId,
orgId: req.auth.orgId,
authMethod: null
};
}
});
});
+14 -3
View File
@@ -3,15 +3,26 @@ import { FastifyReply, FastifyRequest, HookHandlerDoneFunction } from "fastify";
import { UnauthorizedError } from "@app/lib/errors";
import { AuthMode } from "@app/services/auth/auth-type";
interface TAuthOptions {
requireOrg: boolean;
}
export const verifyAuth =
<T extends FastifyRequest>(authStrats: AuthMode[]) =>
<T extends FastifyRequest>(authStrategies: AuthMode[], options: TAuthOptions = { requireOrg: true }) =>
(req: T, _res: FastifyReply, done: HookHandlerDoneFunction) => {
if (!Array.isArray(authStrats)) throw new Error("Auth strategy must be array");
if (!Array.isArray(authStrategies)) throw new Error("Auth strategy must be array");
if (!req.auth) throw new UnauthorizedError({ name: "Unauthorized access", message: "Token missing" });
const isAccessAllowed = authStrats.some((strat) => strat === req.auth.authMode);
const isAccessAllowed = authStrategies.some((strategy) => strategy === req.auth.authMode);
if (!isAccessAllowed) {
throw new UnauthorizedError({ name: `${req.url} Unauthorized Access` });
}
// New optional option. There are some routes which do not require an organization ID to be present on the request.
// An example of this is the /v1 auth routes.
if (req.auth.authMode === AuthMode.JWT && options.requireOrg === true && !req.permission.orgId) {
throw new UnauthorizedError({ name: `${req.url} Unauthorized Access, no organization found in request` });
}
done();
};
@@ -0,0 +1,12 @@
import fp from "fastify-plugin";
import { getConfig } from "@app/lib/config/env";
export const maintenanceMode = fp(async (fastify) => {
fastify.addHook("onRequest", async (req) => {
const serverEnvs = getConfig();
if (req.url !== "/api/v1/auth/checkAuth" && req.method !== "GET" && serverEnvs.MAINTENANCE_MODE) {
throw new Error("Infisical is in maintenance mode. Please try again later.");
}
});
});
@@ -4,6 +4,7 @@ import SmeeClient from "smee-client";
import { getConfig } from "@app/lib/config/env";
import { logger } from "@app/lib/logger";
import { writeLimit } from "@app/server/config/rateLimiter";
export const registerSecretScannerGhApp = async (server: FastifyZodProvider) => {
const probotApp = (app: Probot) => {
@@ -49,6 +50,9 @@ export const registerSecretScannerGhApp = async (server: FastifyZodProvider) =>
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
handler: async (req, res) => {
const eventName = req.headers["x-github-event"];
const signatureSHA256 = req.headers["x-hub-signature-256"] as string;
+4 -10
View File
@@ -14,13 +14,13 @@ export const fastifySwagger = fp(async (fastify) => {
version: "0.0.1"
},
servers: [
{
url: "http://localhost:8080",
description: "Local server"
},
{
url: "https://app.infisical.com",
description: "Production server"
},
{
url: "http://localhost:8080",
description: "Local server"
}
],
components: {
@@ -30,12 +30,6 @@ export const fastifySwagger = fp(async (fastify) => {
scheme: "bearer",
bearerFormat: "JWT",
description: "An access token in Infisical"
},
apiKeyAuth: {
type: "apiKey",
in: "header",
name: "X-API-Key",
description: "An API Key in Infisical"
}
}
}
+129 -16
View File
@@ -5,12 +5,25 @@ import { registerV1EERoutes } from "@app/ee/routes/v1";
import { auditLogDALFactory } from "@app/ee/services/audit-log/audit-log-dal";
import { auditLogQueueServiceFactory } from "@app/ee/services/audit-log/audit-log-queue";
import { auditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
import { dynamicSecretDALFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-dal";
import { dynamicSecretServiceFactory } from "@app/ee/services/dynamic-secret/dynamic-secret-service";
import { buildDynamicSecretProviders } from "@app/ee/services/dynamic-secret/providers";
import { dynamicSecretLeaseDALFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-dal";
import { dynamicSecretLeaseQueueServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-queue";
import { dynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
import { groupDALFactory } from "@app/ee/services/group/group-dal";
import { groupServiceFactory } from "@app/ee/services/group/group-service";
import { userGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
import { identityProjectAdditionalPrivilegeDALFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-dal";
import { identityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service";
import { ldapConfigDALFactory } from "@app/ee/services/ldap-config/ldap-config-dal";
import { ldapConfigServiceFactory } from "@app/ee/services/ldap-config/ldap-config-service";
import { licenseDALFactory } from "@app/ee/services/license/license-dal";
import { licenseServiceFactory } from "@app/ee/services/license/license-service";
import { permissionDALFactory } from "@app/ee/services/permission/permission-dal";
import { permissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { projectUserAdditionalPrivilegeDALFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-dal";
import { projectUserAdditionalPrivilegeServiceFactory } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-service";
import { samlConfigDALFactory } from "@app/ee/services/saml-config/saml-config-dal";
import { samlConfigServiceFactory } from "@app/ee/services/saml-config/saml-config-service";
import { scimDALFactory } from "@app/ee/services/scim/scim-dal";
@@ -39,6 +52,7 @@ import { trustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-
import { TKeyStoreFactory } from "@app/keystore/keystore";
import { getConfig } from "@app/lib/config/env";
import { TQueueServiceFactory } from "@app/queue";
import { readLimit } from "@app/server/config/rateLimiter";
import { apiKeyDALFactory } from "@app/services/api-key/api-key-dal";
import { apiKeyServiceFactory } from "@app/services/api-key/api-key-service";
import { authDALFactory } from "@app/services/auth/auth-dal";
@@ -47,6 +61,9 @@ import { authPaswordServiceFactory } from "@app/services/auth/auth-password-serv
import { authSignupServiceFactory } from "@app/services/auth/auth-signup-service";
import { tokenDALFactory } from "@app/services/auth-token/auth-token-dal";
import { tokenServiceFactory } from "@app/services/auth-token/auth-token-service";
import { groupProjectDALFactory } from "@app/services/group-project/group-project-dal";
import { groupProjectMembershipRoleDALFactory } from "@app/services/group-project/group-project-membership-role-dal";
import { groupProjectServiceFactory } from "@app/services/group-project/group-project-service";
import { identityDALFactory } from "@app/services/identity/identity-dal";
import { identityOrgDALFactory } from "@app/services/identity/identity-org-dal";
import { identityServiceFactory } from "@app/services/identity/identity-service";
@@ -143,6 +160,7 @@ export const registerRoutes = async (
const projectDAL = projectDALFactory(db);
const projectMembershipDAL = projectMembershipDALFactory(db);
const projectUserAdditionalPrivilegeDAL = projectUserAdditionalPrivilegeDALFactory(db);
const projectUserMembershipRoleDAL = projectUserMembershipRoleDALFactory(db);
const projectRoleDAL = projectRoleDALFactory(db);
const projectEnvDAL = projectEnvDALFactory(db);
@@ -168,6 +186,7 @@ export const registerRoutes = async (
const identityOrgMembershipDAL = identityOrgDALFactory(db);
const identityProjectDAL = identityProjectDALFactory(db);
const identityProjectMembershipRoleDAL = identityProjectMembershipRoleDALFactory(db);
const identityProjectAdditionalPrivilegeDAL = identityProjectAdditionalPrivilegeDALFactory(db);
const identityUaDAL = identityUaDALFactory(db);
const identityUaClientSecretDAL = identityUaClientSecretDALFactory(db);
@@ -194,14 +213,21 @@ export const registerRoutes = async (
const gitAppInstallSessionDAL = gitAppInstallSessionDALFactory(db);
const gitAppOrgDAL = gitAppDALFactory(db);
const groupDAL = groupDALFactory(db);
const groupProjectDAL = groupProjectDALFactory(db);
const groupProjectMembershipRoleDAL = groupProjectMembershipRoleDALFactory(db);
const userGroupMembershipDAL = userGroupMembershipDALFactory(db);
const secretScanningDAL = secretScanningDALFactory(db);
const licenseDAL = licenseDALFactory(db);
const dynamicSecretDAL = dynamicSecretDALFactory(db);
const dynamicSecretLeaseDAL = dynamicSecretLeaseDALFactory(db);
const permissionService = permissionServiceFactory({
permissionDAL,
orgRoleDAL,
projectRoleDAL,
serviceTokenDAL
serviceTokenDAL,
projectDAL
});
const licenseService = licenseServiceFactory({ permissionService, orgDAL, licenseDAL, keyStore });
const trustedIpService = trustedIpServiceFactory({
@@ -233,6 +259,29 @@ export const registerRoutes = async (
samlConfigDAL,
licenseService
});
const groupService = groupServiceFactory({
userDAL,
groupDAL,
groupProjectDAL,
orgDAL,
userGroupMembershipDAL,
projectDAL,
projectBotDAL,
projectKeyDAL,
permissionService,
licenseService
});
const groupProjectService = groupProjectServiceFactory({
groupDAL,
groupProjectDAL,
groupProjectMembershipRoleDAL,
userGroupMembershipDAL,
projectDAL,
projectKeyDAL,
projectBotDAL,
projectRoleDAL,
permissionService
});
const scimService = scimServiceFactory({
licenseService,
scimDAL,
@@ -240,6 +289,7 @@ export const registerRoutes = async (
orgDAL,
projectDAL,
projectMembershipDAL,
groupDAL,
permissionService,
smtpService
});
@@ -266,7 +316,7 @@ export const registerRoutes = async (
const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL });
const userService = userServiceFactory({ userDAL });
const loginService = authLoginServiceFactory({ userDAL, smtpService, tokenService });
const loginService = authLoginServiceFactory({ userDAL, smtpService, tokenService, orgDAL, tokenDAL: authTokenDAL });
const passwordService = authPaswordServiceFactory({
tokenService,
smtpService,
@@ -286,6 +336,7 @@ export const registerRoutes = async (
projectKeyDAL,
smtpService,
userDAL,
groupDAL,
orgBotDAL
});
const signupService = authSignupServiceFactory({
@@ -331,11 +382,17 @@ export const registerRoutes = async (
projectBotDAL,
orgDAL,
userDAL,
userGroupMembershipDAL,
smtpService,
projectKeyDAL,
projectRoleDAL,
licenseService
});
const projectUserAdditionalPrivilegeService = projectUserAdditionalPrivilegeServiceFactory({
permissionService,
projectMembershipDAL,
projectUserAdditionalPrivilegeDAL
});
const projectKeyService = projectKeyServiceFactory({
permissionService,
projectKeyDAL,
@@ -372,12 +429,14 @@ export const registerRoutes = async (
projectKeyDAL,
userDAL,
projectEnvDAL,
orgDAL,
orgService,
projectMembershipDAL,
folderDAL,
licenseService,
projectUserMembershipRoleDAL,
identityProjectMembershipRoleDAL
identityProjectMembershipRoleDAL,
keyStore
});
const projectEnvService = projectEnvServiceFactory({
@@ -388,7 +447,12 @@ export const registerRoutes = async (
folderDAL
});
const projectRoleService = projectRoleServiceFactory({ permissionService, projectRoleDAL });
const projectRoleService = projectRoleServiceFactory({
permissionService,
projectRoleDAL,
projectUserMembershipRoleDAL,
identityProjectMembershipRoleDAL
});
const snapshotService = secretSnapshotServiceFactory({
permissionService,
@@ -417,14 +481,6 @@ export const registerRoutes = async (
projectEnvDAL,
snapshotService
});
const secretImportService = secretImportServiceFactory({
projectEnvDAL,
folderDAL,
permissionService,
secretImportDAL,
projectDAL,
secretDAL
});
const integrationAuthService = integrationAuthServiceFactory({
integrationAuthDAL,
integrationDAL,
@@ -452,6 +508,15 @@ export const registerRoutes = async (
secretTagDAL,
secretVersionTagDAL
});
const secretImportService = secretImportServiceFactory({
projectEnvDAL,
folderDAL,
permissionService,
secretImportDAL,
projectDAL,
secretDAL,
secretQueueService
});
const secretBlindIndexService = secretBlindIndexServiceFactory({
permissionService,
secretDAL,
@@ -469,6 +534,7 @@ export const registerRoutes = async (
snapshotService,
secretQueueService,
secretImportDAL,
projectEnvDAL,
projectBotService
});
const sarService = secretApprovalRequestServiceFactory({
@@ -517,7 +583,8 @@ export const registerRoutes = async (
projectEnvDAL,
serviceTokenDAL,
userDAL,
permissionService
permissionService,
projectDAL
});
const identityService = identityServiceFactory({
@@ -525,7 +592,10 @@ export const registerRoutes = async (
identityDAL,
identityOrgMembershipDAL
});
const identityAccessTokenService = identityAccessTokenServiceFactory({ identityAccessTokenDAL });
const identityAccessTokenService = identityAccessTokenServiceFactory({
identityAccessTokenDAL,
identityOrgMembershipDAL
});
const identityProjectService = identityProjectServiceFactory({
permissionService,
projectDAL,
@@ -534,6 +604,12 @@ export const registerRoutes = async (
identityProjectMembershipRoleDAL,
projectRoleDAL
});
const identityProjectAdditionalPrivilegeService = identityProjectAdditionalPrivilegeServiceFactory({
projectDAL,
identityProjectAdditionalPrivilegeDAL,
permissionService,
identityProjectDAL
});
const identityUaService = identityUaServiceFactory({
identityOrgMembershipDAL,
permissionService,
@@ -544,6 +620,34 @@ export const registerRoutes = async (
licenseService
});
const dynamicSecretProviders = buildDynamicSecretProviders();
const dynamicSecretQueueService = dynamicSecretLeaseQueueServiceFactory({
queueService,
dynamicSecretLeaseDAL,
dynamicSecretProviders,
dynamicSecretDAL
});
const dynamicSecretService = dynamicSecretServiceFactory({
projectDAL,
dynamicSecretQueueService,
dynamicSecretDAL,
dynamicSecretLeaseDAL,
dynamicSecretProviders,
folderDAL,
permissionService,
licenseService
});
const dynamicSecretLeaseService = dynamicSecretLeaseServiceFactory({
projectDAL,
permissionService,
dynamicSecretQueueService,
dynamicSecretDAL,
dynamicSecretLeaseDAL,
dynamicSecretProviders,
folderDAL,
licenseService
});
await superAdminService.initServerCfg();
//
// setup the communication with license key server
@@ -558,6 +662,8 @@ export const registerRoutes = async (
password: passwordService,
signup: signupService,
user: userService,
group: groupService,
groupProject: groupProjectService,
permission: permissionService,
org: orgService,
orgRole: orgRoleService,
@@ -585,6 +691,8 @@ export const registerRoutes = async (
secretApprovalPolicy: sapService,
secretApprovalRequest: sarService,
secretRotation: secretRotationService,
dynamicSecret: dynamicSecretService,
dynamicSecretLease: dynamicSecretLeaseService,
snapshot: snapshotService,
saml: samlService,
ldap: ldapService,
@@ -594,7 +702,9 @@ export const registerRoutes = async (
trustedIp: trustedIpService,
scim: scimService,
secretBlindIndex: secretBlindIndexService,
telemetry: telemetryService
telemetry: telemetryService,
projectUserAdditionalPrivilege: projectUserAdditionalPrivilegeService,
identityProjectAdditionalPrivilege: identityProjectAdditionalPrivilegeService
});
server.decorate<FastifyZodProvider["store"]>("store", {
@@ -606,8 +716,11 @@ export const registerRoutes = async (
await server.register(injectAuditLogInfo);
server.route({
url: "/api/status",
method: "GET",
url: "/api/status",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.object({
+14 -1
View File
@@ -1,6 +1,11 @@
import { z } from "zod";
import { IntegrationAuthsSchema, SecretApprovalPoliciesSchema, UsersSchema } from "@app/db/schemas";
import {
DynamicSecretsSchema,
IntegrationAuthsSchema,
SecretApprovalPoliciesSchema,
UsersSchema
} from "@app/db/schemas";
// sometimes the return data must be santizied to avoid leaking important values
// always prefer pick over omit in zod
@@ -56,3 +61,11 @@ export const secretRawSchema = z.object({
secretValue: z.string(),
secretComment: z.string().optional()
});
export const SanitizedDynamicSecretSchema = DynamicSecretsSchema.omit({
inputIV: true,
inputTag: true,
inputCiphertext: true,
keyEncoding: true,
algorithm: true
});
+18 -5
View File
@@ -3,6 +3,7 @@ import { z } from "zod";
import { OrganizationsSchema, SuperAdminSchema, UsersSchema } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { UnauthorizedError } from "@app/lib/errors";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifySuperAdmin } from "@app/server/plugins/auth/superAdmin";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -11,24 +12,33 @@ import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
export const registerAdminRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/config",
method: "GET",
url: "/config",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.object({
config: SuperAdminSchema.omit({ createdAt: true, updatedAt: true })
config: SuperAdminSchema.omit({ createdAt: true, updatedAt: true }).merge(
z.object({ isMigrationModeOn: z.boolean() })
)
})
}
},
handler: async () => {
const config = await getServerCfg();
return { config };
const serverEnvs = getConfig();
return { config: { ...config, isMigrationModeOn: serverEnvs.MAINTENANCE_MODE } };
}
});
server.route({
url: "/config",
method: "PATCH",
url: "/config",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
allowSignUp: z.boolean().optional(),
@@ -52,8 +62,11 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/signup",
method: "POST",
url: "/signup",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
email: z.string().email().trim(),
+11 -4
View File
@@ -3,7 +3,7 @@ import { z } from "zod";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
import { authRateLimit } from "@app/server/config/rateLimiter";
import { authRateLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode, AuthModeRefreshJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
@@ -21,7 +21,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT], { requireOrg: false }),
handler: async (req, res) => {
const appCfg = getConfig();
if (req.auth.authMode === AuthMode.JWT) {
@@ -38,8 +38,11 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
});
server.route({
url: "/checkAuth",
method: "POST",
url: "/checkAuth",
config: {
rateLimit: writeLimit
},
schema: {
response: {
200: z.object({
@@ -52,8 +55,11 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
});
server.route({
url: "/token",
method: "POST",
url: "/token",
config: {
rateLimit: writeLimit
},
schema: {
response: {
200: z.object({
@@ -85,6 +91,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
const token = jwt.sign(
{
authMethod: decodedToken.authMethod,
authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: decodedToken.userId,
tokenVersionId: tokenVersion.id,
+11 -2
View File
@@ -1,13 +1,17 @@
import { z } from "zod";
import { ProjectBotsSchema } from "@app/db/schemas";
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";
export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:projectId",
method: "GET",
url: "/:projectId",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
@@ -30,6 +34,7 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
projectId: req.params.projectId
});
return { bot };
@@ -37,8 +42,11 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:botId/active",
method: "PATCH",
url: "/:botId/active",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
isActive: z.boolean(),
@@ -70,6 +78,7 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
botId: req.params.botId,
botKey: req.body.botKey,
isActive: req.body.isActive
@@ -1,13 +1,19 @@
import { z } from "zod";
import { UNIVERSAL_AUTH } from "@app/lib/api-docs";
import { writeLimit } from "@app/server/config/rateLimiter";
export const registerIdentityAccessTokenRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/token/renew",
method: "POST",
config: {
rateLimit: writeLimit
},
schema: {
description: "Renew access token",
body: z.object({
accessToken: z.string().trim()
accessToken: z.string().trim().describe(UNIVERSAL_AUTH.RENEW_ACCESS_TOKEN.accessToken)
}),
response: {
200: z.object({
@@ -2,6 +2,8 @@ import { z } from "zod";
import { IdentitiesSchema, OrgMembershipRole } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { IDENTITIES } from "@app/lib/api-docs";
import { creationLimit, writeLimit } from "@app/server/config/rateLimiter";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -11,6 +13,9 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/",
config: {
rateLimit: creationLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Create identity",
@@ -20,9 +25,9 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
}
],
body: z.object({
name: z.string().trim(),
organizationId: z.string().trim(),
role: z.string().trim().min(1).default(OrgMembershipRole.NoAccess)
name: z.string().trim().describe(IDENTITIES.CREATE.name),
organizationId: z.string().trim().describe(IDENTITIES.CREATE.organizationId),
role: z.string().trim().min(1).default(OrgMembershipRole.NoAccess).describe(IDENTITIES.CREATE.role)
}),
response: {
200: z.object({
@@ -34,6 +39,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.createIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
orgId: req.body.organizationId
@@ -69,6 +75,9 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
server.route({
method: "PATCH",
url: "/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Update identity",
@@ -78,11 +87,11 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string()
identityId: z.string().describe(IDENTITIES.UPDATE.identityId)
}),
body: z.object({
name: z.string().trim().optional(),
role: z.string().trim().min(1).optional()
name: z.string().trim().optional().describe(IDENTITIES.UPDATE.name),
role: z.string().trim().min(1).optional().describe(IDENTITIES.UPDATE.role)
}),
response: {
200: z.object({
@@ -94,6 +103,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.updateIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.identityId,
...req.body
@@ -118,6 +128,9 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Delete identity",
@@ -127,7 +140,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string()
identityId: z.string().describe(IDENTITIES.DELETE.identityId)
}),
response: {
200: z.object({
@@ -139,6 +152,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.deleteIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.identityId
});
+74 -28
View File
@@ -2,6 +2,8 @@ import { z } from "zod";
import { IdentityUaClientSecretsSchema, IdentityUniversalAuthsSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { UNIVERSAL_AUTH } 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 { TIdentityTrustedIp } from "@app/services/identity/identity-types";
@@ -21,13 +23,16 @@ export const sanitizedClientSecretSchema = IdentityUaClientSecretsSchema.pick({
export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/universal-auth/login",
method: "POST",
url: "/universal-auth/login",
config: {
rateLimit: writeLimit
},
schema: {
description: "Login with Universal Auth",
body: z.object({
clientId: z.string().trim(),
clientSecret: z.string().trim()
clientId: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientId),
clientSecret: z.string().trim().describe(UNIVERSAL_AUTH.LOGIN.clientSecret)
}),
response: {
200: z.object({
@@ -65,8 +70,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/universal-auth/identities/:identityId",
method: "POST",
url: "/universal-auth/identities/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Attach Universal Auth configuration onto identity",
@@ -76,7 +84,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string().trim()
identityId: z.string().trim().describe(UNIVERSAL_AUTH.ATTACH.identityId)
}),
body: z.object({
clientSecretTrustedIps: z
@@ -85,14 +93,16 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
})
.array()
.min(1)
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]),
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }])
.describe(UNIVERSAL_AUTH.ATTACH.clientSecretTrustedIps),
accessTokenTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }]),
.default([{ ipAddress: "0.0.0.0/0" }, { ipAddress: "::/0" }])
.describe(UNIVERSAL_AUTH.ATTACH.accessTokenTrustedIps),
accessTokenTTL: z
.number()
.int()
@@ -100,15 +110,22 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
.refine((value) => value !== 0, {
message: "accessTokenTTL must have a non zero number"
})
.default(2592000),
.default(2592000)
.describe(UNIVERSAL_AUTH.ATTACH.accessTokenTTL), // 30 days
accessTokenMaxTTL: z
.number()
.int()
.refine((value) => value !== 0, {
message: "accessTokenMaxTTL must have a non zero number"
})
.default(2592000), // 30 days
accessTokenNumUsesLimit: z.number().int().min(0).default(0)
.default(2592000)
.describe(UNIVERSAL_AUTH.ATTACH.accessTokenMaxTTL), // 30 days
accessTokenNumUsesLimit: z
.number()
.int()
.min(0)
.default(0)
.describe(UNIVERSAL_AUTH.ATTACH.accessTokenNumUsesLimit)
}),
response: {
200: z.object({
@@ -121,6 +138,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
...req.body,
identityId: req.params.identityId
});
@@ -145,8 +163,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/universal-auth/identities/:identityId",
method: "PATCH",
url: "/universal-auth/identities/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Update Universal Auth configuration on identity",
@@ -156,7 +177,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string()
identityId: z.string().describe(UNIVERSAL_AUTH.UPDATE.identityId)
}),
body: z.object({
clientSecretTrustedIps: z
@@ -165,16 +186,23 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
})
.array()
.min(1)
.optional(),
.optional()
.describe(UNIVERSAL_AUTH.UPDATE.clientSecretTrustedIps),
accessTokenTrustedIps: z
.object({
ipAddress: z.string().trim()
})
.array()
.min(1)
.optional(),
accessTokenTTL: z.number().int().min(0).optional(),
accessTokenNumUsesLimit: z.number().int().min(0).optional(),
.optional()
.describe(UNIVERSAL_AUTH.UPDATE.accessTokenTrustedIps),
accessTokenTTL: z.number().int().min(0).optional().describe(UNIVERSAL_AUTH.UPDATE.accessTokenTTL),
accessTokenNumUsesLimit: z
.number()
.int()
.min(0)
.optional()
.describe(UNIVERSAL_AUTH.UPDATE.accessTokenNumUsesLimit),
accessTokenMaxTTL: z
.number()
.int()
@@ -182,6 +210,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
message: "accessTokenMaxTTL must have a non zero number"
})
.optional()
.describe(UNIVERSAL_AUTH.UPDATE.accessTokenMaxTTL)
}),
response: {
200: z.object({
@@ -194,6 +223,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
...req.body,
identityId: req.params.identityId
});
@@ -219,8 +249,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/universal-auth/identities/:identityId",
method: "GET",
url: "/universal-auth/identities/:identityId",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Retrieve Universal Auth configuration on identity",
@@ -230,7 +263,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string()
identityId: z.string().describe(UNIVERSAL_AUTH.RETRIEVE.identityId)
}),
response: {
200: z.object({
@@ -242,6 +275,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const identityUniversalAuth = await server.services.identityUa.getIdentityUa({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId
});
@@ -262,8 +296,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/universal-auth/identities/:identityId/client-secrets",
method: "POST",
url: "/universal-auth/identities/:identityId/client-secrets",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Create Universal Auth Client Secret for identity",
@@ -273,12 +310,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string()
identityId: z.string().describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.identityId)
}),
body: z.object({
description: z.string().trim().default(""),
numUsesLimit: z.number().min(0).default(0),
ttl: z.number().min(0).default(0)
description: z.string().trim().default("").describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.description),
numUsesLimit: z.number().min(0).default(0).describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.numUsesLimit),
ttl: z.number().min(0).default(0).describe(UNIVERSAL_AUTH.CREATE_CLIENT_SECRET.ttl)
}),
response: {
200: z.object({
@@ -291,6 +328,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
...req.body
@@ -313,8 +351,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/universal-auth/identities/:identityId/client-secrets",
method: "GET",
url: "/universal-auth/identities/:identityId/client-secrets",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "List Universal Auth Client Secrets for identity",
@@ -324,7 +365,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string()
identityId: z.string().describe(UNIVERSAL_AUTH.LIST_CLIENT_SECRETS.identityId)
}),
response: {
200: z.object({
@@ -336,6 +377,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUaClientSecrets({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId
});
@@ -355,8 +397,11 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/universal-auth/identities/:identityId/client-secrets/:clientSecretId/revoke",
method: "POST",
url: "/universal-auth/identities/:identityId/client-secrets/:clientSecretId/revoke",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Revoke Universal Auth Client Secrets for identity",
@@ -366,8 +411,8 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
identityId: z.string(),
clientSecretId: z.string()
identityId: z.string().describe(UNIVERSAL_AUTH.REVOKE_CLIENT_SECRET.identityId),
clientSecretId: z.string().describe(UNIVERSAL_AUTH.REVOKE_CLIENT_SECRET.clientSecretId)
}),
response: {
200: z.object({
@@ -379,6 +424,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const clientSecretData = await server.services.identityUa.revokeUaClientSecret({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
clientSecretId: req.params.clientSecretId
@@ -1,6 +1,8 @@
import { z } from "zod";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { INTEGRATION_AUTH } 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";
@@ -8,10 +10,19 @@ import { integrationAuthPubSchema } from "../sanitizedSchemas";
export const registerIntegrationAuthRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/integration-options",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/integration-options",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "List of integrations available.",
security: [
{
bearerAuth: []
}
],
response: {
200: z.object({
integrationOptions: z
@@ -36,12 +47,21 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId",
method: "GET",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/:integrationAuthId",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Get details of an integration authorization by auth object id.",
security: [
{
bearerAuth: []
}
],
params: z.object({
integrationAuthId: z.string().trim()
integrationAuthId: z.string().trim().describe(INTEGRATION_AUTH.GET.integrationAuthId)
}),
response: {
200: z.object({
@@ -53,6 +73,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.getIntegrationAuth({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
@@ -61,13 +82,22 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/",
method: "DELETE",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Remove all integration's auth object from the project.",
security: [
{
bearerAuth: []
}
],
querystring: z.object({
integration: z.string().trim(),
projectId: z.string().trim()
integration: z.string().trim().describe(INTEGRATION_AUTH.DELETE.integration),
projectId: z.string().trim().describe(INTEGRATION_AUTH.DELETE.projectId)
}),
response: {
200: z.object({
@@ -80,6 +110,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
integration: req.query.integration,
projectId: req.query.projectId
});
@@ -100,12 +131,21 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId",
method: "DELETE",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/:integrationAuthId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Remove an integration auth object by object id.",
security: [
{
bearerAuth: []
}
],
params: z.object({
integrationAuthId: z.string().trim()
integrationAuthId: z.string().trim().describe(INTEGRATION_AUTH.DELETE_BY_ID.integrationAuthId)
}),
response: {
200: z.object({
@@ -117,6 +157,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.deleteIntegrationAuthById({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
@@ -137,8 +178,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/oauth-token",
method: "POST",
url: "/oauth-token",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
@@ -157,6 +201,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.oauthExchange({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId,
...req.body
@@ -177,18 +222,27 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/access-token",
method: "POST",
onRequest: verifyAuth([AuthMode.JWT]),
url: "/access-token",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Create the integration authentication object required for syncing secrets.",
security: [
{
bearerAuth: []
}
],
body: z.object({
workspaceId: z.string().trim(),
integration: z.string().trim(),
accessId: z.string().trim().optional(),
accessToken: z.string().trim().optional(),
url: z.string().url().trim().optional(),
namespace: z.string().trim().optional(),
refreshToken: z.string().trim().optional()
workspaceId: z.string().trim().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.workspaceId),
integration: z.string().trim().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.integration),
accessId: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.accessId),
accessToken: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.accessToken),
url: z.string().url().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.url),
namespace: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.namespace),
refreshToken: z.string().trim().optional().describe(INTEGRATION_AUTH.CREATE_ACCESS_TOKEN.refreshToken)
}),
response: {
200: z.object({
@@ -200,6 +254,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.saveIntegrationToken({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId,
...req.body
@@ -220,8 +275,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/apps",
method: "GET",
url: "/:integrationAuthId/apps",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -247,6 +305,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const apps = await server.services.integrationAuth.getIntegrationApps({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
...req.query
@@ -256,8 +315,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/teams",
method: "GET",
url: "/:integrationAuthId/teams",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -278,6 +340,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const teams = await server.services.integrationAuth.getIntegrationAuthTeams({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
@@ -286,8 +349,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/vercel/branches",
method: "GET",
url: "/:integrationAuthId/vercel/branches",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -306,6 +372,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const branches = await server.services.integrationAuth.getVercelBranches({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
@@ -315,8 +382,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/checkly/groups",
method: "GET",
url: "/:integrationAuthId/checkly/groups",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -335,6 +405,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const groups = await server.services.integrationAuth.getChecklyGroups({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
accountId: req.query.accountId
@@ -344,8 +415,79 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/qovery/orgs",
method: "GET",
url: "/:integrationAuthId/github/orgs",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
integrationAuthId: z.string().trim()
}),
response: {
200: z.object({
orgs: z.object({ name: z.string(), orgId: z.string() }).array()
})
}
},
handler: async (req) => {
const orgs = await server.services.integrationAuth.getGithubOrgs({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
id: req.params.integrationAuthId
});
if (!orgs) throw new Error("No organization found.");
return { orgs };
}
});
server.route({
method: "GET",
url: "/:integrationAuthId/github/envs",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
integrationAuthId: z.string().trim()
}),
querystring: z.object({
repoOwner: z.string().trim(),
repoName: z.string().trim()
}),
response: {
200: z.object({
envs: z.object({ name: z.string(), envId: z.string() }).array()
})
}
},
handler: async (req) => {
const envs = await server.services.integrationAuth.getGithubEnvs({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
actorAuthMethod: req.permission.authMethod,
repoName: req.query.repoName,
repoOwner: req.query.repoOwner
});
if (!envs) throw new Error("No organization found.");
return { envs };
}
});
server.route({
method: "GET",
url: "/:integrationAuthId/qovery/orgs",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -361,6 +503,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const orgs = await server.services.integrationAuth.getQoveryOrgs({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
@@ -369,8 +512,44 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/qovery/projects",
method: "GET",
url: "/:integrationAuthId/aws-secrets-manager/kms-keys",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
integrationAuthId: z.string().trim()
}),
querystring: z.object({
region: z.string().trim()
}),
response: {
200: z.object({
kmsKeys: z.object({ id: z.string(), alias: z.string() }).array()
})
}
},
handler: async (req) => {
const kmsKeys = await server.services.integrationAuth.getAwsKmsKeys({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
region: req.query.region
});
return { kmsKeys };
}
});
server.route({
method: "GET",
url: "/:integrationAuthId/qovery/projects",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -389,6 +568,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const projects = await server.services.integrationAuth.getQoveryProjects({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
orgId: req.query.orgId
@@ -398,8 +578,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/qovery/environments",
method: "GET",
url: "/:integrationAuthId/qovery/environments",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -418,6 +601,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const environments = await server.services.integrationAuth.getQoveryEnvs({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
projectId: req.query.projectId
@@ -427,8 +611,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/qovery/apps",
method: "GET",
url: "/:integrationAuthId/qovery/apps",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -447,6 +634,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const apps = await server.services.integrationAuth.getQoveryApps({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
environmentId: req.query.environmentId
@@ -456,8 +644,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/qovery/containers",
method: "GET",
url: "/:integrationAuthId/qovery/containers",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -476,6 +667,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const containers = await server.services.integrationAuth.getQoveryContainers({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
environmentId: req.query.environmentId
@@ -485,8 +677,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/qovery/jobs",
method: "GET",
url: "/:integrationAuthId/qovery/jobs",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -505,6 +700,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const jobs = await server.services.integrationAuth.getQoveryJobs({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
environmentId: req.query.environmentId
@@ -514,8 +710,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/heroku/pipelines",
method: "GET",
url: "/:integrationAuthId/heroku/pipelines",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -537,6 +736,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const pipelines = await server.services.integrationAuth.getHerokuPipelines({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
@@ -545,8 +745,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/railway/environments",
method: "GET",
url: "/:integrationAuthId/railway/environments",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -565,6 +768,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const environments = await server.services.integrationAuth.getRailwayEnvironments({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
@@ -574,8 +778,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/railway/services",
method: "GET",
url: "/:integrationAuthId/railway/services",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -594,6 +801,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const services = await server.services.integrationAuth.getRailwayServices({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
@@ -603,8 +811,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/bitbucket/workspaces",
method: "GET",
url: "/:integrationAuthId/bitbucket/workspaces",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -630,6 +841,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const workspaces = await server.services.integrationAuth.getBitbucketWorkspaces({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
@@ -638,8 +850,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/northflank/secret-groups",
method: "GET",
url: "/:integrationAuthId/northflank/secret-groups",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -663,6 +878,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const secretGroups = await server.services.integrationAuth.getNorthFlankSecretGroups({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
@@ -672,8 +888,11 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:integrationAuthId/teamcity/build-configs",
method: "GET",
url: "/:integrationAuthId/teamcity/build-configs",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -697,6 +916,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const buildConfigs = await server.services.integrationAuth.getTeamcityBuildConfigs({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
@@ -2,7 +2,9 @@ import { z } from "zod";
import { IntegrationsSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { INTEGRATION } from "@app/lib/api-docs";
import { removeTrailingSlash, shake } from "@app/lib/fn";
import { writeLimit } from "@app/server/config/rateLimiter";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -10,37 +12,63 @@ import { PostHogEventTypes, TIntegrationCreatedEvent } from "@app/services/telem
export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
schema: {
description: "Create an integration to sync secrets.",
security: [
{
bearerAuth: []
}
],
body: z.object({
integrationAuthId: z.string().trim(),
app: z.string().trim().optional(),
isActive: z.boolean(),
appId: z.string().trim().optional(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
sourceEnvironment: z.string().trim(),
targetEnvironment: z.string().trim().optional(),
targetEnvironmentId: z.string().trim().optional(),
targetService: z.string().trim().optional(),
targetServiceId: z.string().trim().optional(),
owner: z.string().trim().optional(),
path: z.string().trim().optional(),
region: z.string().trim().optional(),
scope: z.string().trim().optional(),
integrationAuthId: z.string().trim().describe(INTEGRATION.CREATE.integrationAuthId),
app: z.string().trim().optional().describe(INTEGRATION.CREATE.app),
isActive: z.boolean().describe(INTEGRATION.CREATE.isActive).default(true),
appId: z.string().trim().optional().describe(INTEGRATION.CREATE.appId),
secretPath: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(INTEGRATION.CREATE.secretPath),
sourceEnvironment: z.string().trim().describe(INTEGRATION.CREATE.sourceEnvironment),
targetEnvironment: z.string().trim().optional().describe(INTEGRATION.CREATE.targetEnvironment),
targetEnvironmentId: z.string().trim().optional().describe(INTEGRATION.CREATE.targetEnvironmentId),
targetService: z.string().trim().optional().describe(INTEGRATION.CREATE.targetService),
targetServiceId: z.string().trim().optional().describe(INTEGRATION.CREATE.targetServiceId),
owner: z.string().trim().optional().describe(INTEGRATION.CREATE.owner),
path: z.string().trim().optional().describe(INTEGRATION.CREATE.path),
region: z.string().trim().optional().describe(INTEGRATION.CREATE.region),
scope: z.string().trim().optional().describe(INTEGRATION.CREATE.scope),
metadata: z
.object({
secretPrefix: z.string().optional(),
secretSuffix: z.string().optional(),
initialSyncBehavior: z.string().optional(),
secretPrefix: z.string().optional().describe(INTEGRATION.CREATE.metadata.secretPrefix),
secretSuffix: z.string().optional().describe(INTEGRATION.CREATE.metadata.secretSuffix),
initialSyncBehavior: z.string().optional().describe(INTEGRATION.CREATE.metadata.initialSyncBehavoir),
shouldAutoRedeploy: z.boolean().optional().describe(INTEGRATION.CREATE.metadata.shouldAutoRedeploy),
secretGCPLabel: z
.object({
labelName: z.string(),
labelValue: z.string()
})
.optional()
.describe(INTEGRATION.CREATE.metadata.secretGCPLabel),
secretAWSTag: z
.array(
z.object({
key: z.string(),
value: z.string()
})
)
.optional()
.describe(INTEGRATION.CREATE.metadata.secretAWSTag),
kmsKeyId: z.string().optional().describe(INTEGRATION.CREATE.metadata.kmsKeyId)
})
.optional()
.default({})
}),
response: {
200: z.object({
@@ -48,11 +76,12 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { integration, integrationAuth } = await server.services.integration.createIntegration({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body
});
@@ -97,20 +126,34 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:integrationId",
method: "PATCH",
url: "/:integrationId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Update an integration by integration id",
security: [
{
bearerAuth: []
}
],
params: z.object({
integrationId: z.string().trim()
integrationId: z.string().trim().describe(INTEGRATION.UPDATE.integrationId)
}),
body: z.object({
app: z.string().trim(),
appId: z.string().trim(),
isActive: z.boolean(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
targetEnvironment: z.string().trim(),
owner: z.string().trim(),
environment: z.string().trim()
app: z.string().trim().describe(INTEGRATION.UPDATE.app),
appId: z.string().trim().describe(INTEGRATION.UPDATE.appId),
isActive: z.boolean().describe(INTEGRATION.UPDATE.isActive),
secretPath: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(INTEGRATION.UPDATE.secretPath),
targetEnvironment: z.string().trim().describe(INTEGRATION.UPDATE.targetEnvironment),
owner: z.string().trim().describe(INTEGRATION.UPDATE.owner),
environment: z.string().trim().describe(INTEGRATION.UPDATE.environment)
}),
response: {
200: z.object({
@@ -118,11 +161,12 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const integration = await server.services.integration.updateIntegration({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.integrationId,
...req.body
@@ -132,11 +176,20 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:integrationId",
method: "DELETE",
url: "/:integrationId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Remove an integration using the integration object ID",
security: [
{
bearerAuth: []
}
],
params: z.object({
integrationId: z.string().trim()
integrationId: z.string().trim().describe(INTEGRATION.DELETE.integrationId)
}),
response: {
200: z.object({
@@ -144,10 +197,11 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const integration = await server.services.integration.deleteIntegration({
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationId
@@ -1,6 +1,7 @@
import { z } from "zod";
import { UsersSchema } from "@app/db/schemas";
import { inviteUserRateLimit } from "@app/server/config/rateLimiter";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
@@ -9,6 +10,9 @@ import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/signup",
config: {
rateLimit: inviteUserRateLimit
},
method: "POST",
schema: {
body: z.object({
@@ -29,6 +33,7 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
orgId: req.body.organizationId,
userId: req.permission.id,
inviteeEmail: req.body.inviteeEmail,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
@@ -51,6 +56,9 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/verify",
method: "POST",
config: {
rateLimit: inviteUserRateLimit
},
schema: {
body: z.object({
email: z.string().trim().email(),
@@ -1,6 +1,15 @@
import { z } from "zod";
import { IncidentContactsSchema, OrganizationsSchema, OrgMembershipsSchema, UsersSchema } from "@app/db/schemas";
import {
GroupsSchema,
IncidentContactsSchema,
OrganizationsSchema,
OrgMembershipsSchema,
OrgRolesSchema,
UsersSchema
} from "@app/db/schemas";
import { ORGANIZATIONS } 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";
@@ -8,6 +17,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.object({
@@ -15,7 +27,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT], { requireOrg: false }),
handler: async (req) => {
const organizations = await server.services.org.findAllOrganizationOfUser(req.permission.id);
return { organizations };
@@ -25,6 +37,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:organizationId",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
organizationId: z.string().trim()
@@ -40,6 +55,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const organization = await server.services.org.findOrganizationById(
req.permission.id,
req.params.organizationId,
req.permission.authMethod,
req.permission.orgId
);
return { organization };
@@ -49,6 +65,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:organizationId/users",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
organizationId: z.string().trim()
@@ -76,6 +95,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const users = await server.services.org.findAllOrgMembers(
req.permission.id,
req.params.organizationId,
req.permission.authMethod,
req.permission.orgId
);
return { users };
@@ -85,6 +105,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "PATCH",
url: "/:organizationId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({ organizationId: z.string().trim() }),
body: z.object({
@@ -111,6 +134,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
orgId: req.params.organizationId,
data: req.body
});
@@ -125,6 +149,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:organizationId/incidentContactOrg",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({ organizationId: z.string().trim() }),
response: {
@@ -138,6 +165,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const incidentContactsOrg = await req.server.services.org.findIncidentContacts(
req.permission.id,
req.params.organizationId,
req.permission.authMethod,
req.permission.orgId
);
return { incidentContactsOrg };
@@ -147,6 +175,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/:organizationId/incidentContactOrg",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({ organizationId: z.string().trim() }),
body: z.object({ email: z.string().email().trim() }),
@@ -162,6 +193,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
req.permission.id,
req.params.organizationId,
req.body.email,
req.permission.authMethod,
req.permission.orgId
);
return { incidentContactsOrg };
@@ -171,6 +203,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/:organizationId/incidentContactOrg/:incidentContactId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({ organizationId: z.string().trim(), incidentContactId: z.string().trim() }),
response: {
@@ -185,9 +220,47 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
req.permission.id,
req.params.organizationId,
req.params.incidentContactId,
req.permission.authMethod,
req.permission.orgId
);
return { incidentContactsOrg };
}
});
server.route({
method: "GET",
url: "/:organizationId/groups",
schema: {
params: z.object({
organizationId: z.string().trim().describe(ORGANIZATIONS.LIST_GROUPS.organizationId)
}),
response: {
200: z.object({
groups: GroupsSchema.merge(
z.object({
customRole: OrgRolesSchema.pick({
id: true,
name: true,
slug: true,
permissions: true,
description: true
}).optional()
})
).array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const groups = await server.services.org.getOrgGroups({
actor: req.permission.type,
actorId: req.permission.id,
orgId: req.params.organizationId,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
return { groups };
}
});
};
@@ -2,7 +2,7 @@ import { z } from "zod";
import { BackupPrivateKeySchema, UsersSchema } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { passwordRateLimit } from "@app/server/config/rateLimiter";
import { authRateLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { validateSignUpAuthorization } from "@app/services/auth/auth-fns";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -12,7 +12,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
method: "POST",
url: "/srp1",
config: {
rateLimit: passwordRateLimit
rateLimit: authRateLimit
},
schema: {
body: z.object({
@@ -39,7 +39,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
method: "POST",
url: "/change-password",
config: {
rateLimit: passwordRateLimit
rateLimit: authRateLimit
},
schema: {
body: z.object({
@@ -78,7 +78,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
method: "POST",
url: "/email/password-reset",
config: {
rateLimit: passwordRateLimit
rateLimit: authRateLimit
},
schema: {
body: z.object({
@@ -103,7 +103,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
method: "POST",
url: "/email/password-reset-verify",
config: {
rateLimit: passwordRateLimit
rateLimit: authRateLimit
},
schema: {
body: z.object({
@@ -133,7 +133,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
method: "POST",
url: "/backup-private-key",
config: {
rateLimit: passwordRateLimit
rateLimit: authRateLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
@@ -168,7 +168,7 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
method: "GET",
url: "/backup-private-key",
config: {
rateLimit: passwordRateLimit
rateLimit: authRateLimit
},
schema: {
response: {
@@ -190,6 +190,9 @@ export const registerPasswordRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/password-reset",
config: {
rateLimit: authRateLimit
},
schema: {
body: z.object({
protectedKey: z.string().trim(),
@@ -3,32 +3,37 @@ import { z } from "zod";
import { ProjectEnvironmentsSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { ENVIRONMENTS } from "@app/lib/api-docs";
import { writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:workspaceId/environments",
method: "POST",
url: "/:workspaceId/environments",
config: {
rateLimit: writeLimit
},
schema: {
description: "Create environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(ENVIRONMENTS.CREATE.workspaceId)
}),
body: z.object({
name: z.string().trim(),
name: z.string().trim().describe(ENVIRONMENTS.CREATE.name),
slug: z
.string()
.trim()
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
})
.describe(ENVIRONMENTS.CREATE.slug)
}),
response: {
200: z.object({
@@ -44,6 +49,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
projectId: req.params.workspaceId,
...req.body
});
@@ -68,28 +74,33 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId/environments/:id",
method: "PATCH",
url: "/:workspaceId/environments/:id",
config: {
rateLimit: writeLimit
},
schema: {
description: "Update environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim(),
id: z.string().trim()
workspaceId: z.string().trim().describe(ENVIRONMENTS.UPDATE.workspaceId),
id: z.string().trim().describe(ENVIRONMENTS.UPDATE.id)
}),
body: z.object({
slug: z
.string()
.regex(/^[^./]*$/g)
.trim()
.optional(),
name: z.string().trim().optional(),
position: z.number().optional()
.optional()
.refine((v) => !v || slugify(v) === v, {
message: "Slug must be a valid slug"
})
.describe(ENVIRONMENTS.UPDATE.slug),
name: z.string().trim().optional().describe(ENVIRONMENTS.UPDATE.name),
position: z.number().optional().describe(ENVIRONMENTS.UPDATE.position)
}),
response: {
200: z.object({
@@ -104,6 +115,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const { environment, old } = await server.services.projectEnv.updateEnvironment({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
id: req.params.id,
@@ -135,19 +147,21 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId/environments/:id",
method: "DELETE",
url: "/:workspaceId/environments/:id",
config: {
rateLimit: writeLimit
},
schema: {
description: "Delete environment",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim(),
id: z.string().trim()
workspaceId: z.string().trim().describe(ENVIRONMENTS.DELETE.workspaceId),
id: z.string().trim().describe(ENVIRONMENTS.DELETE.id)
}),
response: {
200: z.object({
@@ -162,6 +176,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const environment = await server.services.projectEnv.deleteEnvironment({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
id: req.params.id
@@ -1,5 +1,6 @@
import { z } from "zod";
import { writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -7,6 +8,9 @@ export const registerProjectKeyRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:workspaceId/key",
method: "POST",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
workspaceId: z.string().trim()
@@ -30,6 +34,7 @@ export const registerProjectKeyRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
nonce: req.body.key.nonce,
receiverId: req.body.key.userId,
@@ -9,52 +9,53 @@ import {
UsersSchema
} from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { PROJECTS } 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 { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types";
export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:workspaceId/memberships",
method: "GET",
url: "/:workspaceId/memberships",
config: {
rateLimit: readLimit
},
schema: {
description: "Return project user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.GET_USER_MEMBERSHIPS.workspaceId)
}),
response: {
200: z.object({
memberships: ProjectMembershipsSchema.omit({ role: true })
.merge(
memberships: ProjectMembershipsSchema.extend({
user: UsersSchema.pick({
email: true,
firstName: true,
lastName: true,
id: true
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true })),
roles: z.array(
z.object({
user: UsersSchema.pick({
email: true,
firstName: true,
lastName: true,
id: true
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true })),
roles: z.array(
z.object({
id: z.string(),
role: z.string(),
customRoleId: z.string().optional().nullable(),
customRoleName: z.string().optional().nullable(),
customRoleSlug: z.string().optional().nullable(),
isTemporary: z.boolean(),
temporaryMode: z.string().optional().nullable(),
temporaryRange: z.string().nullable().optional(),
temporaryAccessStartTime: z.date().nullable().optional(),
temporaryAccessEndTime: z.date().nullable().optional()
})
)
id: z.string(),
role: z.string(),
customRoleId: z.string().optional().nullable(),
customRoleName: z.string().optional().nullable(),
customRoleSlug: z.string().optional().nullable(),
isTemporary: z.boolean(),
temporaryMode: z.string().optional().nullable(),
temporaryRange: z.string().nullable().optional(),
temporaryAccessStartTime: z.date().nullable().optional(),
temporaryAccessEndTime: z.date().nullable().optional()
})
)
})
.omit({ createdAt: true, updatedAt: true })
.array()
})
@@ -65,6 +66,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const memberships = await server.services.projectMembership.getProjectMemberships({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
@@ -73,8 +75,11 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
});
server.route({
url: "/:workspaceId/memberships",
method: "POST",
url: "/:workspaceId/memberships",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
workspaceId: z.string().trim()
@@ -101,6 +106,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const data = await server.services.projectMembership.addUsersToProject({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
members: req.body.members
@@ -123,19 +129,21 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
});
server.route({
url: "/:workspaceId/memberships/:membershipId",
method: "PATCH",
url: "/:workspaceId/memberships/:membershipId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Update project user membership",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim(),
membershipId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.UPDATE_USER_MEMBERSHIP.workspaceId),
membershipId: z.string().trim().describe(PROJECTS.UPDATE_USER_MEMBERSHIP.membershipId)
}),
body: z.object({
roles: z
@@ -155,7 +163,8 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
])
)
.min(1)
.refine((data) => data.some(({ isTemporary }) => !isTemporary), "At least long lived role is required")
.refine((data) => data.some(({ isTemporary }) => !isTemporary), "At least one long lived role is required")
.describe(PROJECTS.UPDATE_USER_MEMBERSHIP.roles)
}),
response: {
200: z.object({
@@ -168,6 +177,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const roles = await server.services.projectMembership.updateProjectMembership({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
membershipId: req.params.membershipId,
@@ -192,14 +202,16 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
});
server.route({
url: "/:workspaceId/memberships/:membershipId",
method: "DELETE",
url: "/:workspaceId/memberships/:membershipId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Delete project user membership",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
@@ -217,6 +229,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const membership = await server.services.projectMembership.deleteProjectMembership({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
membershipId: req.params.membershipId
+139 -79
View File
@@ -7,8 +7,11 @@ import {
UserEncryptionKeysSchema,
UsersSchema
} from "@app/db/schemas";
import { PROJECTS } 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 { ProjectFilterType } from "@app/services/project/project-types";
import { integrationAuthPubSchema } from "../sanitizedSchemas";
import { sanitizedServiceTokenSchema } from "../v2/service-token-router";
@@ -22,8 +25,11 @@ const projectWithEnv = ProjectsSchema.merge(
export const registerProjectRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:workspaceId/keys",
method: "GET",
url: "/:workspaceId/keys",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
workspaceId: z.string().trim()
@@ -44,6 +50,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const publicKeys = await server.services.projectKey.getProjectPublicKeys({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
@@ -52,40 +59,40 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId/users",
method: "GET",
url: "/:workspaceId/users",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
workspaceId: z.string().trim()
}),
response: {
200: z.object({
users: ProjectMembershipsSchema.omit({ role: true })
.merge(
users: ProjectMembershipsSchema.extend({
user: UsersSchema.pick({
email: true,
username: true,
firstName: true,
lastName: true,
id: true
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true })),
roles: z.array(
z.object({
user: UsersSchema.pick({
username: true,
email: true,
firstName: true,
lastName: true,
id: true
}).merge(UserEncryptionKeysSchema.pick({ publicKey: true })),
roles: z.array(
z.object({
id: z.string(),
role: z.string(),
customRoleId: z.string().optional().nullable(),
customRoleName: z.string().optional().nullable(),
customRoleSlug: z.string().optional().nullable(),
isTemporary: z.boolean(),
temporaryMode: z.string().optional().nullable(),
temporaryRange: z.string().nullable().optional(),
temporaryAccessStartTime: z.date().nullable().optional(),
temporaryAccessEndTime: z.date().nullable().optional()
})
)
id: z.string(),
role: z.string(),
customRoleId: z.string().optional().nullable(),
customRoleName: z.string().optional().nullable(),
customRoleSlug: z.string().optional().nullable(),
isTemporary: z.boolean(),
temporaryMode: z.string().optional().nullable(),
temporaryRange: z.string().nullable().optional(),
temporaryAccessStartTime: z.date().nullable().optional(),
temporaryAccessEndTime: z.date().nullable().optional()
})
)
})
.omit({ createdAt: true, updatedAt: true })
.array()
})
@@ -96,6 +103,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const users = await server.services.projectMembership.getProjectMemberships({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
projectId: req.params.workspaceId,
actorOrgId: req.permission.orgId
});
@@ -104,8 +112,11 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/",
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.object({
@@ -121,11 +132,20 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId",
method: "GET",
url: "/:workspaceId",
config: {
rateLimit: readLimit
},
schema: {
description: "Get project",
security: [
{
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.GET.workspaceId)
}),
response: {
200: z.object({
@@ -136,48 +156,34 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const workspace = await server.services.project.getAProject({
filter: {
type: ProjectFilterType.ID,
projectId: req.params.workspaceId
},
actorAuthMethod: req.permission.authMethod,
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
actorOrgId: req.permission.orgId
});
return { workspace };
}
});
server.route({
url: "/",
method: "POST",
schema: {
body: z.object({
workspaceName: z.string().trim(),
organizationId: z.string().trim()
}),
response: {
200: z.object({
workspace: projectWithEnv
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const workspace = await server.services.project.createProject({
actorId: req.permission.id,
actor: req.permission.type,
orgId: req.body.organizationId,
actorOrgId: req.permission.orgId,
workspaceName: req.body.workspaceName
});
return { workspace };
}
});
server.route({
url: "/:workspaceId",
method: "DELETE",
url: "/:workspaceId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Delete project",
security: [
{
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.DELETE.workspaceId)
}),
response: {
200: z.object({
@@ -188,10 +194,14 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const workspace = await server.services.project.deleteProject({
filter: {
type: ProjectFilterType.ID,
projectId: req.params.workspaceId
},
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
actorOrgId: req.permission.orgId
});
return { workspace };
}
@@ -200,6 +210,9 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:workspaceId/name",
method: "POST",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
workspaceId: z.string().trim()
@@ -219,6 +232,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.updateName({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
name: req.body.name
@@ -231,15 +245,29 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId",
method: "PATCH",
url: "/:workspaceId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Update project",
security: [
{
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.UPDATE.workspaceId)
}),
body: z.object({
name: z.string().trim().max(64, { message: "Name must be 64 or fewer characters" }).optional(),
autoCapitalization: z.boolean().optional()
name: z
.string()
.trim()
.max(64, { message: "Name must be 64 or fewer characters" })
.optional()
.describe(PROJECTS.UPDATE.name),
autoCapitalization: z.boolean().optional().describe(PROJECTS.UPDATE.autoCapitalization)
}),
response: {
200: z.object({
@@ -247,17 +275,21 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const workspace = await server.services.project.updateProject({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
filter: {
type: ProjectFilterType.ID,
projectId: req.params.workspaceId
},
update: {
name: req.body.name,
autoCapitalization: req.body.autoCapitalization
}
},
actorAuthMethod: req.permission.authMethod,
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
return {
workspace
@@ -266,8 +298,11 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId/auto-capitalization",
method: "POST",
url: "/:workspaceId/auto-capitalization",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
workspaceId: z.string().trim()
@@ -287,6 +322,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.toggleAutoCapitalization({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
autoCapitalization: req.body.autoCapitalization
@@ -299,11 +335,20 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId/integrations",
method: "GET",
url: "/:workspaceId/integrations",
config: {
rateLimit: readLimit
},
schema: {
description: "List integrations for a project.",
security: [
{
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION.workspaceId)
}),
response: {
200: z.object({
@@ -319,10 +364,11 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const integrations = await server.services.integration.listIntegrationByProject({
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
@@ -332,11 +378,20 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId/authorizations",
method: "GET",
url: "/:workspaceId/authorizations",
config: {
rateLimit: readLimit
},
schema: {
description: "List integration auth objects for a workspace.",
security: [
{
bearerAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.LIST_INTEGRATION_AUTHORIZATION.workspaceId)
}),
response: {
200: z.object({
@@ -344,10 +399,11 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const authorizations = await server.services.integrationAuth.listIntegrationAuthByProjectId({
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
@@ -357,8 +413,11 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:workspaceId/service-token-data",
method: "GET",
url: "/:workspaceId/service-token-data",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
workspaceId: z.string().trim()
@@ -373,6 +432,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
handler: async (req) => {
const serviceTokenData = await server.services.serviceToken.getProjectServiceTokens({
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
@@ -2,7 +2,9 @@ import { z } from "zod";
import { SecretFoldersSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { FOLDERS } from "@app/lib/api-docs";
import { removeTrailingSlash } from "@app/lib/fn";
import { readLimit, secretsLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -10,21 +12,23 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
server.route({
url: "/",
method: "POST",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Create folders",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
name: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
workspaceId: z.string().trim().describe(FOLDERS.CREATE.workspaceId),
environment: z.string().trim().describe(FOLDERS.CREATE.environment),
name: z.string().trim().describe(FOLDERS.CREATE.name),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.CREATE.path),
// backward compatiability with cli
directory: z.string().trim().default("/").transform(removeTrailingSlash)
directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.CREATE.directory)
}),
response: {
200: z.object({
@@ -38,6 +42,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folder = await server.services.folder.createFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
@@ -63,25 +68,27 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
server.route({
url: "/:folderId",
method: "PATCH",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Update folder",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
// old way this was name
folderId: z.string()
folderId: z.string().describe(FOLDERS.UPDATE.folderId)
}),
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
name: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
workspaceId: z.string().trim().describe(FOLDERS.UPDATE.workspaceId),
environment: z.string().trim().describe(FOLDERS.UPDATE.environment),
name: z.string().trim().describe(FOLDERS.UPDATE.name),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.UPDATE.path),
// backward compatiability with cli
directory: z.string().trim().default("/").transform(removeTrailingSlash)
directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.UPDATE.directory)
}),
response: {
200: z.object({
@@ -95,6 +102,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const { folder, old } = await server.services.folder.updateFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
@@ -119,26 +127,29 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
}
});
// TODO(daniel): Expose this route in api reference and write docs for it.
server.route({
url: "/:folderIdOrName",
method: "DELETE",
url: "/:folderIdOrName",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Delete a folder",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
folderIdOrName: z.string()
folderIdOrName: z.string().describe(FOLDERS.DELETE.folderIdOrName)
}),
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
workspaceId: z.string().trim().describe(FOLDERS.DELETE.workspaceId),
environment: z.string().trim().describe(FOLDERS.DELETE.environment),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.DELETE.path),
// keep this here as cli need directory
directory: z.string().trim().default("/").transform(removeTrailingSlash)
directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.DELETE.directory)
}),
response: {
200: z.object({
@@ -152,6 +163,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folder = await server.services.folder.deleteFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
@@ -176,22 +188,24 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/",
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
description: "Get folders",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
querystring: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
workspaceId: z.string().trim().describe(FOLDERS.LIST.workspaceId),
environment: z.string().trim().describe(FOLDERS.LIST.environment),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.LIST.path),
// backward compatiability with cli
directory: z.string().trim().default("/").transform(removeTrailingSlash)
directory: z.string().trim().default("/").transform(removeTrailingSlash).describe(FOLDERS.LIST.directory)
}),
response: {
200: z.object({
@@ -205,6 +219,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folders = await server.services.folder.getFolders({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId,
@@ -2,29 +2,33 @@ import { z } from "zod";
import { SecretImportsSchema, SecretsSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { SECRET_IMPORTS } from "@app/lib/api-docs";
import { removeTrailingSlash } from "@app/lib/fn";
import { readLimit, secretsLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
export const registerSecretImportRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "POST",
url: "/",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Create secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
workspaceId: z.string().trim().describe(SECRET_IMPORTS.CREATE.workspaceId),
environment: z.string().trim().describe(SECRET_IMPORTS.CREATE.environment),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.CREATE.path),
import: z.object({
environment: z.string().trim(),
path: z.string().trim().transform(removeTrailingSlash)
environment: z.string().trim().describe(SECRET_IMPORTS.CREATE.import.environment),
path: z.string().trim().transform(removeTrailingSlash).describe(SECRET_IMPORTS.CREATE.import.path)
})
}),
response: {
@@ -43,6 +47,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.createImport({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
@@ -69,31 +74,34 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/:secretImportId",
method: "PATCH",
url: "/:secretImportId",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Update secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
secretImportId: z.string().trim()
secretImportId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.secretImportId)
}),
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash),
workspaceId: z.string().trim().describe(SECRET_IMPORTS.UPDATE.workspaceId),
environment: z.string().trim().describe(SECRET_IMPORTS.UPDATE.environment),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.UPDATE.path),
import: z.object({
environment: z.string().trim().optional(),
environment: z.string().trim().optional().describe(SECRET_IMPORTS.UPDATE.import.environment),
path: z
.string()
.trim()
.optional()
.transform((val) => (val ? removeTrailingSlash(val) : val)),
position: z.number().optional()
.transform((val) => (val ? removeTrailingSlash(val) : val))
.describe(SECRET_IMPORTS.UPDATE.import.path),
position: z.number().optional().describe(SECRET_IMPORTS.UPDATE.import.position)
})
}),
response: {
@@ -112,6 +120,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.updateImport({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.secretImportId,
...req.body,
@@ -139,23 +148,25 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/:secretImportId",
method: "DELETE",
url: "/:secretImportId",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Delete secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
secretImportId: z.string().trim()
secretImportId: z.string().trim().describe(SECRET_IMPORTS.DELETE.secretImportId)
}),
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash)
workspaceId: z.string().trim().describe(SECRET_IMPORTS.DELETE.workspaceId),
environment: z.string().trim().describe(SECRET_IMPORTS.DELETE.environment),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.DELETE.path)
}),
response: {
200: z.object({
@@ -173,6 +184,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.deleteImport({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.secretImportId,
...req.body,
@@ -199,20 +211,22 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/",
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
description: "Get secret imports",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
querystring: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
path: z.string().trim().default("/").transform(removeTrailingSlash)
workspaceId: z.string().trim().describe(SECRET_IMPORTS.LIST.workspaceId),
environment: z.string().trim().describe(SECRET_IMPORTS.LIST.environment),
path: z.string().trim().default("/").transform(removeTrailingSlash).describe(SECRET_IMPORTS.LIST.path)
}),
response: {
200: z.object({
@@ -232,6 +246,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImports = await server.services.secretImport.getImports({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId
@@ -256,6 +271,9 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
server.route({
url: "/secrets",
method: "GET",
config: {
rateLimit: secretsLimit
},
schema: {
querystring: z.object({
workspaceId: z.string().trim(),
@@ -285,6 +303,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const importedSecrets = await server.services.secretImport.getSecretsFromImports({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId
@@ -1,16 +1,21 @@
import { z } from "zod";
import { SecretTagsSchema } from "@app/db/schemas";
import { SECRET_TAGS } 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";
export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:projectId/tags",
method: "GET",
url: "/:projectId/tags",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
projectId: z.string().trim().describe(SECRET_TAGS.LIST.projectId)
}),
response: {
200: z.object({
@@ -23,6 +28,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTags = await server.services.secretTag.getProjectTags({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId
});
@@ -31,16 +37,19 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:projectId/tags",
method: "POST",
url: "/:projectId/tags",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
projectId: z.string().trim().describe(SECRET_TAGS.CREATE.projectId)
}),
body: z.object({
name: z.string().trim(),
slug: z.string().trim(),
color: z.string()
name: z.string().trim().describe(SECRET_TAGS.CREATE.name),
slug: z.string().trim().describe(SECRET_TAGS.CREATE.slug),
color: z.string().trim().describe(SECRET_TAGS.CREATE.color)
}),
response: {
200: z.object({
@@ -53,6 +62,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTag = await server.services.secretTag.createTag({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId,
...req.body
@@ -62,12 +72,15 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:projectId/tags/:tagId",
method: "DELETE",
url: "/:projectId/tags/:tagId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
projectId: z.string().trim(),
tagId: z.string().trim()
projectId: z.string().trim().describe(SECRET_TAGS.DELETE.projectId),
tagId: z.string().trim().describe(SECRET_TAGS.DELETE.tagId)
}),
response: {
200: z.object({
@@ -80,6 +93,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTag = await server.services.secretTag.deleteTag({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.tagId
});
@@ -1,6 +1,7 @@
import { z } from "zod";
import { UserActionsSchema } from "@app/db/schemas";
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";
@@ -8,6 +9,9 @@ export const registerUserActionRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "POST",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
action: z.string().trim()
@@ -29,6 +33,9 @@ export const registerUserActionRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "GET",
config: {
rateLimit: readLimit
},
schema: {
querystring: z.object({
action: z.string().trim()
+5 -1
View File
@@ -1,6 +1,7 @@
import { z } from "zod";
import { UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -8,6 +9,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.object({
@@ -15,7 +19,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
onRequest: verifyAuth([AuthMode.JWT], { requireOrg: false }),
handler: async (req) => {
const user = await server.services.user.getMe(req.permission.id);
return { user };
@@ -3,6 +3,7 @@ import { z } from "zod";
import { WebhooksSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { removeTrailingSlash } from "@app/lib/fn";
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";
@@ -27,6 +28,9 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
@@ -47,6 +51,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.createWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId,
...req.body
@@ -74,6 +79,9 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
server.route({
method: "PATCH",
url: "/:webhookId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -93,6 +101,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.updateWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.webhookId,
isDisabled: req.body.isDisabled
@@ -120,6 +129,9 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/:webhookId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -130,6 +142,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.deleteWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.webhookId
});
@@ -156,6 +169,9 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/:webhookId/test",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -172,6 +188,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.testWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.webhookId
});
@@ -182,6 +199,9 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
querystring: z.object({
@@ -204,6 +224,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhooks = await server.services.webhook.listWebhooks({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId
@@ -0,0 +1,201 @@
import ms from "ms";
import { z } from "zod";
import {
GroupProjectMembershipsSchema,
GroupsSchema,
ProjectMembershipRole,
ProjectUserMembershipRolesSchema
} from "@app/db/schemas";
import { PROJECTS } from "@app/lib/api-docs";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types";
export const registerGroupProjectRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/:projectSlug/groups/:groupSlug",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Add group to project",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECTS.ADD_GROUP_TO_PROJECT.projectSlug),
groupSlug: z.string().trim().describe(PROJECTS.ADD_GROUP_TO_PROJECT.groupSlug)
}),
body: z.object({
role: z
.string()
.trim()
.min(1)
.default(ProjectMembershipRole.NoAccess)
.describe(PROJECTS.ADD_GROUP_TO_PROJECT.role)
}),
response: {
200: z.object({
groupMembership: GroupProjectMembershipsSchema
})
}
},
handler: async (req) => {
const groupMembership = await server.services.groupProject.addGroupToProject({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
groupSlug: req.params.groupSlug,
projectSlug: req.params.projectSlug,
role: req.body.role
});
return { groupMembership };
}
});
server.route({
method: "PATCH",
url: "/:projectSlug/groups/:groupSlug",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Update group in project",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECTS.UPDATE_GROUP_IN_PROJECT.projectSlug),
groupSlug: z.string().trim().describe(PROJECTS.UPDATE_GROUP_IN_PROJECT.groupSlug)
}),
body: z.object({
roles: z
.array(
z.union([
z.object({
role: z.string(),
isTemporary: z.literal(false).default(false)
}),
z.object({
role: z.string(),
isTemporary: z.literal(true),
temporaryMode: z.nativeEnum(ProjectUserMembershipTemporaryMode),
temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"),
temporaryAccessStartTime: z.string().datetime()
})
])
)
.min(1)
.describe(PROJECTS.UPDATE_GROUP_IN_PROJECT.roles)
}),
response: {
200: z.object({
roles: ProjectUserMembershipRolesSchema.array()
})
}
},
handler: async (req) => {
const roles = await server.services.groupProject.updateGroupInProject({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
groupSlug: req.params.groupSlug,
projectSlug: req.params.projectSlug,
roles: req.body.roles
});
return { roles };
}
});
server.route({
method: "DELETE",
url: "/:projectSlug/groups/:groupSlug",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Remove group from project",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECTS.REMOVE_GROUP_FROM_PROJECT.projectSlug),
groupSlug: z.string().trim().describe(PROJECTS.REMOVE_GROUP_FROM_PROJECT.groupSlug)
}),
response: {
200: z.object({
groupMembership: GroupProjectMembershipsSchema
})
}
},
handler: async (req) => {
const groupMembership = await server.services.groupProject.removeGroupFromProject({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
groupSlug: req.params.groupSlug,
projectSlug: req.params.projectSlug
});
return { groupMembership };
}
});
server.route({
method: "GET",
url: "/:projectSlug/groups",
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Return list of groups in project",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECTS.LIST_GROUPS_IN_PROJECT.projectSlug)
}),
response: {
200: z.object({
groupMemberships: z
.object({
id: z.string(),
groupId: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
roles: z.array(
z.object({
id: z.string(),
role: z.string(),
customRoleId: z.string().optional().nullable(),
customRoleName: z.string().optional().nullable(),
customRoleSlug: z.string().optional().nullable(),
isTemporary: z.boolean(),
temporaryMode: z.string().optional().nullable(),
temporaryRange: z.string().nullable().optional(),
temporaryAccessStartTime: z.date().nullable().optional(),
temporaryAccessEndTime: z.date().nullable().optional()
})
),
group: GroupsSchema.pick({ name: true, id: true, slug: true })
})
.array()
})
}
},
handler: async (req) => {
const groupMemberships = await server.services.groupProject.listGroupsInProject({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectSlug: req.params.projectSlug
});
return { groupMemberships };
}
});
};
@@ -1,6 +1,8 @@
import { z } from "zod";
import { IdentitiesSchema, IdentityOrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas";
import { ORGANIZATIONS } 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";
@@ -8,17 +10,19 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:orgId/identity-memberships",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Return organization identity memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
orgId: z.string().trim()
orgId: z.string().trim().describe(ORGANIZATIONS.LIST_IDENTITY_MEMBERSHIPS.orgId)
}),
response: {
200: z.object({
@@ -41,9 +45,11 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
const identityMemberships = await server.services.identity.listOrgIdentities({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
orgId: req.params.orgId
});
return { identityMemberships };
}
});
@@ -7,6 +7,8 @@ import {
ProjectMembershipRole,
ProjectUserMembershipRolesSchema
} from "@app/db/schemas";
import { PROJECTS } 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 { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types";
@@ -15,6 +17,9 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
server.route({
method: "POST",
url: "/:projectId/identity-memberships/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
params: z.object({
@@ -34,6 +39,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.createProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
projectId: req.params.projectId,
@@ -46,6 +52,9 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
server.route({
method: "PATCH",
url: "/:projectId/identity-memberships/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Update project identity memberships",
@@ -55,8 +64,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
}
],
params: z.object({
projectId: z.string().trim(),
identityId: z.string().trim()
projectId: z.string().trim().describe(PROJECTS.UPDATE_IDENTITY_MEMBERSHIP.projectId),
identityId: z.string().trim().describe(PROJECTS.UPDATE_IDENTITY_MEMBERSHIP.identityId)
}),
body: z.object({
roles: z
@@ -76,6 +85,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
])
)
.min(1)
.describe(PROJECTS.UPDATE_IDENTITY_MEMBERSHIP.roles)
}),
response: {
200: z.object({
@@ -87,6 +97,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const roles = await server.services.identityProject.updateProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
projectId: req.params.projectId,
@@ -99,6 +110,9 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
server.route({
method: "DELETE",
url: "/:projectId/identity-memberships/:identityId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Delete project identity memberships",
@@ -108,8 +122,8 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
}
],
params: z.object({
projectId: z.string().trim(),
identityId: z.string().trim()
projectId: z.string().trim().describe(PROJECTS.DELETE_IDENTITY_MEMBERSHIP.projectId),
identityId: z.string().trim().describe(PROJECTS.DELETE_IDENTITY_MEMBERSHIP.identityId)
}),
response: {
200: z.object({
@@ -121,6 +135,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.deleteProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
projectId: req.params.projectId
@@ -132,6 +147,9 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
server.route({
method: "GET",
url: "/:projectId/identity-memberships",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: {
description: "Return project identity memberships",
@@ -141,7 +159,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
}
],
params: z.object({
projectId: z.string().trim()
projectId: z.string().trim().describe(PROJECTS.LIST_IDENTITY_MEMBERSHIPS.projectId)
}),
response: {
200: z.object({
@@ -175,6 +193,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMemberships = await server.services.identityProject.listProjectIdentities({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId
});
+2
View File
@@ -1,3 +1,4 @@
import { registerGroupProjectRouter } from "./group-project-router";
import { registerIdentityOrgRouter } from "./identity-org-router";
import { registerIdentityProjectRouter } from "./identity-project-router";
import { registerMfaRouter } from "./mfa-router";
@@ -22,6 +23,7 @@ export const registerV2Routes = async (server: FastifyZodProvider) => {
async (projectServer) => {
await projectServer.register(registerProjectRouter);
await projectServer.register(registerIdentityProjectRouter);
await projectServer.register(registerGroupProjectRouter);
await projectServer.register(registerProjectMembershipRouter);
},
{ prefix: "/workspace" }
+11 -1
View File
@@ -2,6 +2,7 @@ import jwt from "jsonwebtoken";
import { z } from "zod";
import { getConfig } from "@app/lib/config/env";
import { writeLimit } from "@app/server/config/rateLimiter";
import { AuthModeMfaJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
export const registerMfaRouter = async (server: FastifyZodProvider) => {
@@ -30,8 +31,11 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/mfa/send",
method: "POST",
url: "/mfa/send",
config: {
rateLimit: writeLimit
},
schema: {
response: {
200: z.object({
@@ -48,6 +52,9 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/mfa/verify",
method: "POST",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
mfaToken: z.string().trim()
@@ -68,11 +75,14 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
},
handler: async (req, res) => {
const userAgent = req.headers["user-agent"];
const mfaJwtToken = req.headers.authorization?.replace("Bearer ", "");
if (!userAgent) throw new Error("user agent header is required");
if (!mfaJwtToken) throw new Error("authorization header is required");
const appCfg = getConfig();
const { user, token } = await server.services.login.verifyMfaToken({
userAgent,
mfaJwtToken,
ip: req.realIp,
userId: req.mfa.userId,
orgId: req.mfa.orgId,
@@ -1,6 +1,8 @@
import { z } from "zod";
import { OrganizationsSchema, OrgMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
import { ORGANIZATIONS } from "@app/lib/api-docs";
import { creationLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
@@ -8,16 +10,18 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:organizationId/memberships",
config: {
rateLimit: readLimit
},
schema: {
description: "Return organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
organizationId: z.string().trim()
organizationId: z.string().trim().describe(ORGANIZATIONS.LIST_USER_MEMBERSHIPS.organizationId)
}),
response: {
200: z.object({
@@ -44,6 +48,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const users = await server.services.org.findAllOrgMembers(
req.permission.id,
req.params.organizationId,
req.permission.authMethod,
req.permission.orgId
);
return { users };
@@ -53,16 +58,18 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:organizationId/workspaces",
config: {
rateLimit: readLimit
},
schema: {
description: "Return projects in organization that user is part of",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
organizationId: z.string().trim()
organizationId: z.string().trim().describe(ORGANIZATIONS.GET_PROJECTS.organizationId)
}),
response: {
200: z.object({
@@ -88,6 +95,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
orgId: req.params.organizationId
});
@@ -98,17 +106,22 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "PATCH",
url: "/:organizationId/memberships/:membershipId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Update organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
params: z.object({
organizationId: z.string().trim().describe(ORGANIZATIONS.UPDATE_USER_MEMBERSHIP.organizationId),
membershipId: z.string().trim().describe(ORGANIZATIONS.UPDATE_USER_MEMBERSHIP.membershipId)
}),
body: z.object({
role: z.string().trim()
role: z.string().trim().describe(ORGANIZATIONS.UPDATE_USER_MEMBERSHIP.role)
}),
response: {
200: z.object({
@@ -123,6 +136,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const membership = await server.services.org.updateOrgMembership({
userId: req.permission.id,
role: req.body.role,
actorAuthMethod: req.permission.authMethod,
orgId: req.params.organizationId,
membershipId: req.params.membershipId,
actorOrgId: req.permission.orgId
@@ -134,15 +148,20 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/:organizationId/memberships/:membershipId",
config: {
rateLimit: writeLimit
},
schema: {
description: "Delete organization user memberships",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({ organizationId: z.string().trim(), membershipId: z.string().trim() }),
params: z.object({
organizationId: z.string().trim().describe(ORGANIZATIONS.DELETE_USER_MEMBERSHIP.organizationId),
membershipId: z.string().trim().describe(ORGANIZATIONS.DELETE_USER_MEMBERSHIP.membershipId)
}),
response: {
200: z.object({
membership: OrgMembershipsSchema
@@ -155,6 +174,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const membership = await server.services.org.deleteOrgMembership({
userId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
orgId: req.params.organizationId,
membershipId: req.params.membershipId,
actorOrgId: req.permission.orgId
@@ -166,6 +186,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/",
config: {
rateLimit: creationLimit
},
schema: {
body: z.object({
name: z.string().trim()
@@ -176,7 +199,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY], { requireOrg: false }),
handler: async (req) => {
if (req.auth.actor !== ActorType.USER) return;
@@ -193,6 +216,9 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/:organizationId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
organizationId: z.string().trim()
@@ -210,6 +236,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const organization = await server.services.org.deleteOrganizationById(
req.permission.id,
req.params.organizationId,
req.permission.authMethod,
req.permission.orgId
);
return { organization };
@@ -2,6 +2,8 @@ import { z } from "zod";
import { ProjectMembershipsSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { PROJECTS } from "@app/lib/api-docs";
import { writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -9,13 +11,22 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
server.route({
method: "POST",
url: "/:projectId/memberships",
config: {
rateLimit: writeLimit
},
schema: {
description: "Invite members to project",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectId: z.string().describe("The ID of the project.")
projectId: z.string().describe(PROJECTS.INVITE_MEMBER.projectId)
}),
body: z.object({
emails: z.string().email().array().default([]).describe("Emails of the users to add to the project."),
usernames: z.string().array().default([]).describe("Usernames of the users to add to the project.")
emails: z.string().email().array().default([]).describe(PROJECTS.INVITE_MEMBER.emails),
usernames: z.string().array().default([]).describe(PROJECTS.INVITE_MEMBER.usernames)
}),
response: {
200: z.object({
@@ -27,7 +38,9 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
handler: async (req) => {
const memberships = await server.services.projectMembership.addUsersToProjectNonE2EE({
projectId: req.params.projectId,
actorAuthMethod: req.permission.authMethod,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
emails: req.body.emails,
usernames: req.body.usernames
@@ -53,14 +66,22 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
server.route({
method: "DELETE",
url: "/:projectId/memberships",
config: {
rateLimit: writeLimit
},
schema: {
description: "Remove members from project",
security: [
{
bearerAuth: []
}
],
params: z.object({
projectId: z.string().describe("The ID of the project.")
projectId: z.string().describe(PROJECTS.REMOVE_MEMBER.projectId)
}),
body: z.object({
emails: z.string().email().array().default([]).describe("Emails of the users to remove from the project."),
usernames: z.string().array().default([]).describe("Usernames of the users to remove from the project.")
emails: z.string().email().array().default([]).describe(PROJECTS.REMOVE_MEMBER.emails),
usernames: z.string().array().default([]).describe(PROJECTS.REMOVE_MEMBER.usernames)
}),
response: {
200: z.object({
@@ -73,6 +94,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const memberships = await server.services.projectMembership.deleteProjectMemberships({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId,
emails: req.body.emails,
+159 -19
View File
@@ -3,10 +3,12 @@ import { z } from "zod";
import { ProjectKeysSchema, ProjectsSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { authRateLimit } from "@app/server/config/rateLimiter";
import { PROJECTS } from "@app/lib/api-docs";
import { creationLimit, readLimit, writeLimit } from "@app/server/config/rateLimiter";
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 { ProjectFilterType } from "@app/services/project/project-types";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
const projectWithEnv = ProjectsSchema.merge(
@@ -16,20 +18,26 @@ const projectWithEnv = ProjectsSchema.merge(
})
);
const slugSchema = z
.string()
.min(5)
.max(36)
.refine((v) => slugify(v) === v, {
message: "Slug must be at least 5 character but no more than 36"
});
export const registerProjectRouter = async (server: FastifyZodProvider) => {
/* Get project key */
server.route({
url: "/:workspaceId/encrypted-key",
method: "GET",
url: "/:workspaceId/encrypted-key",
config: {
rateLimit: readLimit
},
schema: {
description: "Return encrypted project key",
security: [
{
apiKeyAuth: []
}
],
params: z.object({
workspaceId: z.string().trim()
workspaceId: z.string().trim().describe(PROJECTS.GET_KEY.workspaceId)
}),
response: {
200: ProjectKeysSchema.merge(
@@ -46,6 +54,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const key = await server.services.projectKey.getLatestProjectKey({
actor: req.permission.type,
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
@@ -67,13 +76,15 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
/* Start upgrade of a project */
server.route({
url: "/:projectId/upgrade",
method: "POST",
url: "/:projectId/upgrade",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
}),
body: z.object({
userPrivateKey: z.string().trim()
}),
@@ -81,11 +92,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
200: z.void()
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
await server.services.project.upgradeProject({
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
projectId: req.params.projectId,
userPrivateKey: req.body.userPrivateKey
});
@@ -96,6 +109,9 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:projectId/upgrade/status",
method: "GET",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
@@ -106,9 +122,11 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const status = await server.services.project.getProjectUpgradeStatus({
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId,
actor: req.permission.type,
actorId: req.permission.id
@@ -123,11 +141,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
method: "POST",
url: "/",
config: {
rateLimit: authRateLimit
rateLimit: creationLimit
},
schema: {
description: "Create a new project",
security: [
{
bearerAuth: []
}
],
body: z.object({
projectName: z.string().trim(),
projectName: z.string().trim().describe(PROJECTS.CREATE.projectName),
slug: z
.string()
.min(5)
@@ -135,8 +159,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
})
.optional(),
organizationId: z.string().trim()
.optional()
.describe(PROJECTS.CREATE.slug)
}),
response: {
200: z.object({
@@ -144,12 +168,13 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const project = await server.services.project.createProject({
actorId: req.permission.id,
actor: req.permission.type,
orgId: req.body.organizationId,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
workspaceName: req.body.projectName,
slug: req.body.slug
});
@@ -158,7 +183,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
event: PostHogEventTypes.ProjectCreated,
distinctId: getTelemetryDistinctId(req),
properties: {
orgId: req.body.organizationId,
orgId: project.orgId,
name: project.name,
...req.auditLogInfo
}
@@ -167,4 +192,119 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
return { project };
}
});
/* Delete a project by slug */
server.route({
method: "DELETE",
url: "/:slug",
config: {
rateLimit: writeLimit
},
schema: {
description: "Delete project",
security: [
{
bearerAuth: []
}
],
params: z.object({
slug: slugSchema.describe("The slug of the project to delete.")
}),
response: {
200: ProjectsSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const project = await server.services.project.deleteProject({
filter: {
type: ProjectFilterType.SLUG,
slug: req.params.slug,
orgId: req.permission.orgId
},
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
actor: req.permission.type
});
return project;
}
});
/* Get a project by slug */
server.route({
method: "GET",
url: "/:slug",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
slug: slugSchema.describe("The slug of the project to get.")
}),
response: {
200: projectWithEnv
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const project = await server.services.project.getAProject({
filter: {
slug: req.params.slug,
orgId: req.permission.orgId,
type: ProjectFilterType.SLUG
},
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type
});
return project;
}
});
/* Update a project by slug */
server.route({
method: "PATCH",
url: "/:slug",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
slug: slugSchema.describe("The slug of the project to update.")
}),
body: z.object({
name: z.string().trim().optional().describe("The new name of the project."),
autoCapitalization: z.boolean().optional().describe("The new auto-capitalization setting.")
}),
response: {
200: ProjectsSchema
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const project = await server.services.project.updateProject({
filter: {
type: ProjectFilterType.SLUG,
slug: req.params.slug,
orgId: req.permission.orgId
},
update: {
name: req.body.name,
autoCapitalization: req.body.autoCapitalization
},
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
return project;
}
});
};
@@ -3,6 +3,7 @@ import { z } from "zod";
import { ServiceTokensSchema } from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { removeTrailingSlash } from "@app/lib/fn";
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";
@@ -17,8 +18,11 @@ export const sanitizedServiceTokenSchema = ServiceTokensSchema.omit({
export const registerServiceTokenRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/",
method: "GET",
url: "/",
config: {
rateLimit: readLimit
},
onRequest: verifyAuth([AuthMode.SERVICE_TOKEN]),
schema: {
description: "Return Infisical Token data",
@@ -46,6 +50,8 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
handler: async (req) => {
const { serviceToken, user } = await server.services.serviceToken.getServiceToken({
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
actor: req.permission.type
});
@@ -67,8 +73,11 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/",
method: "POST",
url: "/",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
@@ -98,6 +107,7 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
const { serviceToken, token } = await server.services.serviceToken.createServiceToken({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId
@@ -119,8 +129,11 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
});
server.route({
url: "/:serviceTokenId",
method: "DELETE",
url: "/:serviceTokenId",
config: {
rateLimit: writeLimit
},
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
params: z.object({
@@ -136,6 +149,7 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
const serviceTokenData = await server.services.serviceToken.deleteServiceToken({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
id: req.params.serviceTokenId
});
+38 -14
View File
@@ -2,13 +2,17 @@ import { z } from "zod";
import { AuthTokenSessionsSchema, OrganizationsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
import { ApiKeysSchema } from "@app/db/schemas/api-keys";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMethod, AuthMode } from "@app/services/auth/auth-type";
export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/me/mfa",
method: "PATCH",
url: "/me/mfa",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
isMfaEnabled: z.boolean()
@@ -27,8 +31,11 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/me/name",
method: "PATCH",
url: "/me/name",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
firstName: z.string().trim(),
@@ -48,8 +55,11 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/me/auth-methods",
method: "PUT",
url: "/me/auth-methods",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
authMethods: z.nativeEnum(AuthMethod).array().min(1)
@@ -60,7 +70,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
})
}
},
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
preHandler: verifyAuth([AuthMode.JWT, AuthMode.API_KEY], { requireOrg: false }),
handler: async (req) => {
const user = await server.services.user.updateAuthMethods(req.permission.id, req.body.authMethods);
return { user };
@@ -70,13 +80,11 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/me/organizations",
config: {
rateLimit: readLimit
},
schema: {
description: "Return organizations that current user is part of",
security: [
{
apiKeyAuth: []
}
],
response: {
200: z.object({
organizations: OrganizationsSchema.array()
@@ -93,6 +101,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/me/api-keys",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: ApiKeysSchema.omit({ secretHash: true }).array()
@@ -108,6 +119,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/me/api-keys",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
name: z.string().trim(),
@@ -130,6 +144,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/me/api-keys/:apiKeyDataId",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
apiKeyDataId: z.string().trim()
@@ -150,6 +167,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/me/sessions",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: AuthTokenSessionsSchema.array()
@@ -165,6 +185,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/me/sessions",
config: {
rateLimit: writeLimit
},
schema: {
response: {
200: z.object({
@@ -184,13 +207,11 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/me",
config: {
rateLimit: readLimit
},
schema: {
description: "Retrieve the current user on the request",
security: [
{
apiKeyAuth: []
}
],
response: {
200: z.object({
user: UsersSchema.merge(UserEncryptionKeysSchema.omit({ verifier: true }))
@@ -207,6 +228,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/me",
config: {
rateLimit: writeLimit
},
schema: {
response: {
200: z.object({
@@ -34,6 +34,42 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
}
});
server.route({
method: "POST",
url: "/select-organization",
config: {
rateLimit: authRateLimit
},
schema: {
body: z.object({
organizationId: z.string().trim()
}),
response: {
200: z.object({
token: z.string()
})
}
},
handler: async (req, res) => {
const cfg = getConfig();
const tokens = await server.services.login.selectOrganization({
userAgent: req.headers["user-agent"],
authJwtToken: req.headers.authorization,
organizationId: req.body.organizationId,
ipAddress: req.realIp
});
void res.setCookie("jid", tokens.refresh, {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: cfg.HTTPS_ENABLED
});
return { token: tokens.access };
}
});
server.route({
method: "POST",
url: "/login2",
@@ -1,13 +1,17 @@
import { z } from "zod";
import { SecretsSchema } from "@app/db/schemas";
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";
export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:projectId/secrets/blind-index-status",
method: "GET",
url: "/:projectId/secrets/blind-index-status",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
@@ -20,6 +24,7 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
handler: async (req) => {
const count = await server.services.secretBlindIndex.getSecretBlindIndexStatus({
projectId: req.params.projectId,
actorAuthMethod: req.permission.authMethod,
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId
@@ -29,8 +34,11 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:projectId/secrets",
method: "GET",
url: "/:projectId/secrets",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
@@ -52,6 +60,7 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
handler: async (req) => {
const secrets = await server.services.secretBlindIndex.getProjectSecrets({
projectId: req.params.projectId,
actorAuthMethod: req.permission.authMethod,
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId
@@ -61,8 +70,11 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
});
server.route({
url: "/:projectId/secrets/names",
method: "POST",
url: "/:projectId/secrets/names",
config: {
rateLimit: writeLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
@@ -86,6 +98,7 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
await server.services.secretBlindIndex.updateProjectSecretName({
projectId: req.params.projectId,
secretsToUpdate: req.body.secretsToUpdate,
actorAuthMethod: req.permission.authMethod,
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId
+309 -68
View File
@@ -10,40 +10,180 @@ import {
} from "@app/db/schemas";
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types";
import { RAW_SECRETS, SECRETS } from "@app/lib/api-docs";
import { BadRequestError } from "@app/lib/errors";
import { removeTrailingSlash } from "@app/lib/fn";
import { secretsLimit, writeLimit } from "@app/server/config/rateLimiter";
import { getTelemetryDistinctId } from "@app/server/lib/telemetry";
import { getUserAgentType } from "@app/server/plugins/audit-log";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { ActorType, AuthMode } from "@app/services/auth/auth-type";
import { ProjectFilterType } from "@app/services/project/project-types";
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
import { secretRawSchema } from "../sanitizedSchemas";
export const registerSecretRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/raw",
method: "POST",
url: "/tags/:secretName",
config: {
rateLimit: writeLimit
},
schema: {
description: "Attach tags to a secret",
security: [
{
bearerAuth: []
}
],
params: z.object({
secretName: z.string().trim().describe(SECRETS.ATTACH_TAGS.secretName)
}),
body: z.object({
projectSlug: z.string().trim().describe(SECRETS.ATTACH_TAGS.projectSlug),
environment: z.string().trim().describe(SECRETS.ATTACH_TAGS.environment),
secretPath: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(SECRETS.ATTACH_TAGS.secretPath),
type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(SECRETS.ATTACH_TAGS.type),
tagSlugs: z.string().array().min(1).describe(SECRETS.ATTACH_TAGS.tagSlugs)
}),
response: {
200: z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true }).merge(
z.object({
tags: SecretTagsSchema.pick({
id: true,
slug: true,
name: true,
color: true
}).array()
})
)
})
}
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const secret = await server.services.secret.attachTags({
secretName: req.params.secretName,
tagSlugs: req.body.tagSlugs,
path: req.body.secretPath,
environment: req.body.environment,
type: req.body.type,
projectSlug: req.body.projectSlug,
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
return { secret };
}
});
server.route({
method: "DELETE",
url: "/tags/:secretName",
config: {
rateLimit: writeLimit
},
schema: {
description: "Detach tags from a secret",
security: [
{
bearerAuth: []
}
],
params: z.object({
secretName: z.string().trim().describe(SECRETS.DETACH_TAGS.secretName)
}),
body: z.object({
projectSlug: z.string().trim().describe(SECRETS.DETACH_TAGS.projectSlug),
environment: z.string().trim().describe(SECRETS.DETACH_TAGS.environment),
secretPath: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(SECRETS.DETACH_TAGS.secretPath),
type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(SECRETS.DETACH_TAGS.type),
tagSlugs: z.string().array().min(1).describe(SECRETS.DETACH_TAGS.tagSlugs)
}),
response: {
200: z.object({
secret: SecretsSchema.omit({ secretBlindIndex: true }).merge(
z.object({
tags: SecretTagsSchema.pick({
id: true,
slug: true,
name: true,
color: true
}).array()
})
)
})
}
},
onRequest: verifyAuth([AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const secret = await server.services.secret.detachTags({
secretName: req.params.secretName,
tagSlugs: req.body.tagSlugs,
path: req.body.secretPath,
environment: req.body.environment,
type: req.body.type,
projectSlug: req.body.projectSlug,
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId
});
return { secret };
}
});
server.route({
method: "GET",
url: "/raw",
config: {
rateLimit: secretsLimit
},
schema: {
description: "List secrets",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
querystring: z.object({
workspaceId: z.string().trim().optional(),
environment: z.string().trim().optional(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
workspaceId: z.string().trim().optional().describe(RAW_SECRETS.LIST.workspaceId),
workspaceSlug: z.string().trim().optional().describe(RAW_SECRETS.LIST.workspaceSlug),
environment: z.string().trim().optional().describe(RAW_SECRETS.LIST.environment),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.LIST.secretPath),
recursive: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.LIST.recursive),
include_imports: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.LIST.includeImports)
}),
response: {
200: z.object({
secrets: secretRawSchema.array(),
secrets: secretRawSchema
.extend({
secretPath: z.string().optional()
})
.array(),
imports: z
.object({
secretPath: z.string(),
@@ -68,6 +208,22 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
environment = scope[0].environment;
workspaceId = req.auth.serviceToken.projectId;
}
} else if (req.permission.type === ActorType.IDENTITY && req.query.workspaceSlug && !workspaceId) {
const workspace = await server.services.project.getAProject({
filter: {
type: ProjectFilterType.SLUG,
orgId: req.permission.orgId,
slug: req.query.workspaceSlug
},
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
if (!workspace) throw new BadRequestError({ message: `No project found with slug ${req.query.workspaceSlug}` });
workspaceId = workspace.id;
}
if (!workspaceId || !environment) throw new BadRequestError({ message: "Missing workspace id or environment" });
@@ -77,13 +233,15 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment,
actorAuthMethod: req.permission.authMethod,
projectId: workspaceId,
path: secretPath,
includeImports: req.query.include_imports
includeImports: req.query.include_imports,
recursive: req.query.recursive
});
await server.services.auditLog.createAuditLog({
projectId: req.query.workspaceId,
projectId: workspaceId,
...req.auditLogInfo,
event: {
type: EventType.GET_SECRETS,
@@ -112,29 +270,32 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/raw/:secretName",
method: "GET",
url: "/raw/:secretName",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Get a secret by name",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
secretName: z.string().trim()
secretName: z.string().trim().describe(RAW_SECRETS.GET.secretName)
}),
querystring: z.object({
workspaceId: z.string().trim().optional(),
environment: z.string().trim().optional(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
version: z.coerce.number().optional(),
type: z.nativeEnum(SecretType).default(SecretType.Shared),
workspaceId: z.string().trim().optional().describe(RAW_SECRETS.GET.workspaceId),
environment: z.string().trim().optional().describe(RAW_SECRETS.GET.environment),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash).describe(RAW_SECRETS.GET.secretPath),
version: z.coerce.number().optional().describe(RAW_SECRETS.GET.version),
type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.GET.type),
include_imports: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true")
.describe(RAW_SECRETS.GET.includeImports)
}),
response: {
200: z.object({
@@ -160,6 +321,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.getSecretByNameRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
environment,
projectId: workspaceId,
@@ -202,27 +364,37 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/raw/:secretName",
method: "POST",
url: "/raw/:secretName",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Create secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
secretName: z.string().trim()
secretName: z.string().trim().describe(RAW_SECRETS.CREATE.secretName)
}),
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
secretComment: z.string().trim().optional().default(""),
skipMultilineEncoding: z.boolean().optional(),
type: z.nativeEnum(SecretType).default(SecretType.Shared)
workspaceId: z.string().trim().describe(RAW_SECRETS.CREATE.workspaceId),
environment: z.string().trim().describe(RAW_SECRETS.CREATE.environment),
secretPath: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(RAW_SECRETS.CREATE.secretPath),
secretValue: z
.string()
.transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim()))
.describe(RAW_SECRETS.CREATE.secretValue),
secretComment: z.string().trim().optional().default("").describe(RAW_SECRETS.CREATE.secretComment),
skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.CREATE.skipMultilineEncoding),
type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.CREATE.type)
}),
response: {
200: z.object({
@@ -237,6 +409,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.body.environment,
actorAuthMethod: req.permission.authMethod,
projectId: req.body.workspaceId,
secretPath: req.body.secretPath,
secretName: req.params.secretName,
@@ -279,26 +452,36 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/raw/:secretName",
method: "PATCH",
url: "/raw/:secretName",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Update secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
secretName: z.string().trim()
secretName: z.string().trim().describe(RAW_SECRETS.UPDATE.secretName)
}),
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
secretValue: z.string().transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim())),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
skipMultilineEncoding: z.boolean().optional(),
type: z.nativeEnum(SecretType).default(SecretType.Shared)
workspaceId: z.string().trim().describe(RAW_SECRETS.UPDATE.workspaceId),
environment: z.string().trim().describe(RAW_SECRETS.UPDATE.environment),
secretValue: z
.string()
.transform((val) => (val.at(-1) === "\n" ? `${val.trim()}\n` : val.trim()))
.describe(RAW_SECRETS.UPDATE.secretValue),
secretPath: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(RAW_SECRETS.UPDATE.secretPath),
skipMultilineEncoding: z.boolean().optional().describe(RAW_SECRETS.UPDATE.skipMultilineEncoding),
type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.UPDATE.type)
}),
response: {
200: z.object({
@@ -312,6 +495,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
environment: req.body.environment,
projectId: req.body.workspaceId,
secretPath: req.body.secretPath,
@@ -353,24 +537,31 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/raw/:secretName",
method: "DELETE",
url: "/raw/:secretName",
config: {
rateLimit: secretsLimit
},
schema: {
description: "Delete secret",
security: [
{
bearerAuth: [],
apiKeyAuth: []
bearerAuth: []
}
],
params: z.object({
secretName: z.string().trim()
secretName: z.string().trim().describe(RAW_SECRETS.DELETE.secretName)
}),
body: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
type: z.nativeEnum(SecretType).default(SecretType.Shared)
workspaceId: z.string().trim().describe(RAW_SECRETS.DELETE.workspaceId),
environment: z.string().trim().describe(RAW_SECRETS.DELETE.environment),
secretPath: z
.string()
.trim()
.default("/")
.transform(removeTrailingSlash)
.describe(RAW_SECRETS.DELETE.secretPath),
type: z.nativeEnum(SecretType).default(SecretType.Shared).describe(RAW_SECRETS.DELETE.type)
}),
response: {
200: z.object({
@@ -383,6 +574,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.deleteSecretRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
environment: req.body.environment,
projectId: req.body.workspaceId,
@@ -424,13 +616,20 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/",
method: "GET",
url: "/",
config: {
rateLimit: secretsLimit
},
schema: {
querystring: z.object({
workspaceId: z.string().trim(),
environment: z.string().trim(),
secretPath: z.string().trim().default("/").transform(removeTrailingSlash),
recursive: z
.enum(["true", "false"])
.default("false")
.transform((value) => value === "true"),
include_imports: z
.enum(["true", "false"])
.default("false")
@@ -439,19 +638,18 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
response: {
200: z.object({
secrets: SecretsSchema.omit({ secretBlindIndex: true })
.merge(
z.object({
_id: z.string(),
workspace: z.string(),
environment: z.string(),
tags: SecretTagsSchema.pick({
id: true,
slug: true,
name: true,
color: true
}).array()
})
)
.extend({
_id: z.string(),
workspace: z.string(),
environment: z.string(),
secretPath: z.string().optional(),
tags: SecretTagsSchema.pick({
id: true,
slug: true,
name: true,
color: true
}).array()
})
.array(),
imports: z
.object({
@@ -478,11 +676,13 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const { secrets, imports } = await server.services.secret.getSecrets({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
environment: req.query.environment,
projectId: req.query.workspaceId,
path: req.query.secretPath,
includeImports: req.query.include_imports
includeImports: req.query.include_imports,
recursive: req.query.recursive
});
await server.services.auditLog.createAuditLog({
@@ -531,8 +731,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:secretName",
method: "GET",
url: "/:secretName",
config: {
rateLimit: secretsLimit
},
schema: {
params: z.object({
secretName: z.string().trim()
@@ -564,6 +767,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.getSecretByName({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
environment: req.query.environment,
projectId: req.query.workspaceId,
@@ -608,6 +812,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
server.route({
url: "/:secretName",
method: "POST",
config: {
rateLimit: secretsLimit
},
schema: {
body: z.object({
workspaceId: z.string().trim(),
@@ -666,6 +873,8 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
if (req.body.type !== SecretType.Personal && req.permission.type === ActorType.USER) {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
secretPath,
environment,
@@ -675,6 +884,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -718,6 +928,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.createSecret({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
path: secretPath,
type,
@@ -770,8 +981,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:secretName",
method: "PATCH",
url: "/:secretName",
config: {
rateLimit: secretsLimit
},
schema: {
params: z.object({
secretName: z.string()
@@ -842,6 +1056,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -851,6 +1066,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -896,6 +1112,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.updateSecret({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
path: secretPath,
type,
@@ -951,8 +1168,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/:secretName",
method: "DELETE",
url: "/:secretName",
config: {
rateLimit: secretsLimit
},
schema: {
params: z.object({
secretName: z.string()
@@ -986,6 +1206,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -995,6 +1216,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -1028,6 +1250,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.deleteSecret({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
path: secretPath,
type,
@@ -1069,8 +1292,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/batch",
method: "POST",
url: "/batch",
config: {
rateLimit: secretsLimit
},
schema: {
body: z.object({
workspaceId: z.string().trim(),
@@ -1110,6 +1336,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -1119,6 +1346,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -1148,6 +1376,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.createManySecret({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
path: secretPath,
environment,
@@ -1189,8 +1418,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/batch",
method: "PATCH",
url: "/batch",
config: {
rateLimit: secretsLimit
},
schema: {
body: z.object({
workspaceId: z.string().trim(),
@@ -1231,6 +1463,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -1240,6 +1473,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -1268,6 +1502,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.updateManySecret({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
path: secretPath,
environment,
@@ -1309,8 +1544,11 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/batch",
method: "DELETE",
url: "/batch",
config: {
rateLimit: secretsLimit
},
schema: {
body: z.object({
workspaceId: z.string().trim(),
@@ -1340,6 +1578,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -1349,6 +1588,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
secretPath,
environment,
@@ -1376,6 +1616,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.deleteManySecret({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
path: req.body.secretPath,
environment,
+10 -8
View File
@@ -108,7 +108,8 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
200: z.object({
message: z.string(),
user: UsersSchema,
token: z.string()
token: z.string(),
organizationId: z.string().nullish()
})
}
},
@@ -124,12 +125,13 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
});
}
const { user, accessToken, refreshToken } = await server.services.signup.completeEmailAccountSignup({
...req.body,
ip: req.realIp,
userAgent,
authorization: req.headers.authorization as string
});
const { user, accessToken, refreshToken, organizationId } =
await server.services.signup.completeEmailAccountSignup({
...req.body,
ip: req.realIp,
userAgent,
authorization: req.headers.authorization as string
});
if (user.email) {
void server.services.telemetry.sendLoopsEvent(user.email, user.firstName || "", user.lastName || "");
@@ -152,7 +154,7 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
secure: appCfg.HTTPS_ENABLED
});
return { message: "Successfully set up account", user, token: accessToken };
return { message: "Successfully set up account", user, token: accessToken, organizationId };
}
});
@@ -1,6 +1,7 @@
import { z } from "zod";
import { ApiKeysSchema } from "@app/db/schemas/api-keys";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -8,6 +9,9 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/me/api-keys",
config: {
rateLimit: readLimit
},
schema: {
response: {
200: z.object({