fixed merge conflicts

This commit is contained in:
x
2025-04-28 10:52:12 -04:00
224 changed files with 5150 additions and 464 deletions
@@ -0,0 +1,24 @@
import { requestContext } from "@fastify/request-context";
import fp from "fastify-plugin";
import { AuthMode } from "@app/services/auth/auth-type";
export const injectAssumePrivilege = fp(async (server: FastifyZodProvider) => {
server.addHook("onRequest", async (req, res) => {
const assumeRoleCookie = req.cookies["infisical-project-assume-privileges"];
try {
if (req?.auth?.authMode === AuthMode.JWT && assumeRoleCookie) {
const decodedToken = server.services.assumePrivileges.verifyAssumePrivilegeToken(
assumeRoleCookie,
req.auth.tokenVersionId
);
if (decodedToken) {
requestContext.set("assumedPrivilegeDetails", decodedToken);
}
}
} catch (error) {
req.log.error({ error }, "Failed to verify assume privilege token");
void res.clearCookie("infisical-project-assume-privileges");
}
});
});
+30 -26
View File
@@ -12,6 +12,7 @@ import { accessApprovalPolicyServiceFactory } from "@app/ee/services/access-appr
import { accessApprovalRequestDALFactory } from "@app/ee/services/access-approval-request/access-approval-request-dal";
import { accessApprovalRequestReviewerDALFactory } from "@app/ee/services/access-approval-request/access-approval-request-reviewer-dal";
import { accessApprovalRequestServiceFactory } from "@app/ee/services/access-approval-request/access-approval-request-service";
import { assumePrivilegeServiceFactory } from "@app/ee/services/assume-privilege/assume-privilege-service";
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";
@@ -32,6 +33,8 @@ import { gatewayDALFactory } from "@app/ee/services/gateway/gateway-dal";
import { gatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
import { orgGatewayConfigDALFactory } from "@app/ee/services/gateway/org-gateway-config-dal";
import { projectGatewayDALFactory } from "@app/ee/services/gateway/project-gateway-dal";
import { githubOrgSyncDALFactory } from "@app/ee/services/github-org-sync/github-org-sync-dal";
import { githubOrgSyncServiceFactory } from "@app/ee/services/github-org-sync/github-org-sync-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";
@@ -214,6 +217,7 @@ import { secretFolderServiceFactory } from "@app/services/secret-folder/secret-f
import { secretFolderVersionDALFactory } from "@app/services/secret-folder/secret-folder-version-dal";
import { secretImportDALFactory } from "@app/services/secret-import/secret-import-dal";
import { secretImportServiceFactory } from "@app/services/secret-import/secret-import-service";
import { secretReminderRecipientsDALFactory } from "@app/services/secret-reminder-recipients/secret-reminder-recipients-dal";
import { secretSharingDALFactory } from "@app/services/secret-sharing/secret-sharing-dal";
import { secretSharingServiceFactory } from "@app/services/secret-sharing/secret-sharing-service";
import { secretSyncDALFactory } from "@app/services/secret-sync/secret-sync-dal";
@@ -248,6 +252,7 @@ import { workflowIntegrationDALFactory } from "@app/services/workflow-integratio
import { workflowIntegrationServiceFactory } from "@app/services/workflow-integration/workflow-integration-service";
import { injectAuditLogInfo } from "../plugins/audit-log";
import { injectAssumePrivilege } from "../plugins/auth/inject-assume-privilege";
import { injectIdentity } from "../plugins/auth/inject-identity";
import { injectPermission } from "../plugins/auth/inject-permission";
import { injectRateLimits } from "../plugins/inject-rate-limits";
@@ -417,6 +422,8 @@ export const registerRoutes = async (
const orgGatewayConfigDAL = orgGatewayConfigDALFactory(db);
const gatewayDAL = gatewayDALFactory(db);
const projectGatewayDAL = projectGatewayDALFactory(db);
const secretReminderRecipientsDAL = secretReminderRecipientsDALFactory(db);
const githubOrgSyncDAL = githubOrgSyncDALFactory(db);
const secretRotationV2DAL = secretRotationV2DALFactory(db, folderDAL);
@@ -427,6 +434,11 @@ export const registerRoutes = async (
serviceTokenDAL,
projectDAL
});
const assumePrivilegeService = assumePrivilegeServiceFactory({
projectDAL,
permissionService
});
const licenseService = licenseServiceFactory({
permissionService,
orgDAL,
@@ -549,6 +561,15 @@ export const registerRoutes = async (
externalGroupOrgRoleMappingDAL
});
const githubOrgSyncConfigService = githubOrgSyncServiceFactory({
licenseService,
githubOrgSyncDAL,
kmsService,
permissionService,
groupDAL,
userGroupMembershipDAL
});
const ldapService = ldapConfigServiceFactory({
ldapConfigDAL,
ldapGroupMapDAL,
@@ -728,6 +749,7 @@ export const registerRoutes = async (
projectKeyDAL,
projectRoleDAL,
groupProjectDAL,
secretReminderRecipientsDAL,
licenseService
});
const projectUserAdditionalPrivilegeService = projectUserAdditionalPrivilegeServiceFactory({
@@ -961,6 +983,7 @@ export const registerRoutes = async (
secretApprovalRequestDAL,
projectKeyDAL,
projectUserMembershipRoleDAL,
secretReminderRecipientsDAL,
orgService,
resourceMetadataDAL,
secretSyncQueue
@@ -1022,7 +1045,9 @@ export const registerRoutes = async (
projectRoleDAL,
projectUserMembershipRoleDAL,
identityProjectMembershipRoleDAL,
projectDAL
projectDAL,
identityDAL,
userDAL
});
const snapshotService = secretSnapshotServiceFactory({
@@ -1675,7 +1700,9 @@ export const registerRoutes = async (
kmip: kmipService,
kmipOperation: kmipOperationService,
gateway: gatewayService,
secretRotationV2: secretRotationV2Service
secretRotationV2: secretRotationV2Service,
assumePrivileges: assumePrivilegeService,
githubOrgSync: githubOrgSyncConfigService
});
const cronJobs: CronJob[] = [];
@@ -1696,6 +1723,7 @@ export const registerRoutes = async (
});
await server.register(injectIdentity, { userDAL, serviceTokenDAL });
await server.register(injectAssumePrivilege);
await server.register(injectPermission);
await server.register(injectRateLimits);
await server.register(injectAuditLogInfo);
@@ -1735,30 +1763,6 @@ export const registerRoutes = async (
logger.info(`Raw event loop stats: ${JSON.stringify(histogram, null, 2)}`);
// try {
// await db.raw("SELECT NOW()");
// } catch (err) {
// logger.error("Health check: database connection failed", err);
// return reply.code(503).send({
// date: new Date(),
// message: "Service unavailable"
// });
// }
// if (cfg.isRedisConfigured) {
// const redis = new Redis(cfg.REDIS_URL);
// try {
// await redis.ping();
// redis.disconnect();
// } catch (err) {
// logger.error("Health check: redis connection failed", err);
// return reply.code(503).send({
// date: new Date(),
// message: "Service unavailable"
// });
// }
// }
return {
date: new Date(),
message: "Ok",
@@ -28,6 +28,7 @@ import {
HumanitecConnectionListItemSchema,
SanitizedHumanitecConnectionSchema
} from "@app/services/app-connection/humanitec";
import { LdapConnectionListItemSchema, SanitizedLdapConnectionSchema } from "@app/services/app-connection/ldap";
import { MsSqlConnectionListItemSchema, SanitizedMsSqlConnectionSchema } from "@app/services/app-connection/mssql";
import {
PostgresConnectionListItemSchema,
@@ -64,6 +65,7 @@ const SanitizedAppConnectionSchema = z.union([
...SanitizedCamundaConnectionSchema.options,
...SanitizedWindmillConnectionSchema.options,
...SanitizedAuth0ConnectionSchema.options,
...SanitizedLdapConnectionSchema.options,
...SanitizedTeamCityConnectionSchema.options
]);
@@ -82,6 +84,7 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
CamundaConnectionListItemSchema,
WindmillConnectionListItemSchema,
Auth0ConnectionListItemSchema,
LdapConnectionListItemSchema,
TeamCityConnectionListItemSchema
]);
@@ -1,6 +1,6 @@
import { registerAuth0ConnectionRouter } from "@app/server/routes/v1/app-connection-routers/auth0-connection-router";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { registerAuth0ConnectionRouter } from "./auth0-connection-router";
import { registerAwsConnectionRouter } from "./aws-connection-router";
import { registerAzureAppConfigurationConnectionRouter } from "./azure-app-configuration-connection-router";
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
@@ -9,6 +9,7 @@ import { registerDatabricksConnectionRouter } from "./databricks-connection-rout
import { registerGcpConnectionRouter } from "./gcp-connection-router";
import { registerGitHubConnectionRouter } from "./github-connection-router";
import { registerHumanitecConnectionRouter } from "./humanitec-connection-router";
import { registerLdapConnectionRouter } from "./ldap-connection-router";
import { registerMsSqlConnectionRouter } from "./mssql-connection-router";
import { registerPostgresConnectionRouter } from "./postgres-connection-router";
import { registerTeamCityConnectionRouter } from "./teamcity-connection-router";
@@ -34,5 +35,6 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
[AppConnection.Camunda]: registerCamundaConnectionRouter,
[AppConnection.Windmill]: registerWindmillConnectionRouter,
[AppConnection.Auth0]: registerAuth0ConnectionRouter,
[AppConnection.LDAP]: registerLdapConnectionRouter,
[AppConnection.TeamCity]: registerTeamCityConnectionRouter
};
@@ -0,0 +1,18 @@
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateLdapConnectionSchema,
SanitizedLdapConnectionSchema,
UpdateLdapConnectionSchema
} from "@app/services/app-connection/ldap";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerLdapConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.LDAP,
server,
sanitizedResponseSchema: SanitizedLdapConnectionSchema,
createSchema: CreateLdapConnectionSchema,
updateSchema: UpdateLdapConnectionSchema
});
};
@@ -33,6 +33,14 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
secure: appCfg.HTTPS_ENABLED
});
void res.cookie("infisical-project-assume-privileges", "", {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED,
maxAge: 0
});
return { message: "Successfully logged out" };
}
});
@@ -1,7 +1,7 @@
import { ForbiddenError } from "@casl/ability";
import { z } from "zod";
import { SecretFoldersSchema, SecretImportsSchema } from "@app/db/schemas";
import { SecretFoldersSchema, SecretImportsSchema, UsersSchema } from "@app/db/schemas";
import { EventType, UserAgentType } from "@app/ee/services/audit-log/audit-log-types";
import { ProjectPermissionSecretActions } from "@app/ee/services/permission/project-permission";
import { SecretRotationV2Schema } from "@app/ee/services/secret-rotation-v2/secret-rotation-v2-union-schema";
@@ -594,6 +594,12 @@ export const registerDashboardRouter = async (server: FastifyZodProvider) => {
.optional(),
secrets: secretRawSchema
.extend({
secretReminderRecipients: z
.object({
user: UsersSchema.pick({ id: true, email: true, username: true }),
id: z.string()
})
.array(),
secretValueHidden: z.boolean(),
secretPath: z.string().optional(),
secretMetadata: ResourceMetadataSchema.optional(),
+56 -11
View File
@@ -14,9 +14,11 @@ import { Strategy as GoogleStrategy } from "passport-google-oauth20";
import { Strategy as OAuth2Strategy } from "passport-oauth2";
import { z } from "zod";
import { INFISICAL_PROVIDER_GITHUB_ACCESS_TOKEN } from "@app/lib/config/const";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { ms } from "@app/lib/ms";
import { fetchGithubEmails, fetchGithubUser } from "@app/lib/requests/github";
import { authRateLimit } from "@app/server/config/rateLimiter";
import { AuthMethod } from "@app/services/auth/auth-type";
@@ -99,7 +101,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
clientID: appCfg.CLIENT_ID_GITHUB_LOGIN!,
clientSecret: appCfg.CLIENT_SECRET_GITHUB_LOGIN!,
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/github`,
scope: ["user:email"],
scope: ["user:email", "read:org"],
state: true,
pkce: true,
passReqToCallback: true
@@ -125,7 +127,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
callbackPort
});
done(null, { isUserCompleted, providerAuthToken });
done(null, { isUserCompleted, providerAuthToken, externalProviderAccessToken: accessToken });
} catch (err) {
logger.error(err);
done(err as Error, false);
@@ -179,17 +181,24 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
method: "GET",
schema: {
querystring: z.object({
callback_port: z.string().optional()
callback_port: z.string().optional(),
is_admin_login: z
.string()
.optional()
.transform((val) => val === "true")
})
},
preValidation: [
async (req, res) => {
const { callback_port: callbackPort } = req.query;
const { callback_port: callbackPort, is_admin_login: isAdminLogin } = req.query;
// ensure fresh session state per login attempt
await req.session.regenerate();
if (callbackPort) {
req.session.set("callbackPort", callbackPort);
}
if (isAdminLogin) {
req.session.set("isAdminLogin", isAdminLogin);
}
return (
passport.authenticate("google", {
scope: ["profile", "email"],
@@ -213,10 +222,13 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
// this is due to zod type difference
}) as never,
handler: async (req, res) => {
const isAdminLogin = req.session.get("isAdminLogin");
await req.session.destroy();
if (req.passportUser.isUserCompleted) {
return res.redirect(
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
isAdminLogin ? `&isAdminLogin=${isAdminLogin}` : ""
}`
);
}
return res.redirect(
@@ -230,18 +242,26 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
method: "GET",
schema: {
querystring: z.object({
callback_port: z.string().optional()
callback_port: z.string().optional(),
is_admin_login: z
.string()
.optional()
.transform((val) => val === "true")
})
},
preValidation: [
async (req, res) => {
const { callback_port: callbackPort } = req.query;
const { callback_port: callbackPort, is_admin_login: isAdminLogin } = req.query;
// ensure fresh session state per login attempt
await req.session.regenerate();
if (callbackPort) {
req.session.set("callbackPort", callbackPort);
}
if (isAdminLogin) {
req.session.set("isAdminLogin", isAdminLogin);
}
return (
passport.authenticate("github", {
session: false,
@@ -302,10 +322,24 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
// this is due to zod type difference
}) as any,
handler: async (req, res) => {
const isAdminLogin = req.session.get("isAdminLogin");
await req.session.destroy();
if (req.passportUser.externalProviderAccessToken) {
void res.cookie(INFISICAL_PROVIDER_GITHUB_ACCESS_TOKEN, req.passportUser.externalProviderAccessToken, {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED,
expires: new Date(Date.now() + ms(appCfg.JWT_PROVIDER_AUTH_LIFETIME))
});
}
if (req.passportUser.isUserCompleted) {
return res.redirect(
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
isAdminLogin ? `&isAdminLogin=${isAdminLogin}` : ""
}`
);
}
return res.redirect(
@@ -319,18 +353,26 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
method: "GET",
schema: {
querystring: z.object({
callback_port: z.string().optional()
callback_port: z.string().optional(),
is_admin_login: z
.string()
.optional()
.transform((val) => val === "true")
})
},
preValidation: [
async (req, res) => {
const { callback_port: callbackPort } = req.query;
const { callback_port: callbackPort, is_admin_login: isAdminLogin } = req.query;
// ensure fresh session state per login attempt
await req.session.regenerate();
if (callbackPort) {
req.session.set("callbackPort", callbackPort);
}
if (isAdminLogin) {
req.session.set("isAdminLogin", isAdminLogin);
}
return (
passport.authenticate("gitlab", {
session: false,
@@ -355,10 +397,13 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}) as any,
handler: async (req, res) => {
const isAdminLogin = req.session.get("isAdminLogin");
await req.session.destroy();
if (req.passportUser.isUserCompleted) {
return res.redirect(
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}${
isAdminLogin ? `&isAdminLogin=${isAdminLogin}` : ""
}`
);
}
return res.redirect(
@@ -1,5 +1,6 @@
import { z } from "zod";
import { INFISICAL_PROVIDER_GITHUB_ACCESS_TOKEN } from "@app/lib/config/const";
import { getConfig } from "@app/lib/config/env";
import { authRateLimit } from "@app/server/config/rateLimiter";
@@ -70,6 +71,21 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
};
}
const githubOauthAccessToken = req.cookies[INFISICAL_PROVIDER_GITHUB_ACCESS_TOKEN];
if (githubOauthAccessToken) {
await server.services.githubOrgSync
.syncUserGroups(req.body.organizationId, tokens.user.userId, githubOauthAccessToken)
.finally(() => {
void res.setCookie(INFISICAL_PROVIDER_GITHUB_ACCESS_TOKEN, "", {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: cfg.HTTPS_ENABLED,
maxAge: 0
});
});
}
void res.setCookie("jid", tokens.refresh, {
httpOnly: true,
path: "/",
@@ -77,6 +93,14 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
secure: cfg.HTTPS_ENABLED
});
void res.cookie("infisical-project-assume-privileges", "", {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: cfg.HTTPS_ENABLED,
maxAge: 0
});
return { token: tokens.access, isMfaEnabled: false };
}
});
@@ -131,6 +155,14 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
secure: appCfg.HTTPS_ENABLED
});
void res.cookie("infisical-project-assume-privileges", "", {
httpOnly: true,
path: "/",
sameSite: "strict",
secure: appCfg.HTTPS_ENABLED,
maxAge: 0
});
return {
encryptionVersion: data.user.encryptionVersion,
token: data.token.access,
@@ -662,6 +662,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
.optional()
.nullable()
.describe(RAW_SECRETS.UPDATE.secretReminderRepeatDays),
secretReminderRecipients: z.string().array().optional().describe(RAW_SECRETS.UPDATE.secretReminderRecipients),
newSecretName: SecretNameSchema.optional().describe(RAW_SECRETS.UPDATE.newSecretName),
secretComment: z.string().optional().describe(RAW_SECRETS.UPDATE.secretComment)
}),
@@ -692,6 +693,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
skipMultilineEncoding: req.body.skipMultilineEncoding,
tagIds: req.body.tagIds,
secretReminderRepeatDays: req.body.secretReminderRepeatDays,
secretReminderRecipients: req.body.secretReminderRecipients,
secretReminderNote: req.body.secretReminderNote,
metadata: req.body.metadata,
newSecretName: req.body.newSecretName,