mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 11:29:42 +00:00
MVP preliminary idea for initial sync behavior
This commit is contained in:
@@ -14,6 +14,7 @@ import fasitfy from "fastify";
|
||||
import { Knex } from "knex";
|
||||
import { Logger } from "pino";
|
||||
|
||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { TQueueServiceFactory } from "@app/queue";
|
||||
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
||||
@@ -31,13 +32,14 @@ type TMain = {
|
||||
smtp: TSmtpService;
|
||||
logger?: Logger;
|
||||
queue: TQueueServiceFactory;
|
||||
keyStore: TKeyStoreFactory;
|
||||
};
|
||||
|
||||
// Run the server!
|
||||
export const main = async ({ db, smtp, logger, queue }: TMain) => {
|
||||
export const main = async ({ db, smtp, logger, queue, keyStore }: TMain) => {
|
||||
const appCfg = getConfig();
|
||||
const server = fasitfy({
|
||||
logger,
|
||||
logger: appCfg.NODE_ENV === "test" ? false : logger,
|
||||
trustProxy: true,
|
||||
connectionTimeout: 30 * 1000,
|
||||
ignoreTrailingSlash: true
|
||||
@@ -70,7 +72,7 @@ export const main = async ({ db, smtp, logger, queue }: TMain) => {
|
||||
}
|
||||
await server.register(helmet, { contentSecurityPolicy: false });
|
||||
|
||||
await server.register(registerRoutes, { smtp, queue, db });
|
||||
await server.register(registerRoutes, { smtp, queue, db, keyStore });
|
||||
|
||||
if (appCfg.isProductionMode) {
|
||||
await server.register(registerExternalNextjs, {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
|
||||
import { ActorType } from "@app/services/auth/auth-type";
|
||||
|
||||
// this is a unique id for sending posthog event
|
||||
export const getTelemetryDistinctId = (req: FastifyRequest) => {
|
||||
if (req.auth.actor === ActorType.USER) {
|
||||
return req.auth.user.email;
|
||||
}
|
||||
if (req.auth.actor === ActorType.IDENTITY) {
|
||||
return `identity-${req.auth.identityId}`;
|
||||
}
|
||||
if (req.auth.actor === ActorType.SERVICE) {
|
||||
return req.auth.serviceToken.createdByEmail || `service-token-null-creator-${req.auth.serviceTokenId}`; // when user gets removed from system
|
||||
}
|
||||
return "unknown-auth-data";
|
||||
};
|
||||
@@ -63,6 +63,11 @@ export const injectAuditLogInfo = fp(async (server: FastifyZodProvider) => {
|
||||
identityId: req.auth.identityId
|
||||
}
|
||||
};
|
||||
} else if (req.auth.actor === ActorType.SCIM_CLIENT) {
|
||||
payload.actor = {
|
||||
type: ActorType.SCIM_CLIENT,
|
||||
metadata: {}
|
||||
};
|
||||
} else {
|
||||
throw new BadRequestError({ message: "Missing logic for other actor" });
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import fp from "fastify-plugin";
|
||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||
|
||||
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";
|
||||
@@ -26,7 +27,7 @@ export type TAuthMode =
|
||||
}
|
||||
| {
|
||||
authMode: AuthMode.SERVICE_TOKEN;
|
||||
serviceToken: TServiceTokens;
|
||||
serviceToken: TServiceTokens & { createdByEmail: string };
|
||||
actor: ActorType.SERVICE;
|
||||
serviceTokenId: string;
|
||||
}
|
||||
@@ -35,6 +36,12 @@ export type TAuthMode =
|
||||
actor: ActorType.IDENTITY;
|
||||
identityId: string;
|
||||
identityName: string;
|
||||
}
|
||||
| {
|
||||
authMode: AuthMode.SCIM_TOKEN;
|
||||
actor: ActorType.SCIM_CLIENT;
|
||||
scimTokenId: string;
|
||||
orgId: string;
|
||||
};
|
||||
|
||||
const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
||||
@@ -55,6 +62,7 @@ const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
||||
}
|
||||
|
||||
const decodedToken = jwt.verify(authTokenValue, jwtSecret) as JwtPayload;
|
||||
|
||||
switch (decodedToken.authTokenType) {
|
||||
case AuthTokenType.ACCESS_TOKEN:
|
||||
return {
|
||||
@@ -70,6 +78,12 @@ const extractAuth = async (req: FastifyRequest, jwtSecret: string) => {
|
||||
token: decodedToken as TIdentityAccessTokenJwtPayload,
|
||||
actor: ActorType.IDENTITY
|
||||
} as const;
|
||||
case AuthTokenType.SCIM_TOKEN:
|
||||
return {
|
||||
authMode: AuthMode.SCIM_TOKEN,
|
||||
token: decodedToken as TScimTokenJwtPayload,
|
||||
actor: ActorType.SCIM_CLIENT
|
||||
} as const;
|
||||
default:
|
||||
return { authMode: null, token: null } as const;
|
||||
}
|
||||
@@ -113,6 +127,11 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||
req.auth = { authMode: AuthMode.API_KEY as const, userId: user.id, actor, user };
|
||||
break;
|
||||
}
|
||||
case AuthMode.SCIM_TOKEN: {
|
||||
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
|
||||
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId };
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new UnauthorizedError({ name: "Unknown token strategy" });
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ export const injectPermission = fp(async (server) => {
|
||||
req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId };
|
||||
} else if (req.auth.actor === ActorType.SERVICE) {
|
||||
req.permission = { type: ActorType.SERVICE, id: req.auth.serviceTokenId };
|
||||
} else if (req.auth.actor === ActorType.SCIM_CLIENT) {
|
||||
req.permission = { type: ActorType.SCIM_CLIENT, id: req.auth.scimTokenId, orgId: req.auth.orgId };
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,13 @@ import { ForbiddenError } from "@casl/ability";
|
||||
import fastifyPlugin from "fastify-plugin";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import { BadRequestError, DatabaseError, InternalServerError, UnauthorizedError } from "@app/lib/errors";
|
||||
import {
|
||||
BadRequestError,
|
||||
DatabaseError,
|
||||
InternalServerError,
|
||||
ScimRequestError,
|
||||
UnauthorizedError
|
||||
} from "@app/lib/errors";
|
||||
|
||||
export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider) => {
|
||||
server.setErrorHandler((error, req, res) => {
|
||||
@@ -21,6 +27,12 @@ export const fastifyErrHandler = fastifyPlugin(async (server: FastifyZodProvider
|
||||
error: "PermissionDenied",
|
||||
message: `You are not allowed to ${error.action} on ${error.subjectType}`
|
||||
});
|
||||
} else if (error instanceof ScimRequestError) {
|
||||
void res.status(error.status).send({
|
||||
schemas: error.schemas,
|
||||
status: error.status,
|
||||
detail: error.detail
|
||||
});
|
||||
} else {
|
||||
void res.send(error);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ import { permissionDALFactory } from "@app/ee/services/permission/permission-dal
|
||||
import { permissionServiceFactory } from "@app/ee/services/permission/permission-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";
|
||||
import { scimServiceFactory } from "@app/ee/services/scim/scim-service";
|
||||
import { secretApprovalPolicyApproverDALFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-approver-dal";
|
||||
import { secretApprovalPolicyDALFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-dal";
|
||||
import { secretApprovalPolicyServiceFactory } from "@app/ee/services/secret-approval-policy/secret-approval-policy-service";
|
||||
@@ -32,6 +34,7 @@ import { snapshotFolderDALFactory } from "@app/ee/services/secret-snapshot/snaps
|
||||
import { snapshotSecretDALFactory } from "@app/ee/services/secret-snapshot/snapshot-secret-dal";
|
||||
import { trustedIpDALFactory } from "@app/ee/services/trusted-ip/trusted-ip-dal";
|
||||
import { trustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { TQueueServiceFactory } from "@app/queue";
|
||||
import { apiKeyDALFactory } from "@app/services/api-key/api-key-dal";
|
||||
@@ -63,6 +66,7 @@ import { orgRoleDALFactory } from "@app/services/org/org-role-dal";
|
||||
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
|
||||
import { orgServiceFactory } from "@app/services/org/org-service";
|
||||
import { projectDALFactory } from "@app/services/project/project-dal";
|
||||
import { projectQueueFactory } from "@app/services/project/project-queue";
|
||||
import { projectServiceFactory } from "@app/services/project/project-service";
|
||||
import { projectBotDALFactory } from "@app/services/project-bot/project-bot-dal";
|
||||
import { projectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
||||
@@ -93,6 +97,8 @@ import { serviceTokenServiceFactory } from "@app/services/service-token/service-
|
||||
import { TSmtpService } from "@app/services/smtp/smtp-service";
|
||||
import { superAdminDALFactory } from "@app/services/super-admin/super-admin-dal";
|
||||
import { getServerCfg, superAdminServiceFactory } from "@app/services/super-admin/super-admin-service";
|
||||
import { telemetryDALFactory } from "@app/services/telemetry/telemetry-dal";
|
||||
import { telemetryQueueServiceFactory } from "@app/services/telemetry/telemetry-queue";
|
||||
import { telemetryServiceFactory } from "@app/services/telemetry/telemetry-service";
|
||||
import { userDALFactory } from "@app/services/user/user-dal";
|
||||
import { userServiceFactory } from "@app/services/user/user-service";
|
||||
@@ -109,7 +115,12 @@ import { registerV3Routes } from "./v3";
|
||||
|
||||
export const registerRoutes = async (
|
||||
server: FastifyZodProvider,
|
||||
{ db, smtp: smtpService, queue: queueService }: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory }
|
||||
{
|
||||
db,
|
||||
smtp: smtpService,
|
||||
queue: queueService,
|
||||
keyStore
|
||||
}: { db: Knex; smtp: TSmtpService; queue: TQueueServiceFactory; keyStore: TKeyStoreFactory }
|
||||
) => {
|
||||
await server.register(registerSecretScannerGhApp, { prefix: "/ss-webhook" });
|
||||
|
||||
@@ -155,6 +166,8 @@ export const registerRoutes = async (
|
||||
|
||||
const auditLogDAL = auditLogDALFactory(db);
|
||||
const trustedIpDAL = trustedIpDALFactory(db);
|
||||
const scimDAL = scimDALFactory(db);
|
||||
const telemetryDAL = telemetryDALFactory(db);
|
||||
|
||||
// ee db layer ops
|
||||
const permissionDAL = permissionDALFactory(db);
|
||||
@@ -181,13 +194,14 @@ export const registerRoutes = async (
|
||||
projectRoleDAL,
|
||||
serviceTokenDAL
|
||||
});
|
||||
const licenseService = licenseServiceFactory({ permissionService, orgDAL, licenseDAL });
|
||||
const licenseService = licenseServiceFactory({ permissionService, orgDAL, licenseDAL, keyStore });
|
||||
const trustedIpService = trustedIpServiceFactory({
|
||||
licenseService,
|
||||
projectDAL,
|
||||
trustedIpDAL,
|
||||
permissionService
|
||||
});
|
||||
|
||||
const auditLogQueue = auditLogQueueServiceFactory({
|
||||
auditLogDAL,
|
||||
queueService,
|
||||
@@ -210,8 +224,27 @@ export const registerRoutes = async (
|
||||
samlConfigDAL,
|
||||
licenseService
|
||||
});
|
||||
const scimService = scimServiceFactory({
|
||||
licenseService,
|
||||
scimDAL,
|
||||
userDAL,
|
||||
orgDAL,
|
||||
projectDAL,
|
||||
projectMembershipDAL,
|
||||
permissionService,
|
||||
smtpService
|
||||
});
|
||||
|
||||
const telemetryService = telemetryServiceFactory({
|
||||
keyStore,
|
||||
licenseService
|
||||
});
|
||||
const telemetryQueue = telemetryQueueServiceFactory({
|
||||
keyStore,
|
||||
telemetryDAL,
|
||||
queueService
|
||||
});
|
||||
|
||||
const telemetryService = telemetryServiceFactory();
|
||||
const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL });
|
||||
const userService = userServiceFactory({ userDAL });
|
||||
const loginService = authLoginServiceFactory({ userDAL, smtpService, tokenService });
|
||||
@@ -230,6 +263,8 @@ export const registerRoutes = async (
|
||||
incidentContactDAL,
|
||||
tokenService,
|
||||
projectDAL,
|
||||
projectMembershipDAL,
|
||||
projectKeyDAL,
|
||||
smtpService,
|
||||
userDAL,
|
||||
orgBotDAL
|
||||
@@ -248,7 +283,8 @@ export const registerRoutes = async (
|
||||
userDAL,
|
||||
authService: loginService,
|
||||
serverCfgDAL: superAdminDAL,
|
||||
orgService
|
||||
orgService,
|
||||
keyStore
|
||||
});
|
||||
const apiKeyService = apiKeyServiceFactory({ apiKeyDAL, userDAL });
|
||||
|
||||
@@ -266,19 +302,13 @@ export const registerRoutes = async (
|
||||
secretScanningDAL,
|
||||
secretScanningQueue
|
||||
});
|
||||
const projectService = projectServiceFactory({
|
||||
permissionService,
|
||||
projectDAL,
|
||||
secretBlindIndexDAL,
|
||||
projectEnvDAL,
|
||||
projectMembershipDAL,
|
||||
folderDAL,
|
||||
licenseService
|
||||
});
|
||||
const projectBotService = projectBotServiceFactory({ permissionService, projectBotDAL, projectDAL });
|
||||
|
||||
const projectMembershipService = projectMembershipServiceFactory({
|
||||
projectMembershipDAL,
|
||||
projectDAL,
|
||||
permissionService,
|
||||
projectBotDAL,
|
||||
orgDAL,
|
||||
userDAL,
|
||||
smtpService,
|
||||
@@ -286,6 +316,46 @@ export const registerRoutes = async (
|
||||
projectRoleDAL,
|
||||
licenseService
|
||||
});
|
||||
const projectKeyService = projectKeyServiceFactory({
|
||||
permissionService,
|
||||
projectKeyDAL,
|
||||
projectMembershipDAL
|
||||
});
|
||||
|
||||
const projectQueueService = projectQueueFactory({
|
||||
queueService,
|
||||
secretDAL,
|
||||
folderDAL,
|
||||
projectDAL,
|
||||
orgDAL,
|
||||
integrationAuthDAL,
|
||||
orgService,
|
||||
projectEnvDAL,
|
||||
userDAL,
|
||||
secretVersionDAL,
|
||||
projectKeyDAL,
|
||||
projectBotDAL,
|
||||
projectMembershipDAL,
|
||||
secretApprovalRequestDAL,
|
||||
secretApprovalSecretDAL: sarSecretDAL
|
||||
});
|
||||
|
||||
const projectService = projectServiceFactory({
|
||||
permissionService,
|
||||
projectDAL,
|
||||
projectQueue: projectQueueService,
|
||||
secretBlindIndexDAL,
|
||||
identityProjectDAL,
|
||||
identityOrgMembershipDAL,
|
||||
projectBotDAL,
|
||||
projectKeyDAL,
|
||||
userDAL,
|
||||
projectEnvDAL,
|
||||
orgService,
|
||||
projectMembershipDAL,
|
||||
folderDAL,
|
||||
licenseService
|
||||
});
|
||||
const projectEnvService = projectEnvServiceFactory({
|
||||
permissionService,
|
||||
projectEnvDAL,
|
||||
@@ -293,11 +363,7 @@ export const registerRoutes = async (
|
||||
projectDAL,
|
||||
folderDAL
|
||||
});
|
||||
const projectKeyService = projectKeyServiceFactory({
|
||||
permissionService,
|
||||
projectKeyDAL,
|
||||
projectMembershipDAL
|
||||
});
|
||||
|
||||
const projectRoleService = projectRoleServiceFactory({ permissionService, projectRoleDAL });
|
||||
|
||||
const snapshotService = secretSnapshotServiceFactory({
|
||||
@@ -332,9 +398,9 @@ export const registerRoutes = async (
|
||||
folderDAL,
|
||||
permissionService,
|
||||
secretImportDAL,
|
||||
projectDAL,
|
||||
secretDAL
|
||||
});
|
||||
const projectBotService = projectBotServiceFactory({ permissionService, projectBotDAL });
|
||||
const integrationAuthService = integrationAuthServiceFactory({
|
||||
integrationAuthDAL,
|
||||
integrationDAL,
|
||||
@@ -355,7 +421,11 @@ export const registerRoutes = async (
|
||||
orgDAL,
|
||||
projectMembershipDAL,
|
||||
smtpService,
|
||||
projectDAL
|
||||
projectDAL,
|
||||
secretVersionDAL,
|
||||
secretBlindIndexDAL,
|
||||
secretTagDAL,
|
||||
secretVersionTagDAL,
|
||||
});
|
||||
const secretBlindIndexService = secretBlindIndexServiceFactory({
|
||||
permissionService,
|
||||
@@ -368,6 +438,7 @@ export const registerRoutes = async (
|
||||
secretVersionTagDAL,
|
||||
secretBlindIndexDAL,
|
||||
permissionService,
|
||||
projectDAL,
|
||||
secretDAL,
|
||||
secretTagDAL,
|
||||
snapshotService,
|
||||
@@ -378,14 +449,17 @@ export const registerRoutes = async (
|
||||
const sarService = secretApprovalRequestServiceFactory({
|
||||
permissionService,
|
||||
folderDAL,
|
||||
secretDAL,
|
||||
secretTagDAL,
|
||||
secretApprovalRequestSecretDAL: sarSecretDAL,
|
||||
secretApprovalRequestReviewerDAL: sarReviewerDAL,
|
||||
projectDAL,
|
||||
secretVersionDAL,
|
||||
secretBlindIndexDAL,
|
||||
secretApprovalRequestDAL,
|
||||
secretService,
|
||||
snapshotService,
|
||||
secretVersionTagDAL,
|
||||
secretQueueService
|
||||
});
|
||||
const secretRotationQueue = secretRotationQueueFactory({
|
||||
@@ -444,9 +518,13 @@ export const registerRoutes = async (
|
||||
});
|
||||
|
||||
await superAdminService.initServerCfg();
|
||||
await auditLogQueue.startAuditLogPruneJob();
|
||||
//
|
||||
// setup the communication with license key server
|
||||
await licenseService.init();
|
||||
|
||||
await auditLogQueue.startAuditLogPruneJob();
|
||||
await telemetryQueue.startTelemetryCheck();
|
||||
|
||||
// inject all services
|
||||
server.decorate<FastifyZodProvider["services"]>("services", {
|
||||
login: loginService,
|
||||
@@ -486,6 +564,7 @@ export const registerRoutes = async (
|
||||
secretScanning: secretScanningService,
|
||||
license: licenseService,
|
||||
trustedIp: trustedIpService,
|
||||
scim: scimService,
|
||||
secretBlindIndex: secretBlindIndexService,
|
||||
telemetry: telemetryService
|
||||
});
|
||||
@@ -537,4 +616,8 @@ export const registerRoutes = async (
|
||||
);
|
||||
await server.register(registerV2Routes, { prefix: "/api/v2" });
|
||||
await server.register(registerV3Routes, { prefix: "/api/v3" });
|
||||
|
||||
server.addHook("onClose", async () => {
|
||||
await telemetryService.flushAll();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { SuperAdminSchema, UsersSchema } from "@app/db/schemas";
|
||||
import { OrganizationsSchema, SuperAdminSchema, UsersSchema } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { UnauthorizedError } from "@app/lib/errors";
|
||||
import { verifySuperAdmin } from "@app/server/plugins/auth/superAdmin";
|
||||
@@ -16,7 +16,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
schema: {
|
||||
response: {
|
||||
200: z.object({
|
||||
config: SuperAdminSchema
|
||||
config: SuperAdminSchema.omit({ createdAt: true, updatedAt: true })
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -31,7 +31,8 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
method: "PATCH",
|
||||
schema: {
|
||||
body: z.object({
|
||||
allowSignUp: z.boolean().optional()
|
||||
allowSignUp: z.boolean().optional(),
|
||||
allowedSignUpDomain: z.string().optional().nullable()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
@@ -72,6 +73,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
200: z.object({
|
||||
message: z.string(),
|
||||
user: UsersSchema,
|
||||
organization: OrganizationsSchema,
|
||||
token: z.string(),
|
||||
new: z.string()
|
||||
})
|
||||
@@ -82,13 +84,13 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
const serverCfg = await getServerCfg();
|
||||
if (serverCfg.initialized)
|
||||
throw new UnauthorizedError({ name: "Admin sign up", message: "Admin has been created" });
|
||||
const { user, token } = await server.services.superAdmin.adminSignUp({
|
||||
const { user, token, organization } = await server.services.superAdmin.adminSignUp({
|
||||
...req.body,
|
||||
ip: req.realIp,
|
||||
userAgent: req.headers["user-agent"] || ""
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.AdminInit,
|
||||
distinctId: user.user.email,
|
||||
properties: {
|
||||
@@ -109,6 +111,7 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
message: "Successfully set up admin account",
|
||||
user: user.user,
|
||||
token: token.access,
|
||||
organization,
|
||||
new: "123"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,14 +2,16 @@ import { z } from "zod";
|
||||
|
||||
import { IdentitiesSchema, OrgMembershipRole } from "@app/db/schemas";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
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 { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Create identity",
|
||||
security: [
|
||||
@@ -49,6 +51,17 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.MachineIdentityCreated,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
orgId: req.body.organizationId,
|
||||
name: identity.name,
|
||||
identityId: identity.id,
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
|
||||
return { identity };
|
||||
}
|
||||
});
|
||||
@@ -56,7 +69,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "PATCH",
|
||||
url: "/:identityId",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Update identity",
|
||||
security: [
|
||||
@@ -105,7 +118,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "DELETE",
|
||||
url: "/:identityId",
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
schema: {
|
||||
description: "Delete identity",
|
||||
security: [
|
||||
|
||||
@@ -39,11 +39,12 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { identityUa, accessToken, identityAccessToken, validClientSecretInfo } =
|
||||
const { identityUa, accessToken, identityAccessToken, validClientSecretInfo, identityMembershipOrg } =
|
||||
await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: identityMembershipOrg?.orgId,
|
||||
event: {
|
||||
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH,
|
||||
metadata: {
|
||||
|
||||
@@ -48,6 +48,7 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
||||
await projectRouter.register(registerProjectMembershipRouter);
|
||||
await projectRouter.register(registerSecretTagRouter);
|
||||
},
|
||||
|
||||
{ prefix: "/workspace" }
|
||||
);
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@ import { z } from "zod";
|
||||
import { IntegrationsSchema } from "@app/db/schemas";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { removeTrailingSlash, shake } from "@app/lib/fn";
|
||||
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 { PostHogEventTypes, TIntegrationCreatedEvent } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
@@ -30,6 +32,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
||||
.object({
|
||||
secretPrefix: z.string().optional(),
|
||||
secretSuffix: z.string().optional(),
|
||||
syncBehavior: z.string().optional(),
|
||||
secretGCPLabel: z
|
||||
.object({
|
||||
labelName: z.string(),
|
||||
@@ -53,28 +56,40 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
|
||||
actorOrgId: req.permission.orgId,
|
||||
...req.body
|
||||
});
|
||||
|
||||
const createIntegrationEventProperty = shake({
|
||||
integrationId: integration.id.toString(),
|
||||
integration: integration.integration,
|
||||
environment: req.body.sourceEnvironment,
|
||||
secretPath: req.body.secretPath,
|
||||
url: integration.url,
|
||||
app: integration.app,
|
||||
appId: integration.appId,
|
||||
targetEnvironment: integration.targetEnvironment,
|
||||
targetEnvironmentId: integration.targetEnvironmentId,
|
||||
targetService: integration.targetService,
|
||||
targetServiceId: integration.targetServiceId,
|
||||
path: integration.path,
|
||||
region: integration.region
|
||||
}) as TIntegrationCreatedEvent["properties"];
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
projectId: integrationAuth.projectId,
|
||||
event: {
|
||||
type: EventType.CREATE_INTEGRATION,
|
||||
// eslint-disable-next-line
|
||||
metadata: shake({
|
||||
integrationId: integration.id.toString(),
|
||||
integration: integration.integration,
|
||||
environment: req.body.sourceEnvironment,
|
||||
secretPath: req.body.secretPath,
|
||||
url: integration.url,
|
||||
app: integration.app,
|
||||
appId: integration.appId,
|
||||
targetEnvironment: integration.targetEnvironment,
|
||||
targetEnvironmentId: integration.targetEnvironmentId,
|
||||
targetService: integration.targetService,
|
||||
targetServiceId: integration.targetServiceId,
|
||||
path: integration.path,
|
||||
region: integration.region
|
||||
// eslint-disable-next-line
|
||||
}) as any
|
||||
metadata: createIntegrationEventProperty
|
||||
}
|
||||
});
|
||||
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.IntegrationCreated,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
...createIntegrationEventProperty,
|
||||
projectId: integrationAuth.projectId,
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
return { integration };
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { UsersSchema } from "@app/db/schemas";
|
||||
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";
|
||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
@@ -30,6 +32,15 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
|
||||
actorOrgId: req.permission.orgId
|
||||
});
|
||||
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.UserOrgInvitation,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
inviteeEmail: req.body.inviteeEmail,
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
completeInviteLink,
|
||||
message: `Send an invite link to ${req.body.inviteeEmail}`
|
||||
|
||||
@@ -87,13 +87,15 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
schema: {
|
||||
params: z.object({ organizationId: z.string().trim() }),
|
||||
body: z.object({
|
||||
name: z.string().trim().optional(),
|
||||
name: z.string().trim().max(64, { message: "Name must be 64 or fewer characters" }).optional(),
|
||||
slug: z
|
||||
.string()
|
||||
.trim()
|
||||
.regex(/^[a-zA-Z0-9-]+$/, "Name must only contain alphanumeric characters or hyphens")
|
||||
.max(64, { message: "Slug must be 64 or fewer characters" })
|
||||
.regex(/^[a-zA-Z0-9-]+$/, "Slug must only contain alphanumeric characters or hyphens")
|
||||
.optional(),
|
||||
authEnforced: z.boolean().optional()
|
||||
authEnforced: z.boolean().optional(),
|
||||
scimEnabled: z.boolean().optional()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { OrgMembershipsSchema, ProjectMembershipsSchema, UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas";
|
||||
import {
|
||||
OrgMembershipsSchema,
|
||||
ProjectMembershipRole,
|
||||
ProjectMembershipsSchema,
|
||||
UserEncryptionKeysSchema,
|
||||
UsersSchema
|
||||
} from "@app/db/schemas";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
@@ -80,7 +86,10 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId,
|
||||
members: req.body.members
|
||||
members: req.body.members.map((member) => ({
|
||||
...member,
|
||||
projectRole: ProjectMembershipRole.Member
|
||||
}))
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
|
||||
@@ -2,13 +2,11 @@ import { z } from "zod";
|
||||
|
||||
import {
|
||||
IntegrationsSchema,
|
||||
ProjectKeysSchema,
|
||||
ProjectMembershipsSchema,
|
||||
ProjectsSchema,
|
||||
UserEncryptionKeysSchema,
|
||||
UsersSchema
|
||||
} from "@app/db/schemas";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
@@ -119,7 +117,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.SERVICE_TOKEN, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const workspace = await server.services.project.getAProject({
|
||||
actorId: req.permission.id,
|
||||
@@ -171,7 +169,7 @@ 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.deleteProject({
|
||||
actorId: req.permission.id,
|
||||
@@ -216,6 +214,41 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
url: "/:workspaceId",
|
||||
method: "PATCH",
|
||||
schema: {
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim()
|
||||
}),
|
||||
body: z.object({
|
||||
name: z.string().trim().max(64, { message: "Name must be 64 or fewer characters" }).optional(),
|
||||
autoCapitalization: z.boolean().optional()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
workspace: ProjectsSchema
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
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,
|
||||
update: {
|
||||
name: req.body.name,
|
||||
autoCapitalization: req.body.autoCapitalization
|
||||
}
|
||||
});
|
||||
return {
|
||||
workspace
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
url: "/:workspaceId/auto-capitalization",
|
||||
method: "POST",
|
||||
@@ -249,48 +282,6 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
url: "/:workspaceId/invite-signup",
|
||||
method: "POST",
|
||||
schema: {
|
||||
params: z.object({
|
||||
workspaceId: z.string().trim()
|
||||
}),
|
||||
body: z.object({
|
||||
email: z.string().trim()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
invitee: UsersSchema,
|
||||
latestKey: ProjectKeysSchema.optional()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
handler: async (req) => {
|
||||
const { invitee, latestKey } = await server.services.projectMembership.inviteUserToProject({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId,
|
||||
email: req.body.email
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
projectId: req.params.workspaceId,
|
||||
event: {
|
||||
type: EventType.ADD_WORKSPACE_MEMBER,
|
||||
metadata: {
|
||||
userId: invitee.id,
|
||||
email: invitee.email
|
||||
}
|
||||
}
|
||||
});
|
||||
return { invitee, latestKey };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
url: "/:workspaceId/integrations",
|
||||
method: "GET",
|
||||
|
||||
@@ -18,7 +18,6 @@ import { BadRequestError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { fetchGithubEmails } from "@app/lib/requests/github";
|
||||
import { AuthMethod } from "@app/services/auth/auth-type";
|
||||
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
||||
|
||||
export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
const appCfg = getConfig();
|
||||
@@ -42,7 +41,6 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
async (req, _accessToken, _refreshToken, profile, cb) => {
|
||||
try {
|
||||
const email = profile?.emails?.[0]?.value;
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!email)
|
||||
throw new BadRequestError({
|
||||
message: "Email not found",
|
||||
@@ -54,8 +52,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
firstName: profile?.name?.givenName || "",
|
||||
lastName: profile?.name?.familyName || "",
|
||||
authMethod: AuthMethod.GOOGLE,
|
||||
callbackPort: req.query.state as string,
|
||||
isSignupAllowed: Boolean(serverCfg.allowSignUp)
|
||||
callbackPort: req.query.state as string
|
||||
});
|
||||
cb(null, { isUserCompleted, providerAuthToken });
|
||||
} catch (error) {
|
||||
@@ -84,14 +81,12 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
try {
|
||||
const ghEmails = await fetchGithubEmails(accessToken);
|
||||
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
|
||||
const serverCfg = await getServerCfg();
|
||||
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
||||
email,
|
||||
firstName: profile.displayName,
|
||||
lastName: "",
|
||||
authMethod: AuthMethod.GITHUB,
|
||||
callbackPort: req.query.state as string,
|
||||
isSignupAllowed: Boolean(serverCfg.allowSignUp)
|
||||
callbackPort: req.query.state as string
|
||||
});
|
||||
return cb(null, { isUserCompleted, providerAuthToken });
|
||||
} catch (error) {
|
||||
@@ -120,14 +115,12 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
|
||||
try {
|
||||
const email = profile.emails[0].value;
|
||||
const serverCfg = await getServerCfg();
|
||||
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
||||
email,
|
||||
firstName: profile.displayName,
|
||||
lastName: "",
|
||||
authMethod: AuthMethod.GITLAB,
|
||||
callbackPort: req.query.state as string,
|
||||
isSignupAllowed: Boolean(serverCfg.allowSignUp)
|
||||
callbackPort: req.query.state as string
|
||||
});
|
||||
|
||||
return cb(null, { isUserCompleted, providerAuthToken });
|
||||
|
||||
@@ -2,6 +2,7 @@ import { registerIdentityOrgRouter } from "./identity-org-router";
|
||||
import { registerIdentityProjectRouter } from "./identity-project-router";
|
||||
import { registerMfaRouter } from "./mfa-router";
|
||||
import { registerOrgRouter } from "./organization-router";
|
||||
import { registerProjectMembershipRouter } from "./project-membership-router";
|
||||
import { registerProjectRouter } from "./project-router";
|
||||
import { registerServiceTokenRouter } from "./service-token-router";
|
||||
import { registerUserRouter } from "./user-router";
|
||||
@@ -21,6 +22,7 @@ export const registerV2Routes = async (server: FastifyZodProvider) => {
|
||||
async (projectServer) => {
|
||||
await projectServer.register(registerProjectRouter);
|
||||
await projectServer.register(registerIdentityProjectRouter);
|
||||
await projectServer.register(registerProjectMembershipRouter);
|
||||
},
|
||||
{ prefix: "/workspace" }
|
||||
);
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { ProjectMembershipsSchema } from "@app/db/schemas";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
export const registerProjectMembershipRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/:projectId/memberships",
|
||||
schema: {
|
||||
params: z.object({
|
||||
projectId: z.string().describe("The ID of the project.")
|
||||
}),
|
||||
body: z.object({
|
||||
emails: z.string().email().array().describe("Emails of the users to add to the project.")
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
memberships: ProjectMembershipsSchema.array()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const memberships = await server.services.projectMembership.addUsersToProjectNonE2EE({
|
||||
projectId: req.params.projectId,
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
emails: req.body.emails
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
projectId: req.params.projectId,
|
||||
...req.auditLogInfo,
|
||||
event: {
|
||||
type: EventType.ADD_BATCH_WORKSPACE_MEMBER,
|
||||
metadata: memberships.map(({ userId, id }) => ({
|
||||
userId: userId || "",
|
||||
membershipId: id,
|
||||
email: ""
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
return { memberships };
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "DELETE",
|
||||
url: "/:projectId/memberships",
|
||||
schema: {
|
||||
params: z.object({
|
||||
projectId: z.string().describe("The ID of the project.")
|
||||
}),
|
||||
|
||||
body: z.object({
|
||||
emails: z.string().email().array().describe("Emails of the users to remove from the project.")
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
memberships: ProjectMembershipsSchema.array()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const memberships = await server.services.projectMembership.deleteProjectMemberships({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId,
|
||||
projectId: req.params.projectId,
|
||||
emails: req.body.emails
|
||||
});
|
||||
|
||||
for (const membership of memberships) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
projectId: req.params.projectId,
|
||||
event: {
|
||||
type: EventType.REMOVE_WORKSPACE_MEMBER,
|
||||
metadata: {
|
||||
userId: membership.userId,
|
||||
email: ""
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return { memberships };
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,11 +1,23 @@
|
||||
import slugify from "@sindresorhus/slugify";
|
||||
import { z } from "zod";
|
||||
|
||||
import { ProjectKeysSchema } from "@app/db/schemas";
|
||||
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 { getTelemetryDistinctId } from "@app/server/lib/telemetry";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
import { AuthMode } from "@app/services/auth/auth-type";
|
||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
const projectWithEnv = ProjectsSchema.merge(
|
||||
z.object({
|
||||
_id: z.string(),
|
||||
environments: z.object({ name: z.string(), slug: z.string(), id: z.string() }).array()
|
||||
})
|
||||
);
|
||||
|
||||
export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
/* Get project key */
|
||||
server.route({
|
||||
url: "/:workspaceId/encrypted-key",
|
||||
method: "GET",
|
||||
@@ -34,8 +46,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
const key = await server.services.projectKey.getLatestProjectKey({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
projectId: req.params.workspaceId,
|
||||
actorOrgId: req.permission.orgId
|
||||
actorOrgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
@@ -52,4 +64,107 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
return key;
|
||||
}
|
||||
});
|
||||
|
||||
/* Start upgrade of a project */
|
||||
server.route({
|
||||
url: "/:projectId/upgrade",
|
||||
method: "POST",
|
||||
schema: {
|
||||
params: z.object({
|
||||
projectId: z.string().trim()
|
||||
}),
|
||||
|
||||
body: z.object({
|
||||
userPrivateKey: z.string().trim()
|
||||
}),
|
||||
response: {
|
||||
200: z.void()
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||
handler: async (req) => {
|
||||
await server.services.project.upgradeProject({
|
||||
actorId: req.permission.id,
|
||||
actor: req.permission.type,
|
||||
projectId: req.params.projectId,
|
||||
userPrivateKey: req.body.userPrivateKey
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/* Get upgrade status of project */
|
||||
server.route({
|
||||
url: "/:projectId/upgrade/status",
|
||||
method: "GET",
|
||||
schema: {
|
||||
params: z.object({
|
||||
projectId: z.string().trim()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
status: z.string().nullable()
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||
handler: async (req) => {
|
||||
const status = await server.services.project.getProjectUpgradeStatus({
|
||||
projectId: req.params.projectId,
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id
|
||||
});
|
||||
|
||||
return { status };
|
||||
}
|
||||
});
|
||||
|
||||
/* Create new project */
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/",
|
||||
config: {
|
||||
rateLimit: authRateLimit
|
||||
},
|
||||
schema: {
|
||||
body: z.object({
|
||||
projectName: z.string().trim(),
|
||||
slug: z
|
||||
.string()
|
||||
.min(5)
|
||||
.max(36)
|
||||
.refine((v) => slugify(v) === v, {
|
||||
message: "Slug must be a valid slug"
|
||||
})
|
||||
.optional(),
|
||||
organizationId: z.string().trim()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
project: projectWithEnv
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, 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,
|
||||
workspaceName: req.body.projectName,
|
||||
slug: req.body.slug
|
||||
});
|
||||
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.ProjectCreated,
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
orgId: req.body.organizationId,
|
||||
name: project.name,
|
||||
...req.auditLogInfo
|
||||
}
|
||||
});
|
||||
|
||||
return { project };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -197,7 +197,7 @@ export const registerUserRouter = async (server: FastifyZodProvider) => {
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: verifyAuth([AuthMode.JWT]),
|
||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY]),
|
||||
handler: async (req) => {
|
||||
const user = await server.services.user.getMe(req.permission.id);
|
||||
return { user };
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { FastifyRequest } from "fastify";
|
||||
import picomatch from "picomatch";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -13,6 +12,7 @@ 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 { BadRequestError } from "@app/lib/errors";
|
||||
import { removeTrailingSlash } from "@app/lib/fn";
|
||||
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";
|
||||
@@ -20,19 +20,6 @@ import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
import { secretRawSchema } from "../sanitizedSchemas";
|
||||
|
||||
const getDistinctId = (req: FastifyRequest) => {
|
||||
if (req.auth.actor === ActorType.USER) {
|
||||
return req.auth.user.email;
|
||||
}
|
||||
if (req.auth.actor === ActorType.IDENTITY) {
|
||||
return `identity-${req.auth.identityId}`;
|
||||
}
|
||||
if (req.auth.actor === ActorType.SERVICE) {
|
||||
return `service-token-${req.auth.serviceToken.id}`;
|
||||
}
|
||||
return "unknown-auth-data";
|
||||
};
|
||||
|
||||
export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
server.route({
|
||||
url: "/raw",
|
||||
@@ -108,9 +95,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secrets.length,
|
||||
workspaceId,
|
||||
@@ -198,9 +185,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId,
|
||||
@@ -274,9 +261,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretCreated,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -349,9 +336,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretUpdated,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -419,9 +406,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretDeleted,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -525,9 +512,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
(req.headers["user-agent"] !== "k8-operator" || shouldRecordK8Event);
|
||||
const approximateNumberTotalSecrets = secrets.length * 20;
|
||||
if (shouldCapture) {
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: shouldRecordK8Event ? approximateNumberTotalSecrets : secrets.length,
|
||||
workspaceId: req.query.workspaceId,
|
||||
@@ -602,9 +589,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretPulled,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId: req.query.workspaceId,
|
||||
@@ -765,9 +752,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretCreated,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -947,9 +934,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretUpdated,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -1065,9 +1052,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretDeleted,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: 1,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -1092,7 +1079,6 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
secrets: z
|
||||
.object({
|
||||
secretName: z.string().trim(),
|
||||
type: z.nativeEnum(SecretType).default(SecretType.Shared),
|
||||
secretKeyCiphertext: z.string().trim(),
|
||||
secretKeyIV: z.string().trim(),
|
||||
secretKeyTag: z.string().trim(),
|
||||
@@ -1139,7 +1125,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
projectId,
|
||||
policy,
|
||||
data: {
|
||||
[CommitType.Create]: inputSecrets.filter(({ type }) => type === "shared")
|
||||
[CommitType.Create]: inputSecrets
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1186,9 +1172,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretCreated,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secrets.length,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -1306,9 +1292,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretUpdated,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secrets.length,
|
||||
workspaceId: req.body.workspaceId,
|
||||
@@ -1414,9 +1400,9 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.services.telemetry.sendPostHogEvents({
|
||||
await server.services.telemetry.sendPostHogEvents({
|
||||
event: PostHogEventTypes.SecretDeleted,
|
||||
distinctId: getDistinctId(req),
|
||||
distinctId: getTelemetryDistinctId(req),
|
||||
properties: {
|
||||
numberOfSecrets: secrets.length,
|
||||
workspaceId: req.body.workspaceId,
|
||||
|
||||
@@ -2,7 +2,9 @@ import { z } from "zod";
|
||||
|
||||
import { UsersSchema } from "@app/db/schemas";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { authRateLimit } from "@app/server/config/rateLimiter";
|
||||
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
||||
import { PostHogEventTypes } from "@app/services/telemetry/telemetry-types";
|
||||
|
||||
export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
@@ -23,8 +25,26 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
await server.services.signup.beginEmailSignupProcess(req.body.email);
|
||||
return { message: `Sent an email verification code to ${req.body.email}` };
|
||||
const { email } = req.body;
|
||||
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!serverCfg.allowSignUp) {
|
||||
throw new BadRequestError({
|
||||
message: "Sign up is disabled"
|
||||
});
|
||||
}
|
||||
|
||||
if (serverCfg?.allowedSignUpDomain) {
|
||||
const domain = email.split("@")[1];
|
||||
const allowedDomains = serverCfg.allowedSignUpDomain.split(",").map((e) => e.trim());
|
||||
if (!allowedDomains.includes(domain)) {
|
||||
throw new BadRequestError({
|
||||
message: `Email with a domain (@${domain}) is not supported`
|
||||
});
|
||||
}
|
||||
}
|
||||
await server.services.signup.beginEmailSignupProcess(email);
|
||||
return { message: `Sent an email verification code to ${email}` };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -48,6 +68,13 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!serverCfg.allowSignUp) {
|
||||
throw new BadRequestError({
|
||||
message: "Sign up is disabled"
|
||||
});
|
||||
}
|
||||
|
||||
const { token, user } = await server.services.signup.verifyEmailSignup(req.body.email, req.body.code);
|
||||
return { message: "Successfuly verified email", token, user };
|
||||
}
|
||||
@@ -90,6 +117,13 @@ export const registerSignupRouter = async (server: FastifyZodProvider) => {
|
||||
if (!userAgent) throw new Error("user agent header is required");
|
||||
const appCfg = getConfig();
|
||||
|
||||
const serverCfg = await getServerCfg();
|
||||
if (!serverCfg.allowSignUp) {
|
||||
throw new BadRequestError({
|
||||
message: "Sign up is disabled"
|
||||
});
|
||||
}
|
||||
|
||||
const { user, accessToken, refreshToken } = await server.services.signup.completeEmailAccountSignup({
|
||||
...req.body,
|
||||
ip: req.realIp,
|
||||
|
||||
Reference in New Issue
Block a user