Merge pull request #1372 from Infisical/org-based-auth

Org-Level Auth Enforcement for SAML Orgs and Enhancements for SAML SSO
This commit is contained in:
Maidul Islam
2024-02-09 13:15:08 -05:00
committed by GitHub
113 changed files with 1568 additions and 1104 deletions
@@ -141,7 +141,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact
const user = await userDAL.findById(session.userId);
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
return { user, tokenVersionId: token.tokenVersionId };
return { user, tokenVersionId: token.tokenVersionId, orgId: token.organizationId };
};
return {
+6
View File
@@ -12,6 +12,12 @@ export const validateProviderAuthToken = (providerToken: string, email: string)
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw new UnauthorizedError();
if (decodedToken.email !== email) throw new Error("Invalid auth credentials");
if (decodedToken.organizationId) {
return { orgId: decodedToken.organizationId };
}
return {};
};
export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => {
+63 -12
View File
@@ -56,7 +56,7 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
* Private
* Send mfa code via email
* */
const sendUserMfaCode = async (userId: string, email: string) => {
const sendUserMfaCode = async ({ userId, email }: { userId: string; email: string }) => {
const code = await tokenService.createTokenForUser({
type: TokenType.TOKEN_EMAIL_MFA,
userId
@@ -76,7 +76,17 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
* Check user device and send mail if new device
* generate the auth and refresh token. fn shared by mfa verification and login verification with mfa disabled
*/
const generateUserTokens = async (user: TUsers, ip: string, userAgent: string) => {
const generateUserTokens = async ({
user,
ip,
userAgent,
organizationId
}: {
user: TUsers;
ip: string;
userAgent: string;
organizationId?: string;
}) => {
const cfg = getConfig();
await updateUserDeviceSession(user, ip, userAgent);
const tokenSession = await tokenService.getUserTokenSession({
@@ -90,7 +100,8 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: user.id,
tokenVersionId: tokenSession.id,
accessVersion: tokenSession.accessVersion
accessVersion: tokenSession.accessVersion,
organizationId
},
cfg.AUTH_SECRET,
{ expiresIn: cfg.JWT_AUTH_LIFETIME }
@@ -101,7 +112,8 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
authTokenType: AuthTokenType.REFRESH_TOKEN,
userId: user.id,
tokenVersionId: tokenSession.id,
refreshVersion: tokenSession.refreshVersion
refreshVersion: tokenSession.refreshVersion,
organizationId
},
cfg.AUTH_SECRET,
{ expiresIn: cfg.JWT_REFRESH_LIFETIME }
@@ -149,8 +161,14 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
if (!userEnc) throw new Error("Failed to find user");
const cfg = getConfig();
let organizationId;
if (!userEnc.authMethods?.includes(AuthMethod.EMAIL)) {
validateProviderAuthToken(providerAuthToken as string, email);
const { orgId } = validateProviderAuthToken(providerAuthToken as string, email);
organizationId = orgId;
} else if (providerAuthToken) {
// SAML SSO
const { orgId } = validateProviderAuthToken(providerAuthToken, email);
organizationId = orgId;
}
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?");
@@ -169,15 +187,36 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
});
// send multi factor auth token if they it enabled
if (userEnc.isMfaEnabled) {
const mfaToken = jwt.sign({ authTokenType: AuthTokenType.MFA_TOKEN, userId: userEnc.userId }, cfg.AUTH_SECRET, {
expiresIn: cfg.JWT_MFA_LIFETIME
const mfaToken = jwt.sign(
{
authTokenType: AuthTokenType.MFA_TOKEN,
userId: userEnc.userId,
organizationId
},
cfg.AUTH_SECRET,
{
expiresIn: cfg.JWT_MFA_LIFETIME
}
);
await sendUserMfaCode({
userId: userEnc.userId,
email: userEnc.email
});
await sendUserMfaCode(userEnc.userId, userEnc.email);
return { isMfaEnabled: true, token: mfaToken } as const;
}
const token = await generateUserTokens({ ...userEnc, id: userEnc.userId }, ip, userAgent);
const token = await generateUserTokens({
user: {
...userEnc,
id: userEnc.userId
},
ip,
userAgent,
organizationId
});
return { token, isMfaEnabled: false, user: userEnc } as const;
};
@@ -188,14 +227,17 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
const resendMfaToken = async (userId: string) => {
const user = await userDAL.findById(userId);
if (!user) return;
await sendUserMfaCode(user.id, user.email);
await sendUserMfaCode({
userId: user.id,
email: user.email
});
};
/*
* Multi factor authentication verification of code
* Third step of login in which user completes with mfa
* */
const verifyMfaToken = async ({ userId, mfaToken, ip, userAgent }: TVerifyMfaTokenDTO) => {
const verifyMfaToken = async ({ userId, mfaToken, ip, userAgent, orgId }: TVerifyMfaTokenDTO) => {
await tokenService.validateTokenForUser({
type: TokenType.TOKEN_EMAIL_MFA,
userId,
@@ -204,7 +246,16 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
const userEnc = await userDAL.findUserEncKeyByUserId(userId);
if (!userEnc) throw new Error("Failed to authenticate user");
const token = await generateUserTokens({ ...userEnc, id: userEnc.userId }, ip, userAgent);
const token = await generateUserTokens({
user: {
...userEnc,
id: userEnc.userId
},
ip,
userAgent,
organizationId: orgId
});
return { token, user: userEnc };
};
/*
@@ -19,6 +19,7 @@ export type TVerifyMfaTokenDTO = {
mfaToken: string;
ip: string;
userAgent: string;
orgId?: string;
};
export type TOauthLoginDTO = {
@@ -120,8 +120,10 @@ export const authSignupServiceFactory = ({
throw new Error("Failed to complete account for complete user");
}
let organizationId;
if (providerAuthToken) {
validateProviderAuthToken(providerAuthToken, user.email);
const { orgId } = validateProviderAuthToken(providerAuthToken, user.email);
organizationId = orgId;
} else {
validateSignUpAuthorization(authorization, user.id);
}
@@ -147,11 +149,7 @@ export const authSignupServiceFactory = ({
return { info: us, key: userEncKey };
});
const hasSamlEnabled = user?.authMethods?.some((authMethod) =>
[AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes(authMethod as AuthMethod)
);
if (!hasSamlEnabled) {
if (!organizationId) {
await orgService.createOrganization(user.id, user.email, organizationName);
}
@@ -175,7 +173,8 @@ export const authSignupServiceFactory = ({
authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: updateduser.info.id,
tokenVersionId: tokenSession.id,
accessVersion: tokenSession.accessVersion
accessVersion: tokenSession.accessVersion,
organizationId
},
appCfg.AUTH_SECRET,
{ expiresIn: appCfg.JWT_AUTH_LIFETIME }
@@ -186,7 +185,8 @@ export const authSignupServiceFactory = ({
authTokenType: AuthTokenType.REFRESH_TOKEN,
userId: updateduser.info.id,
tokenVersionId: tokenSession.id,
refreshVersion: tokenSession.refreshVersion
refreshVersion: tokenSession.refreshVersion,
organizationId
},
appCfg.AUTH_SECRET,
{ expiresIn: appCfg.JWT_REFRESH_LIFETIME }
+4
View File
@@ -39,11 +39,13 @@ export type AuthModeJwtTokenPayload = {
userId: string;
tokenVersionId: string;
accessVersion: number;
organizationId?: string;
};
export type AuthModeMfaJwtTokenPayload = {
authTokenType: AuthTokenType.MFA_TOKEN;
userId: string;
organizationId?: string;
};
export type AuthModeRefreshJwtTokenPayload = {
@@ -51,11 +53,13 @@ export type AuthModeRefreshJwtTokenPayload = {
userId: string;
tokenVersionId: string;
refreshVersion: number;
organizationId?: string;
};
export type AuthModeProviderJwtTokenPayload = {
authTokenType: AuthTokenType.PROVIDER_TOKEN;
email: string;
organizationId?: string;
};
export type AuthModeProviderSignUpTokenPayload = {
@@ -32,8 +32,15 @@ export const identityProjectServiceFactory = ({
identityOrgMembershipDAL,
projectDAL
}: TIdentityProjectServiceFactoryDep) => {
const createProjectIdentity = async ({ identityId, actor, actorId, projectId, role }: TCreateProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const createProjectIdentity = async ({
identityId,
actor,
actorId,
actorOrgId,
projectId,
role
}: TCreateProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Identity);
const existingIdentity = await identityProjectDAL.findOne({ identityId, projectId });
@@ -72,8 +79,15 @@ export const identityProjectServiceFactory = ({
return projectIdentity;
};
const updateProjectIdentity = async ({ projectId, identityId, role, actor, actorId }: TUpdateProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const updateProjectIdentity = async ({
projectId,
identityId,
role,
actor,
actorId,
actorOrgId
}: TUpdateProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Identity);
const projectIdentity = await identityProjectDAL.findOne({ identityId, projectId });
@@ -85,7 +99,8 @@ export const identityProjectServiceFactory = ({
const { permission: identityRolePermission } = await permissionService.getProjectPermission(
ActorType.IDENTITY,
projectIdentity.identityId,
projectIdentity.projectId
projectIdentity.projectId,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges)
@@ -115,7 +130,13 @@ export const identityProjectServiceFactory = ({
return updatedProjectIdentity;
};
const deleteProjectIdentity = async ({ identityId, actorId, actor, projectId }: TDeleteProjectIdentityDTO) => {
const deleteProjectIdentity = async ({
identityId,
actorId,
actor,
actorOrgId,
projectId
}: TDeleteProjectIdentityDTO) => {
const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId });
if (!identityProjectMembership)
throw new BadRequestError({ message: `Failed to find identity with id ${identityId}` });
@@ -123,13 +144,15 @@ export const identityProjectServiceFactory = ({
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
identityProjectMembership.projectId
identityProjectMembership.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Identity);
const { permission: identityRolePermission } = await permissionService.getProjectPermission(
ActorType.IDENTITY,
identityId,
identityProjectMembership.projectId
identityProjectMembership.projectId,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges)
@@ -139,8 +162,8 @@ export const identityProjectServiceFactory = ({
return deletedIdentity;
};
const listProjectIdentities = async ({ projectId, actor, actorId }: TListProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const listProjectIdentities = async ({ projectId, actor, actorId, actorOrgId }: TListProjectIdentityDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Identity);
const identityMemberhips = await identityProjectDAL.findByProjectId(projectId);
@@ -127,6 +127,7 @@ export const identityUaServiceFactory = ({
expiresIn: identityAccessToken.accessTokenMaxTTL === 0 ? undefined : identityAccessToken.accessTokenMaxTTL
}
);
return { accessToken, identityUa, validClientSecretInfo, identityAccessToken };
};
@@ -138,7 +139,8 @@ export const identityUaServiceFactory = ({
accessTokenTrustedIps,
clientSecretTrustedIps,
actorId,
actor
actor,
actorOrgId
}: TAttachUaDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
@@ -151,7 +153,12 @@ export const identityUaServiceFactory = ({
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
}
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
@@ -221,7 +228,8 @@ export const identityUaServiceFactory = ({
accessTokenTrustedIps,
clientSecretTrustedIps,
actorId,
actor
actor,
actorOrgId
}: TUpdateUaDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
@@ -239,7 +247,12 @@ export const identityUaServiceFactory = ({
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
}
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity);
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
@@ -290,7 +303,7 @@ export const identityUaServiceFactory = ({
return { ...updatedUaAuth, orgId: identityMembershipOrg.orgId };
};
const getIdentityUa = async ({ identityId, actorId, actor }: TGetUaDTO) => {
const getIdentityUa = async ({ identityId, actorId, actor, actorOrgId }: TGetUaDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
@@ -300,7 +313,12 @@ export const identityUaServiceFactory = ({
const uaIdentityAuth = await identityUaDAL.findOne({ identityId });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
return { ...uaIdentityAuth, orgId: identityMembershipOrg.orgId };
};
@@ -308,6 +326,7 @@ export const identityUaServiceFactory = ({
const createUaClientSecret = async ({
actor,
actorId,
actorOrgId,
identityId,
ttl,
description,
@@ -319,13 +338,19 @@ export const identityUaServiceFactory = ({
throw new BadRequestError({
message: "The identity does not have universal auth"
});
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
const { permission: rolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY,
identityMembershipOrg.identityId,
identityMembershipOrg.orgId
identityMembershipOrg.orgId,
actorOrgId
);
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge)
@@ -358,20 +383,26 @@ export const identityUaServiceFactory = ({
};
};
const getUaClientSecrets = async ({ actor, actorId, identityId }: TGetUaClientSecretsDTO) => {
const getUaClientSecrets = async ({ actor, actorId, actorOrgId, identityId }: TGetUaClientSecretsDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
throw new BadRequestError({
message: "The identity does not have universal auth"
});
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
const { permission: rolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY,
identityMembershipOrg.identityId,
identityMembershipOrg.orgId
identityMembershipOrg.orgId,
actorOrgId
);
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge)
@@ -390,20 +421,32 @@ export const identityUaServiceFactory = ({
return { clientSecrets, orgId: identityMembershipOrg.orgId };
};
const revokeUaClientSecret = async ({ identityId, actorId, actor, clientSecretId }: TRevokeUaClientSecretDTO) => {
const revokeUaClientSecret = async ({
identityId,
actorId,
actor,
actorOrgId,
clientSecretId
}: TRevokeUaClientSecretDTO) => {
const identityMembershipOrg = await identityOrgMembershipDAL.findOne({ identityId });
if (!identityMembershipOrg) throw new BadRequestError({ message: "Failed to find identity" });
if (identityMembershipOrg.identity?.authMethod !== IdentityAuthMethod.Univeral)
throw new BadRequestError({
message: "The identity does not have universal auth"
});
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityMembershipOrg.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityMembershipOrg.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity);
const { permission: rolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY,
identityMembershipOrg.identityId,
identityMembershipOrg.orgId
identityMembershipOrg.orgId,
actorOrgId
);
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge)
@@ -25,8 +25,8 @@ export const identityServiceFactory = ({
identityOrgMembershipDAL,
permissionService
}: TIdentityServiceFactoryDep) => {
const createIdentity = async ({ name, role, actor, orgId, actorId }: TCreateIdentityDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const createIdentity = async ({ name, role, actor, orgId, actorId, actorOrgId }: TCreateIdentityDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Identity);
const { permission: rolePermission, role: customRole } = await permissionService.getOrgPermissionByRole(
@@ -54,17 +54,23 @@ export const identityServiceFactory = ({
return identity;
};
const updateIdentity = async ({ id, role, name, actor, actorId }: TUpdateIdentityDTO) => {
const updateIdentity = async ({ id, role, name, actor, actorId, actorOrgId }: TUpdateIdentityDTO) => {
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityOrgMembership.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Identity);
const { permission: identityRolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY,
id,
identityOrgMembership.orgId
identityOrgMembership.orgId,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, identityRolePermission);
if (!hasRequiredPriviledges)
@@ -102,11 +108,16 @@ export const identityServiceFactory = ({
return { ...identity, orgId: identityOrgMembership.orgId };
};
const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => {
const deleteIdentity = async ({ actorId, actor, actorOrgId, id }: TDeleteIdentityDTO) => {
const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id });
if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` });
const { permission } = await permissionService.getOrgPermission(actor, actorId, identityOrgMembership.orgId);
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
identityOrgMembership.orgId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Identity);
const { permission: identityRolePermission } = await permissionService.getOrgPermission(
ActorType.IDENTITY,
@@ -121,8 +132,8 @@ export const identityServiceFactory = ({
return { ...deletedIdentity, orgId: identityOrgMembership.orgId };
};
const listOrgIdentities = async ({ orgId, actor, actorId }: TOrgPermission) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const listOrgIdentities = async ({ orgId, actor, actorId, actorOrgId }: TOrgPermission) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
const identityMemberhips = await identityOrgMembershipDAL.findByOrgId(orgId);
@@ -59,27 +59,40 @@ export const integrationAuthServiceFactory = ({
projectBotDAL,
projectBotService
}: TIntegrationAuthServiceFactoryDep) => {
const listIntegrationAuthByProjectId = async ({ actorId, actor, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const listIntegrationAuthByProjectId = async ({ actorId, actor, actorOrgId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const authorizations = await integrationAuthDAL.find({ projectId });
return authorizations;
};
const getIntegrationAuth = async ({ actor, id, actorId }: TGetIntegrationAuthDTO) => {
const getIntegrationAuth = async ({ actor, id, actorId, actorOrgId }: TGetIntegrationAuthDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
return integrationAuth;
};
const oauthExchange = async ({ projectId, actorId, actor, integration, url, code }: TOauthExchangeDTO) => {
const oauthExchange = async ({
projectId,
actorId,
actor,
actorOrgId,
integration,
url,
code
}: TOauthExchangeDTO) => {
if (!Object.values(Integrations).includes(integration as Integrations))
throw new BadRequestError({ message: "Invalid integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
const bot = await projectBotDAL.findOne({ isActive: true, projectId });
@@ -134,6 +147,7 @@ export const integrationAuthServiceFactory = ({
integration,
url,
actor,
actorOrgId,
accessId,
namespace,
accessToken
@@ -141,7 +155,7 @@ export const integrationAuthServiceFactory = ({
if (!Object.values(Integrations).includes(integration as Integrations))
throw new BadRequestError({ message: "Invalid integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
const bot = await projectBotDAL.findOne({ isActive: true, projectId });
@@ -254,11 +268,23 @@ export const integrationAuthServiceFactory = ({
return { accessId, accessToken };
};
const getIntegrationApps = async ({ actor, actorId, teamId, id, workspaceSlug }: TIntegrationAuthAppsDTO) => {
const getIntegrationApps = async ({
actor,
actorId,
actorOrgId,
teamId,
id,
workspaceSlug
}: TIntegrationAuthAppsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -274,11 +300,16 @@ export const integrationAuthServiceFactory = ({
return apps;
};
const getIntegrationAuthTeams = async ({ actor, actorId, id }: TIntegrationAuthTeamsDTO) => {
const getIntegrationAuthTeams = async ({ actor, actorId, actorOrgId, id }: TIntegrationAuthTeamsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
@@ -291,11 +322,16 @@ export const integrationAuthServiceFactory = ({
return teams;
};
const getVercelBranches = async ({ appId, id, actor, actorId }: TIntegrationAuthVercelBranchesDTO) => {
const getVercelBranches = async ({ appId, id, actor, actorId, actorOrgId }: TIntegrationAuthVercelBranchesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -319,11 +355,16 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getChecklyGroups = async ({ actorId, actor, id, accountId }: TIntegrationAuthChecklyGroupsDTO) => {
const getChecklyGroups = async ({ actorId, actor, actorOrgId, id, accountId }: TIntegrationAuthChecklyGroupsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -340,11 +381,16 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getQoveryOrgs = async ({ actorId, actor, id }: TIntegrationAuthQoveryOrgsDTO) => {
const getQoveryOrgs = async ({ actorId, actor, actorOrgId, id }: TIntegrationAuthQoveryOrgsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -361,11 +407,16 @@ export const integrationAuthServiceFactory = ({
return data.results.map(({ name, id: orgId }) => ({ name, orgId }));
};
const getQoveryProjects = async ({ actorId, actor, id, orgId }: TIntegrationAuthQoveryProjectDTO) => {
const getQoveryProjects = async ({ actorId, actor, actorOrgId, id, orgId }: TIntegrationAuthQoveryProjectDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -384,11 +435,22 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getQoveryEnvs = async ({ projectId, id, actor, actorId }: TIntegrationAuthQoveryEnvironmentsDTO) => {
const getQoveryEnvs = async ({
projectId,
id,
actor,
actorId,
actorOrgId
}: TIntegrationAuthQoveryEnvironmentsDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -412,11 +474,16 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getQoveryApps = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => {
const getQoveryApps = async ({ id, actor, actorId, actorOrgId, environmentId }: TIntegrationAuthQoveryScopesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -439,11 +506,22 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getQoveryContainers = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => {
const getQoveryContainers = async ({
id,
actor,
actorId,
actorOrgId,
environmentId
}: TIntegrationAuthQoveryScopesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -466,11 +544,16 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getQoveryJobs = async ({ id, actor, actorId, environmentId }: TIntegrationAuthQoveryScopesDTO) => {
const getQoveryJobs = async ({ id, actor, actorId, actorOrgId, environmentId }: TIntegrationAuthQoveryScopesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -493,11 +576,16 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getRailwayEnvironments = async ({ id, actor, actorId, appId }: TIntegrationAuthRailwayEnvDTO) => {
const getRailwayEnvironments = async ({ id, actor, actorId, actorOrgId, appId }: TIntegrationAuthRailwayEnvDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -547,11 +635,17 @@ export const integrationAuthServiceFactory = ({
}
return [];
};
const getRailwayServices = async ({ id, actor, actorId, appId }: TIntegrationAuthRailwayServicesDTO) => {
const getRailwayServices = async ({ id, actor, actorId, actorOrgId, appId }: TIntegrationAuthRailwayServicesDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -620,11 +714,16 @@ export const integrationAuthServiceFactory = ({
return [];
};
const getBitbucketWorkspaces = async ({ actorId, actor, id }: TIntegrationAuthBitbucketWorkspaceDTO) => {
const getBitbucketWorkspaces = async ({ actorId, actor, actorOrgId, id }: TIntegrationAuthBitbucketWorkspaceDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -658,11 +757,22 @@ export const integrationAuthServiceFactory = ({
return workspaces;
};
const getNorthFlankSecretGroups = async ({ id, actor, actorId, appId }: TIntegrationAuthNorthflankSecretGroupDTO) => {
const getNorthFlankSecretGroups = async ({
id,
actor,
actorId,
actorOrgId,
appId
}: TIntegrationAuthNorthflankSecretGroupDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -713,11 +823,22 @@ export const integrationAuthServiceFactory = ({
return secretGroups;
};
const getTeamcityBuildConfigs = async ({ appId, id, actorId, actor }: TGetIntegrationAuthTeamCityBuildConfigDTO) => {
const getTeamcityBuildConfigs = async ({
appId,
id,
actorId,
actorOrgId,
actor
}: TGetIntegrationAuthTeamCityBuildConfigDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const botKey = await projectBotService.getBotKey(integrationAuth.projectId);
const { accessToken } = await getIntegrationAccessToken(integrationAuth, botKey);
@@ -742,19 +863,30 @@ export const integrationAuthServiceFactory = ({
return [];
};
const deleteIntegrationAuths = async ({ projectId, integration, actor, actorId }: TDeleteIntegrationAuthsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteIntegrationAuths = async ({
projectId,
integration,
actor,
actorId,
actorOrgId
}: TDeleteIntegrationAuthsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
const integrations = await integrationAuthDAL.delete({ integration, projectId });
return integrations;
};
const deleteIntegrationAuthById = async ({ id, actorId, actor }: TDeleteIntegrationAuthByIdDTO) => {
const deleteIntegrationAuthById = async ({ id, actorId, actor, actorOrgId }: TDeleteIntegrationAuthByIdDTO) => {
const integrationAuth = await integrationAuthDAL.findById(id);
if (!integrationAuth) throw new BadRequestError({ message: "Failed to find integration" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
const delIntegrationAuth = await integrationAuthDAL.transaction(async (tx) => {
@@ -31,6 +31,7 @@ export const integrationServiceFactory = ({
const createIntegration = async ({
app,
actor,
actorOrgId,
path,
appId,
owner,
@@ -50,7 +51,12 @@ export const integrationServiceFactory = ({
const integrationAuth = await integrationAuthDAL.findById(integrationAuthId);
if (!integrationAuth) throw new BadRequestError({ message: "Integration auth not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integrationAuth.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integrationAuth.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Integrations);
const folder = await folderDAL.findBySecretPath(integrationAuth.projectId, sourceEnvironment, secretPath);
@@ -86,6 +92,7 @@ export const integrationServiceFactory = ({
const updateIntegration = async ({
actorId,
actor,
actorOrgId,
targetEnvironment,
app,
id,
@@ -98,7 +105,12 @@ export const integrationServiceFactory = ({
const integration = await integrationDAL.findById(id);
if (!integration) throw new BadRequestError({ message: "Integration auth not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integration.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integration.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);
const folder = await folderDAL.findBySecretPath(integration.projectId, environment, secretPath);
@@ -117,19 +129,24 @@ export const integrationServiceFactory = ({
return updatedIntegration;
};
const deleteIntegration = async ({ actorId, id, actor }: TDeleteIntegrationDTO) => {
const deleteIntegration = async ({ actorId, id, actor, actorOrgId }: TDeleteIntegrationDTO) => {
const integration = await integrationDAL.findById(id);
if (!integration) throw new BadRequestError({ message: "Integration auth not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, integration.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
integration.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Integrations);
const deletedIntegration = await integrationDAL.deleteById(id);
return { ...integration, ...deletedIntegration };
};
const listIntegrationByProject = async ({ actor, actorId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const listIntegrationByProject = async ({ actor, actorId, actorOrgId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const integrations = await integrationDAL.findByProjectId(projectId);
+4 -1
View File
@@ -11,11 +11,13 @@ import {
TUserEncryptionKeys
} from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
import { buildFindFilter, selectAllTableCols, TFindFilter, TFindOpt, withTransaction } from "@app/lib/knex";
import { buildFindFilter, ormify, selectAllTableCols, TFindFilter, TFindOpt, withTransaction } from "@app/lib/knex";
export type TOrgDALFactory = ReturnType<typeof orgDALFactory>;
export const orgDALFactory = (db: TDbClient) => {
const orgOrm = ormify(db, TableName.Organization);
const findOrgById = async (orgId: string) => {
try {
const org = await db(TableName.Organization).where({ id: orgId }).first();
@@ -177,6 +179,7 @@ export const orgDALFactory = (db: TDbClient) => {
};
return withTransaction(db, {
...orgOrm,
findOrgByProjectId,
findAllOrgMembers,
findOrgById,
+21 -10
View File
@@ -22,8 +22,13 @@ type TOrgRoleServiceFactoryDep = {
export type TOrgRoleServiceFactory = ReturnType<typeof orgRoleServiceFactory>;
export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRoleServiceFactoryDep) => {
const createRole = async (userId: string, orgId: string, data: Omit<TOrgRolesInsert, "orgId">) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const createRole = async (
userId: string,
orgId: string,
data: Omit<TOrgRolesInsert, "orgId">,
actorOrgId?: string
) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Role);
const existingRole = await orgRoleDAL.findOne({ slug: data.slug, orgId });
if (existingRole) throw new BadRequestError({ name: "Create Role", message: "Duplicate role" });
@@ -35,8 +40,14 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return role;
};
const updateRole = async (userId: string, orgId: string, roleId: string, data: Omit<TOrgRolesUpdate, "orgId">) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const updateRole = async (
userId: string,
orgId: string,
roleId: string,
data: Omit<TOrgRolesUpdate, "orgId">,
actorOrgId?: string
) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Role);
if (data?.slug) {
const existingRole = await orgRoleDAL.findOne({ slug: data.slug, orgId });
@@ -51,8 +62,8 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return updatedRole;
};
const deleteRole = async (userId: string, orgId: string, roleId: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const deleteRole = async (userId: string, orgId: string, roleId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Role);
const [deletedRole] = await orgRoleDAL.delete({ id: roleId, orgId });
if (!deleteRole) throw new BadRequestError({ message: "Role not found", name: "Update role" });
@@ -60,8 +71,8 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return deletedRole;
};
const listRoles = async (userId: string, orgId: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const listRoles = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Role);
const customRoles = await orgRoleDAL.find({ orgId });
const roles = [
@@ -104,8 +115,8 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return roles;
};
const getUserPermission = async (userId: string, orgId: string) => {
const { permission, membership } = await permissionService.getUserOrgPermission(userId, orgId);
const getUserPermission = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission, membership } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
return { permissions: packRules(permission.rules), membership };
};
+56 -30
View File
@@ -29,6 +29,7 @@ import {
TDeleteOrgMembershipDTO,
TFindAllWorkspacesDTO,
TInviteUserToOrgDTO,
TUpdateOrgDTO,
TUpdateOrgMembershipDTO,
TVerifyUserToOrgDTO
} from "./org-types";
@@ -40,7 +41,7 @@ type TOrgServiceFactoryDep = {
userDAL: TUserDALFactory;
projectDAL: TProjectDALFactory;
incidentContactDAL: TIncidentContactsDALFactory;
samlConfigDAL: Pick<TSamlConfigDALFactory, "findOne">;
samlConfigDAL: Pick<TSamlConfigDALFactory, "findOne" | "findEnforceableSamlCfg">;
smtpService: TSmtpService;
tokenService: TAuthTokenServiceFactory;
permissionService: TPermissionServiceFactory;
@@ -68,8 +69,8 @@ export const orgServiceFactory = ({
/*
* Get organization details by the organization id
* */
const findOrganizationById = async (userId: string, orgId: string) => {
await permissionService.getUserOrgPermission(userId, orgId);
const findOrganizationById = async (userId: string, orgId: string, actorOrgId?: string) => {
await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
const org = await orgDAL.findOrgById(orgId);
if (!org) throw new BadRequestError({ name: "Org not found", message: "Organization not found" });
return org;
@@ -84,16 +85,16 @@ export const orgServiceFactory = ({
/*
* Get all workspace members
* */
const findAllOrgMembers = async (userId: string, orgId: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const findAllOrgMembers = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
const members = await orgDAL.findAllOrgMembers(orgId);
return members;
};
const findAllWorkspaces = async ({ actor, actorId, orgId }: TFindAllWorkspacesDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const findAllWorkspaces = async ({ actor, actorId, actorOrgId, orgId }: TFindAllWorkspacesDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Workspace);
const organizationWorkspaceIds = new Set((await projectDAL.find({ orgId })).map((workspace) => workspace.id));
@@ -118,12 +119,36 @@ export const orgServiceFactory = ({
};
/*
* Update organization settings
* Update organization details
* */
const updateOrgName = async (userId: string, orgId: string, name: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const updateOrg = async ({
actor,
actorId,
actorOrgId,
orgId,
data: { name, slug, authEnforced }
}: TUpdateOrgDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
const org = await orgDAL.updateById(orgId, { name });
if (authEnforced !== undefined) {
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
}
if (authEnforced) {
const samlCfg = await samlConfigDAL.findEnforceableSamlCfg(orgId);
if (!samlCfg)
throw new BadRequestError({
name: "No enforceable SAML config found",
message: "No enforceable SAML config found"
});
}
const org = await orgDAL.updateById(orgId, {
name,
slug: slug ? slugify(slug) : undefined,
authEnforced
});
if (!org) throw new BadRequestError({ name: "Org not found", message: "Organization not found" });
return org;
};
@@ -191,8 +216,8 @@ export const orgServiceFactory = ({
/*
* Delete organization by id
* */
const deleteOrganizationById = async (userId: string, orgId: string) => {
const { membership } = await permissionService.getUserOrgPermission(userId, orgId);
const deleteOrganizationById = async (userId: string, orgId: string, actorOrgId?: string) => {
const { membership } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
if ((membership.role as OrgMembershipRole) !== OrgMembershipRole.Admin)
throw new UnauthorizedError({ name: "Delete org by id", message: "Not an admin" });
@@ -206,8 +231,8 @@ export const orgServiceFactory = ({
* Org membership management
* Not another service because it has close ties with how an org works doesn't make sense to seperate them
* */
const updateOrgMembership = async ({ role, orgId, userId, membershipId }: TUpdateOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const updateOrgMembership = async ({ role, orgId, userId, membershipId, actorOrgId }: TUpdateOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Member);
const isCustomRole = !Object.values(OrgMembershipRole).includes(role as OrgMembershipRole);
@@ -237,16 +262,18 @@ export const orgServiceFactory = ({
/*
* Invite user to organization
*/
const inviteUserToOrganization = async ({ orgId, userId, inviteeEmail }: TInviteUserToOrgDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const inviteUserToOrganization = async ({ orgId, userId, inviteeEmail, actorOrgId }: TInviteUserToOrgDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Member);
const samlCfg = await samlConfigDAL.findOne({ orgId });
if (samlCfg && samlCfg.isActive) {
const org = await orgDAL.findOrgById(orgId);
if (org?.authEnforced) {
throw new BadRequestError({
message: "Failed to invite member due to SAML SSO configured for organization"
message: "Failed to invite user due to org-level auth enforced for organization"
});
}
const plan = await licenseService.getPlan(orgId);
if (plan.memberLimit !== null && plan.membersUsed >= plan.memberLimit) {
// case: limit imposed on number of members allowed
@@ -317,7 +344,6 @@ export const orgServiceFactory = ({
orgId
});
const org = await orgDAL.findOrgById(orgId);
const user = await userDAL.findById(userId);
const appCfg = getConfig();
await smtpService.sendMail({
@@ -394,8 +420,8 @@ export const orgServiceFactory = ({
return { token, user };
};
const deleteOrgMembership = async ({ orgId, userId, membershipId }: TDeleteOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const deleteOrgMembership = async ({ orgId, userId, membershipId, actorOrgId }: TDeleteOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member);
const membership = await orgDAL.deleteMembershipById(membershipId, orgId);
@@ -407,15 +433,15 @@ export const orgServiceFactory = ({
/*
* CRUD operations of incident contacts
* */
const findIncidentContacts = async (userId: string, orgId: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const findIncidentContacts = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.IncidentAccount);
const incidentContacts = await incidentContactDAL.findByOrgId(orgId);
return incidentContacts;
};
const createIncidentContact = async (userId: string, orgId: string, email: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const createIncidentContact = async (userId: string, orgId: string, email: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.IncidentAccount);
const doesIncidentContactExist = await incidentContactDAL.findOne(orgId, { email });
if (doesIncidentContactExist) {
@@ -429,8 +455,8 @@ export const orgServiceFactory = ({
return incidentContact;
};
const deleteIncidentContact = async (userId: string, orgId: string, id: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId);
const deleteIncidentContact = async (userId: string, orgId: string, id: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.IncidentAccount);
const incidentContact = await incidentContactDAL.deleteById(id, orgId);
@@ -443,7 +469,7 @@ export const orgServiceFactory = ({
findAllOrganizationOfUser,
inviteUserToOrganization,
verifyUserToOrg,
updateOrgName,
updateOrg,
createOrganization,
deleteOrganizationById,
deleteOrgMembership,
+10
View File
@@ -1,3 +1,5 @@
import { TOrgPermission } from "@app/lib/types";
import { ActorType } from "../auth/auth-type";
export type TUpdateOrgMembershipDTO = {
@@ -5,17 +7,20 @@ export type TUpdateOrgMembershipDTO = {
orgId: string;
membershipId: string;
role: string;
actorOrgId?: string;
};
export type TDeleteOrgMembershipDTO = {
userId: string;
orgId: string;
membershipId: string;
actorOrgId?: string;
};
export type TInviteUserToOrgDTO = {
userId: string;
orgId: string;
actorOrgId?: string;
inviteeEmail: string;
};
@@ -28,5 +33,10 @@ export type TVerifyUserToOrgDTO = {
export type TFindAllWorkspacesDTO = {
actor: ActorType;
actorId: string;
actorOrgId?: string;
orgId: string;
};
export type TUpdateOrgDTO = {
data: Partial<{ name: string; slug: string; authEnforced: boolean }>;
} & TOrgPermission;
@@ -71,8 +71,8 @@ export const projectBotServiceFactory = ({ projectBotDAL, permissionService }: T
});
};
const findBotByProjectId = async ({ actorId, actor, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const findBotByProjectId = async ({ actorId, actor, actorOrgId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Integrations);
const appCfg = getConfig();
@@ -120,11 +120,11 @@ export const projectBotServiceFactory = ({ projectBotDAL, permissionService }: T
return bot;
};
const setBotActiveState = async ({ actor, botId, botKey, actorId, isActive }: TSetActiveStateDTO) => {
const setBotActiveState = async ({ actor, botId, botKey, actorId, actorOrgId, isActive }: TSetActiveStateDTO) => {
const bot = await projectBotDAL.findById(botId);
if (!bot) throw new BadRequestError({ message: "Bot not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, bot.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, bot.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Integrations);
if (isActive) {
@@ -27,8 +27,8 @@ export const projectEnvServiceFactory = ({
projectDAL,
folderDAL
}: TProjectEnvServiceFactoryDep) => {
const createEnvironment = async ({ projectId, actorId, actor, name, slug }: TCreateEnvDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const createEnvironment = async ({ projectId, actorId, actor, actorOrgId, name, slug }: TCreateEnvDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Environments);
const envs = await projectEnvDAL.find({ projectId });
@@ -59,8 +59,17 @@ export const projectEnvServiceFactory = ({
return env;
};
const updateEnvironment = async ({ projectId, slug, actor, actorId, name, id, position }: TUpdateEnvDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const updateEnvironment = async ({
projectId,
slug,
actor,
actorId,
actorOrgId,
name,
id,
position
}: TUpdateEnvDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Environments);
const oldEnv = await projectEnvDAL.findOne({ id, projectId });
@@ -85,8 +94,8 @@ export const projectEnvServiceFactory = ({
return { environment: env, old: oldEnv };
};
const deleteEnvironment = async ({ projectId, actor, actorId, id }: TDeleteEnvDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteEnvironment = async ({ projectId, actor, actorId, actorOrgId, id }: TDeleteEnvDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Environments);
const env = await projectEnvDAL.transaction(async (tx) => {
@@ -25,11 +25,12 @@ export const projectKeyServiceFactory = ({
receiverId,
actor,
actorId,
actorOrgId,
projectId,
nonce,
encryptedKey
}: TUploadProjectKeyDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member);
const receiverMembership = await projectMembershipDAL.findOne({
@@ -45,14 +46,14 @@ export const projectKeyServiceFactory = ({
await projectKeyDAL.create({ projectId, receiverId, encryptedKey, nonce, senderId: actorId });
};
const getLatestProjectKey = async ({ actorId, projectId, actor }: TGetLatestProjectKeyDTO) => {
await permissionService.getProjectPermission(actor, actorId, projectId);
const getLatestProjectKey = async ({ actorId, projectId, actor, actorOrgId }: TGetLatestProjectKeyDTO) => {
await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
const latestKey = await projectKeyDAL.findLatestProjectKey(actorId, projectId);
return latestKey;
};
const getProjectPublicKeys = async ({ actor, actorId, projectId }: TGetLatestProjectKeyDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getProjectPublicKeys = async ({ actor, actorId, actorOrgId, projectId }: TGetLatestProjectKeyDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Member);
return projectKeyDAL.findAllProjectUserPubKeys(projectId);
};
@@ -48,15 +48,15 @@ export const projectMembershipServiceFactory = ({
projectKeyDAL,
licenseService
}: TProjectMembershipServiceFactoryDep) => {
const getProjectMemberships = async ({ actorId, actor, projectId }: TGetProjectMembershipDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getProjectMemberships = async ({ actorId, actor, actorOrgId, projectId }: TGetProjectMembershipDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Member);
return projectMembershipDAL.findAllProjectMembers(projectId);
};
const inviteUserToProject = async ({ actorId, actor, projectId, email }: TInviteUserToProjectDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const inviteUserToProject = async ({ actorId, actor, actorOrgId, projectId, email }: TInviteUserToProjectDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Member);
const invitee = await userDAL.findOne({ email });
@@ -112,11 +112,11 @@ export const projectMembershipServiceFactory = ({
return { invitee, latestKey };
};
const addUsersToProject = async ({ projectId, actorId, actor, members }: TAddUsersToWorkspaceDTO) => {
const addUsersToProject = async ({ projectId, actorId, actor, actorOrgId, members }: TAddUsersToWorkspaceDTO) => {
const project = await projectDAL.findById(projectId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Member);
const orgMembers = await orgDAL.findMembership({
orgId: project.orgId,
@@ -172,11 +172,12 @@ export const projectMembershipServiceFactory = ({
const updateProjectMembership = async ({
actorId,
actor,
actorOrgId,
projectId,
membershipId,
role
}: TUpdateProjectMembershipDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member);
const isCustomRole = !Object.values(ProjectMembershipRole).includes(role as ProjectMembershipRole);
@@ -204,8 +205,14 @@ export const projectMembershipServiceFactory = ({
return membership;
};
const deleteProjectMembership = async ({ actorId, actor, projectId, membershipId }: TDeleteProjectMembershipDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteProjectMembership = async ({
actorId,
actor,
actorOrgId,
projectId,
membershipId
}: TDeleteProjectMembershipDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Member);
const membership = await projectMembershipDAL.transaction(async (tx) => {
@@ -28,9 +28,10 @@ export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }:
actor: ActorType,
actorId: string,
projectId: string,
data: Omit<TProjectRolesInsert, "projectId">
data: Omit<TProjectRolesInsert, "projectId">,
actorOrgId?: string
) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Role);
const existingRole = await projectRoleDAL.findOne({ slug: data.slug, projectId });
if (existingRole) throw new BadRequestError({ name: "Create Role", message: "Duplicate role" });
@@ -47,9 +48,10 @@ export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }:
actorId: string,
projectId: string,
roleId: string,
data: Omit<TOrgRolesUpdate, "orgId">
data: Omit<TOrgRolesUpdate, "orgId">,
actorOrgId?: string
) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Role);
if (data?.slug) {
const existingRole = await projectRoleDAL.findOne({ slug: data.slug, projectId });
@@ -64,8 +66,14 @@ export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }:
return updatedRole;
};
const deleteRole = async (actor: ActorType, actorId: string, projectId: string, roleId: string) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteRole = async (
actor: ActorType,
actorId: string,
projectId: string,
roleId: string,
actorOrgId?: string
) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Role);
const [deletedRole] = await projectRoleDAL.delete({ id: roleId, projectId });
if (!deleteRole) throw new BadRequestError({ message: "Role not found", name: "Update role" });
@@ -73,8 +81,8 @@ export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }:
return deletedRole;
};
const listRoles = async (actor: ActorType, actorId: string, projectId: string) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const listRoles = async (actor: ActorType, actorId: string, projectId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
const customRoles = await projectRoleDAL.find({ projectId });
const roles = [
@@ -127,8 +135,8 @@ export const projectRoleServiceFactory = ({ projectRoleDAL, permissionService }:
return roles;
};
const getUserPermission = async (userId: string, projectId: string) => {
const { permission, membership } = await permissionService.getUserProjectPermission(userId, projectId);
const getUserPermission = async (userId: string, projectId: string, actorOrgId?: string) => {
const { permission, membership } = await permissionService.getUserProjectPermission(userId, projectId, actorOrgId);
return { permissions: packRules(permission.rules), membership };
};
@@ -48,8 +48,8 @@ export const projectServiceFactory = ({
/*
* Create workspace. Make user the admin
* */
const createProject = async ({ orgId, actor, actorId, workspaceName }: TCreateProjectDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const createProject = async ({ orgId, actor, actorId, actorOrgId, workspaceName }: TCreateProjectDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace);
const appCfg = getConfig();
@@ -106,8 +106,8 @@ export const projectServiceFactory = ({
return newProject;
};
const deleteProject = async ({ actor, actorId, projectId }: TDeleteProjectDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteProject = async ({ actor, actorId, actorOrgId, projectId }: TDeleteProjectDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Project);
const deletedProject = await projectDAL.deleteById(projectId);
@@ -119,8 +119,8 @@ export const projectServiceFactory = ({
return workspaces;
};
const getAProject = async ({ actorId, projectId, actor }: TGetProjectDTO) => {
await permissionService.getProjectPermission(actor, actorId, projectId);
const getAProject = async ({ actorId, actorOrgId, projectId, actor }: TGetProjectDTO) => {
await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
return projectDAL.findProjectById(projectId);
};
@@ -128,17 +128,18 @@ export const projectServiceFactory = ({
projectId,
actor,
actorId,
actorOrgId,
autoCapitalization
}: TGetProjectDTO & { autoCapitalization: boolean }) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
const updatedProject = await projectDAL.updateById(projectId, { autoCapitalization });
return updatedProject;
};
const updateName = async ({ projectId, actor, actorId, name }: TGetProjectDTO & { name: string }) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const updateName = async ({ projectId, actor, actorId, actorOrgId, name }: TGetProjectDTO & { name: string }) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Settings);
const updatedProject = await projectDAL.updateById(projectId, { name });
@@ -3,6 +3,7 @@ import { ActorType } from "../auth/auth-type";
export type TCreateProjectDTO = {
actor: ActorType;
actorId: string;
actorOrgId?: string;
orgId: string;
workspaceName: string;
};
@@ -10,11 +11,13 @@ export type TCreateProjectDTO = {
export type TDeleteProjectDTO = {
actor: ActorType;
actorId: string;
actorOrgId?: string;
projectId: string;
};
export type TGetProjectDTO = {
actor: ActorType;
actorId: string;
actorOrgId?: string;
projectId: string;
};
@@ -24,8 +24,13 @@ export const secretBlindIndexServiceFactory = ({
permissionService,
secretDAL
}: TSecretBlindIndexServiceFactoryDep) => {
const getSecretBlindIndexStatus = async ({ actor, projectId, actorId }: TGetProjectBlindIndexStatusDTO) => {
await permissionService.getProjectPermission(actor, actorId, projectId);
const getSecretBlindIndexStatus = async ({
actor,
projectId,
actorId,
actorOrgId
}: TGetProjectBlindIndexStatusDTO) => {
await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
const secretCount = await secretBlindIndexDAL.countOfSecretsWithNullSecretBlindIndex(projectId);
return Number(secretCount);
@@ -45,9 +50,10 @@ export const secretBlindIndexServiceFactory = ({
projectId,
actor,
actorId,
actorOrgId,
secretsToUpdate
}: TUpdateProjectSecretNameDTO) => {
const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
if (membership?.role !== ProjectMembershipRole.Admin) {
throw new UnauthorizedError({ message: "User must be admin" });
}
@@ -30,8 +30,16 @@ export const secretFolderServiceFactory = ({
projectEnvDAL,
folderVersionDAL
}: TSecretFolderServiceFactoryDep) => {
const createFolder = async ({ projectId, actor, actorId, name, environment, path: secretPath }: TCreateFolderDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const createFolder = async ({
projectId,
actor,
actorId,
actorOrgId,
name,
environment,
path: secretPath
}: TCreateFolderDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
@@ -105,12 +113,13 @@ export const secretFolderServiceFactory = ({
projectId,
actor,
actorId,
actorOrgId,
name,
environment,
path: secretPath,
id
}: TUpdateFolderDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
@@ -148,8 +157,16 @@ export const secretFolderServiceFactory = ({
return { folder: newFolder, old: folder };
};
const deleteFolder = async ({ projectId, actor, actorId, environment, path: secretPath, id }: TDeleteFolderDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteFolder = async ({
projectId,
actor,
actorId,
actorOrgId,
environment,
path: secretPath,
id
}: TDeleteFolderDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
@@ -171,10 +188,17 @@ export const secretFolderServiceFactory = ({
return folder;
};
const getFolders = async ({ projectId, actor, actorId, environment, path: secretPath }: TGetFolderDTO) => {
const getFolders = async ({
projectId,
actor,
actorId,
actorOrgId,
environment,
path: secretPath
}: TGetFolderDTO) => {
// folder list is allowed to be read by anyone
// permission to check does user has access
await permissionService.getProjectPermission(actor, actorId, projectId);
await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
const env = await projectEnvDAL.findOne({ projectId, slug: environment });
if (!env) throw new BadRequestError({ message: "Environment not found", name: "get folders" });
@@ -36,8 +36,16 @@ export const secretImportServiceFactory = ({
folderDAL,
secretDAL
}: TSecretImportServiceFactoryDep) => {
const createImport = async ({ environment, data, actor, actorId, projectId, path }: TCreateSecretImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const createImport = async ({
environment,
data,
actor,
actorId,
actorOrgId,
projectId,
path
}: TCreateSecretImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
// check if user has permission to import into destination path
ForbiddenError.from(permission).throwUnlessCan(
@@ -77,8 +85,17 @@ export const secretImportServiceFactory = ({
return { ...secImport, importEnv };
};
const updateImport = async ({ path, environment, projectId, actor, actorId, data, id }: TUpdateSecretImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const updateImport = async ({
path,
environment,
projectId,
actor,
actorId,
actorOrgId,
data,
id
}: TUpdateSecretImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -115,8 +132,16 @@ export const secretImportServiceFactory = ({
return { ...updatedSecImport, importEnv: importedEnv };
};
const deleteImport = async ({ path, environment, projectId, actor, actorId, id }: TDeleteSecretImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteImport = async ({
path,
environment,
projectId,
actor,
actorId,
actorOrgId,
id
}: TDeleteSecretImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -137,8 +162,8 @@ export const secretImportServiceFactory = ({
return secImport;
};
const getImports = async ({ path, environment, projectId, actor, actorId }: TGetSecretImportsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getImports = async ({ path, environment, projectId, actor, actorId, actorOrgId }: TGetSecretImportsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -151,8 +176,15 @@ export const secretImportServiceFactory = ({
return secImports;
};
const getSecretsFromImports = async ({ path, environment, projectId, actor, actorId }: TGetSecretsFromImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getSecretsFromImports = async ({
path,
environment,
projectId,
actor,
actorId,
actorOrgId
}: TGetSecretsFromImportDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -15,8 +15,8 @@ type TSecretTagServiceFactoryDep = {
export type TSecretTagServiceFactory = ReturnType<typeof secretTagServiceFactory>;
export const secretTagServiceFactory = ({ secretTagDAL, permissionService }: TSecretTagServiceFactoryDep) => {
const createTag = async ({ name, slug, actor, color, actorId, projectId }: TCreateTagDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const createTag = async ({ name, slug, actor, color, actorId, actorOrgId, projectId }: TCreateTagDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Tags);
const existingTag = await secretTagDAL.findOne({ slug });
@@ -32,19 +32,19 @@ export const secretTagServiceFactory = ({ secretTagDAL, permissionService }: TSe
return newTag;
};
const deleteTag = async ({ actorId, actor, id }: TDeleteTagDTO) => {
const deleteTag = async ({ actorId, actor, actorOrgId, id }: TDeleteTagDTO) => {
const tag = await secretTagDAL.findById(id);
if (!tag) throw new BadRequestError({ message: "Tag doesn't exist" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, tag.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, tag.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Tags);
const deletedTag = await secretTagDAL.deleteById(tag.id);
return deletedTag;
};
const getProjectTags = async ({ actor, actorId, projectId }: TListProjectTagsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getProjectTags = async ({ actor, actorId, actorOrgId, projectId }: TListProjectTagsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Tags);
const tags = await secretTagDAL.find({ projectId }, { sort: [["createdAt", "asc"]] });
+77 -32
View File
@@ -37,7 +37,6 @@ import {
TGetSecretsDTO,
TGetSecretsRawDTO,
TGetSecretVersionsDTO,
TListSecretVersionDTO,
TUpdateBulkSecretDTO,
TUpdateSecretDTO,
TUpdateSecretRawDTO
@@ -267,8 +266,16 @@ export const secretServiceFactory = ({
return { secsGroupedByBlindIndex, secrets };
};
const createSecret = async ({ path, actor, actorId, environment, projectId, ...inputSecret }: TCreateSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const createSecret = async ({
path,
actor,
actorId,
actorOrgId,
environment,
projectId,
...inputSecret
}: TCreateSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -337,8 +344,16 @@ export const secretServiceFactory = ({
return { ...secret[0], environment, workspace: projectId, tags };
};
const updateSecret = async ({ path, actor, actorId, environment, projectId, ...inputSecret }: TUpdateSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const updateSecret = async ({
path,
actor,
actorId,
actorOrgId,
environment,
projectId,
...inputSecret
}: TUpdateSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -429,8 +444,16 @@ export const secretServiceFactory = ({
return { ...updatedSecret[0], workspace: projectId, environment };
};
const deleteSecret = async ({ path, actor, actorId, environment, projectId, ...inputSecret }: TDeleteSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteSecret = async ({
path,
actor,
actorId,
actorOrgId,
environment,
projectId,
...inputSecret
}: TDeleteSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -476,8 +499,16 @@ export const secretServiceFactory = ({
return { ...deletedSecret[0], _id: deletedSecret[0].id, workspace: projectId, environment };
};
const getSecrets = async ({ actorId, path, environment, projectId, actor, includeImports }: TGetSecretsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getSecrets = async ({
actorId,
path,
environment,
projectId,
actor,
actorOrgId,
includeImports
}: TGetSecretsDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -518,6 +549,7 @@ export const secretServiceFactory = ({
const getSecretByName = async ({
actorId,
actor,
actorOrgId,
projectId,
environment,
path,
@@ -526,7 +558,7 @@ export const secretServiceFactory = ({
version,
includeImports
}: TGetASecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -607,11 +639,12 @@ export const secretServiceFactory = ({
path,
actor,
actorId,
actorOrgId,
environment,
projectId,
secrets: inputSecrets
}: TCreateBulkSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -661,11 +694,12 @@ export const secretServiceFactory = ({
path,
actor,
actorId,
actorOrgId,
environment,
projectId,
secrets: inputSecrets
}: TUpdateBulkSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -733,9 +767,10 @@ export const secretServiceFactory = ({
environment,
projectId,
actor,
actorId
actorId,
actorOrgId
}: TDeleteBulkSecretDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
@@ -774,20 +809,15 @@ export const secretServiceFactory = ({
return secretsDeleted;
};
const listSecretVersionsBySecretId = async ({ actorId, actor, limit, offset, secretId }: TListSecretVersionDTO) => {
const secret = await secretDAL.findById(secretId);
if (!secret) throw new BadRequestError({ message: "Failed to find secret" });
const folder = await folderDAL.findById(secret.folderId);
if (!folder) throw new BadRequestError({ message: "Folder not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, folder.projectId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
const secretVersions = await secretVersionDAL.find({ secretId }, { limit, offset, sort: [["createdAt", "desc"]] });
return secretVersions;
};
const getSecretsRaw = async ({ projectId, path, actor, actorId, environment, includeImports }: TGetSecretsRawDTO) => {
const getSecretsRaw = async ({
projectId,
path,
actor,
actorId,
actorOrgId,
environment,
includeImports
}: TGetSecretsRawDTO) => {
const botKey = await projectBotService.getBotKey(projectId);
if (!botKey) throw new BadRequestError({ message: "Project bot not found", name: "bot_not_found_error" });
@@ -796,6 +826,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
path,
includeImports
});
@@ -818,6 +849,7 @@ export const secretServiceFactory = ({
environment,
projectId,
actorId,
actorOrgId,
secretName,
includeImports,
version
@@ -830,6 +862,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
path,
secretName,
type,
@@ -845,6 +878,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
type,
secretPath,
secretValue,
@@ -866,6 +900,7 @@ export const secretServiceFactory = ({
path: secretPath,
actor,
actorId,
actorOrgId,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
@@ -890,6 +925,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
type,
secretPath,
secretValue,
@@ -908,6 +944,7 @@ export const secretServiceFactory = ({
path: secretPath,
actor,
actorId,
actorOrgId,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
@@ -926,6 +963,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
type,
secretPath
}: TDeleteSecretRawDTO) => {
@@ -939,7 +977,8 @@ export const secretServiceFactory = ({
type,
path: secretPath,
actor,
actorId
actorId,
actorOrgId
});
await snapshotService.performSnapshot(secret.folderId);
@@ -948,14 +987,21 @@ export const secretServiceFactory = ({
return decryptSecretRaw(secret, botKey);
};
const getSecretVersions = async ({ actorId, actor, limit = 20, offset = 0, secretId }: TGetSecretVersionsDTO) => {
const getSecretVersions = async ({
actorId,
actor,
actorOrgId,
limit = 20,
offset = 0,
secretId
}: TGetSecretVersionsDTO) => {
const secret = await secretDAL.findById(secretId);
if (!secret) throw new BadRequestError({ message: "Failed to find secret" });
const folder = await folderDAL.findById(secret.folderId);
if (!folder) throw new BadRequestError({ message: "Failed to find secret" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, folder.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, folder.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
const secretVersions = await secretVersionDAL.find({ secretId }, { offset, limit, sort: [["createdAt", "desc"]] });
@@ -976,7 +1022,6 @@ export const secretServiceFactory = ({
createSecretRaw,
updateSecretRaw,
deleteSecretRaw,
listSecretVersionsBySecretId,
getSecretVersions,
// external services function
fnSecretBulkDelete,
@@ -128,12 +128,6 @@ export type TDeleteBulkSecretDTO = {
}>;
} & TProjectPermission;
export type TListSecretVersionDTO = {
secretId: string;
offset?: number;
limit?: number;
} & Omit<TProjectPermission, "projectId">;
export type TGetSecretsRawDTO = {
path: string;
environment: string;
@@ -39,6 +39,7 @@ export const serviceTokenServiceFactory = ({
tag,
name,
actor,
actorOrgId,
scopes,
actorId,
projectId,
@@ -46,7 +47,7 @@ export const serviceTokenServiceFactory = ({
permissions,
encryptedKey
}: TCreateServiceTokenDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.ServiceTokens);
scopes.forEach(({ environment, secretPath }) => {
@@ -90,11 +91,16 @@ export const serviceTokenServiceFactory = ({
return { token, serviceToken };
};
const deleteServiceToken = async ({ actorId, actor, id }: TDeleteServiceTokenDTO) => {
const deleteServiceToken = async ({ actorId, actor, actorOrgId, id }: TDeleteServiceTokenDTO) => {
const serviceToken = await serviceTokenDAL.findById(id);
if (!serviceToken) throw new BadRequestError({ message: "Token not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, serviceToken.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
serviceToken.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.ServiceTokens);
const deletedServiceToken = await serviceTokenDAL.deleteById(id);
@@ -113,8 +119,8 @@ export const serviceTokenServiceFactory = ({
return { serviceToken, user: serviceTokenUser };
};
const getProjectServiceTokens = async ({ actorId, actor, projectId }: TProjectServiceTokensDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getProjectServiceTokens = async ({ actorId, actor, actorOrgId, projectId }: TProjectServiceTokensDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.ServiceTokens);
const tokens = await serviceTokenDAL.find({ projectId }, { sort: [["createdAt", "desc"]] });
@@ -99,7 +99,12 @@ export const superAdminServiceFactory = ({
await orgService.createOrganization(userInfo.user.id, userInfo.user.email, initialOrganizationName);
await updateServerCfg({ initialized: true });
const token = await authService.generateUserTokens(userInfo.user, ip, userAgent);
const token = await authService.generateUserTokens({
user: userInfo.user,
ip,
userAgent,
organizationId: undefined
});
// TODO(akhilmhdh-pg): telemetry service
return { token, user: userInfo };
};
@@ -30,15 +30,6 @@ export const userServiceFactory = ({ userDAL }: TUserServiceFactoryDep) => {
const user = await userDAL.findById(userId);
if (!user) throw new BadRequestError({ name: "Update auth methods" });
const hasSamlEnabled = user?.authMethods?.some((method) =>
[AuthMethod.OKTA_SAML, AuthMethod.AZURE_SAML, AuthMethod.JUMPCLOUD_SAML].includes(method as AuthMethod)
);
if (hasSamlEnabled)
throw new BadRequestError({
name: "Update auth method",
message: "Failed to update auth methods due to SAML SSO "
});
const updatedUser = await userDAL.updateById(userId, { authMethods });
return updatedUser;
};
@@ -30,13 +30,14 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer
const createWebhook = async ({
actor,
actorId,
actorOrgId,
projectId,
webhookUrl,
environment,
secretPath,
webhookSecretKey
}: TCreateWebhookDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Webhooks);
const env = await projectEnvDAL.findOne({ projectId, slug: environment });
if (!env) throw new BadRequestError({ message: "Env not found" });
@@ -72,33 +73,33 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer
return { ...webhook, projectId, environment: env };
};
const updateWebhook = async ({ actorId, actor, id, isDisabled }: TUpdateWebhookDTO) => {
const updateWebhook = async ({ actorId, actor, actorOrgId, id, isDisabled }: TUpdateWebhookDTO) => {
const webhook = await webhookDAL.findById(id);
if (!webhook) throw new BadRequestError({ message: "Webhook not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Webhooks);
const updatedWebhook = await webhookDAL.updateById(id, { isDisabled });
return { ...webhook, ...updatedWebhook };
};
const deleteWebhook = async ({ id, actor, actorId }: TDeleteWebhookDTO) => {
const deleteWebhook = async ({ id, actor, actorId, actorOrgId }: TDeleteWebhookDTO) => {
const webhook = await webhookDAL.findById(id);
if (!webhook) throw new BadRequestError({ message: "Webhook not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Delete, ProjectPermissionSub.Webhooks);
const deletedWebhook = await webhookDAL.deleteById(id);
return { ...webhook, ...deletedWebhook };
};
const testWebhook = async ({ id, actor, actorId }: TTestWebhookDTO) => {
const testWebhook = async ({ id, actor, actorId, actorOrgId }: TTestWebhookDTO) => {
const webhook = await webhookDAL.findById(id);
if (!webhook) throw new BadRequestError({ message: "Webhook not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, webhook.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks);
let webhookError: string | undefined;
@@ -118,8 +119,8 @@ export const webhookServiceFactory = ({ webhookDAL, projectEnvDAL, permissionSer
return { ...webhook, ...updatedWebhook };
};
const listWebhooks = async ({ actorId, actor, projectId, secretPath, environment }: TListWebhookDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const listWebhooks = async ({ actorId, actor, actorOrgId, projectId, secretPath, environment }: TListWebhookDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Webhooks);
return webhookDAL.findAllWebhooks(projectId, environment, secretPath);