Compare commits

..

24 Commits

Author SHA1 Message Date
069b0cd6fb Fix lint issue, add backend permission check for SAML SSO enforcement toggle 2024-02-09 10:02:12 -08:00
ed23bd40d2 Redirect to SAML portal upon enforcing SAML SSO 2024-02-09 09:50:20 -08:00
82181f078a Patch login with SAML when config is inactive 2024-02-09 09:35:51 -08:00
a9a5e92358 Empty 2024-02-09 09:02:22 -08:00
5878a221f8 Run lint fix 2024-02-09 08:44:30 -08:00
fdbf59cd78 Redirect users to SAML portal on change org to SAML org 2024-02-09 08:31:19 -08:00
2cc2a91812 Change update slug fallback to undefined 2024-02-08 17:47:58 -08:00
92828b5295 add slug index 2024-02-08 20:47:33 -05:00
4e2f2281f9 Update orgScope to orgId naming for org-level auth ref, rewire user invite saml block to org authEnforce field 2024-02-08 17:29:21 -08:00
22d89d791c Patch new org creation condition on SAML account signup, enable users to toggle auth methods regardless of what org they are in 2024-02-07 12:13:09 -08:00
3f8ce42682 Merge remote-tracking branch 'origin' into org-based-auth 2024-02-07 09:49:13 -08:00
3ecfb3f9d2 Show usage and billing tab on cloud only 2024-02-07 09:45:42 -08:00
9011394c34 Add validation to org slug 2024-02-07 09:39:06 -08:00
c0096ca64c Merge pull request #1378 from Infisical/patch-service-token-fetch
patch get secret by name
2024-02-07 23:00:20 +05:30
8bc952388c add log 2024-02-07 12:23:48 -05:00
eef29cd2d4 patch get secret by name 2024-02-07 12:11:58 -05:00
6ef873f3a0 Merge pull request #1377 from Infisical/allow-name-initial-org
add initial org rename
2024-02-07 20:51:30 +05:30
fe99c12c0d add initial org rename 2024-02-07 10:18:41 -05:00
332b0e2cc3 Merge pull request #1374 from Infisical/admin-ui-fix
fix admin dashboard styling
2024-02-07 12:18:09 +05:30
fc7015de83 Add lockout-preventative step in saml config setup, add update org slug section in org settings, revise navigate to org flow to account for org-level auth enforced orgs 2024-02-06 15:51:24 -08:00
c1aa5c840c Add org-scoped auth to project-level endpoints 2024-02-05 14:48:02 -08:00
410476ecb5 Merge remote-tracking branch 'origin' into org-based-auth 2024-02-04 15:03:43 -08:00
f1c41be7d4 Resolve merge conflicts 2024-02-04 15:02:43 -08:00
f138973ac7 Add org-scoped auth to org-level endpoints, add migration file for org enableAuth field 2024-02-04 14:44:08 -08:00
114 changed files with 1605 additions and 1121 deletions

View File

@ -125,4 +125,4 @@
"zod": "^3.22.4",
"zod-to-json-schema": "^3.22.0"
}
}
}

View File

@ -51,6 +51,7 @@ declare module "fastify" {
// used for mfa session authentication
mfa: {
userId: string;
orgId?: string;
user: TUsers;
};
// identity injection. depending on which kinda of token the information is filled in auth
@ -58,6 +59,7 @@ declare module "fastify" {
permission: {
type: ActorType;
id: string;
orgId?: string;
};
// passport data
passportUser: {

View File

@ -0,0 +1,25 @@
import { Knex } from "knex";
import { TableName } from "../schemas";
export async function up(knex: Knex): Promise<void> {
await knex.schema.alterTable(TableName.Organization, (t) => {
t.boolean("authEnforced").defaultTo(false);
t.index("slug");
});
await knex.schema.alterTable(TableName.SamlConfig, (t) => {
t.datetime("lastUsed");
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.alterTable(TableName.Organization, (t) => {
t.dropColumn("authEnforced");
t.dropIndex("slug");
});
await knex.schema.alterTable(TableName.SamlConfig, (t) => {
t.dropColumn("lastUsed");
});
}

View File

@ -13,7 +13,8 @@ export const OrganizationsSchema = z.object({
customerId: z.string().nullable().optional(),
slug: z.string(),
createdAt: z.date(),
updatedAt: z.date()
updatedAt: z.date(),
authEnforced: z.boolean().default(false).nullable().optional()
});
export type TOrganizations = z.infer<typeof OrganizationsSchema>;

View File

@ -22,7 +22,8 @@ export const SamlConfigsSchema = z.object({
certTag: z.string().nullable().optional(),
createdAt: z.date(),
updatedAt: z.date(),
orgId: z.string().uuid()
orgId: z.string().uuid(),
lastUsed: z.date().nullable().optional()
});
export type TSamlConfigs = z.infer<typeof SamlConfigsSchema>;

View File

@ -22,6 +22,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgPlansTableByBillCycle({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
billingCycle: req.query.billingCycle
});
@ -43,6 +44,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const plan = await server.services.license.getOrgPlan({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return { plan };
@ -85,6 +87,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.startOrgTrial({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
success_url: req.body.success_url
});
@ -106,6 +109,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.createOrganizationPortalSession({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;
@ -126,6 +130,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgBillingInfo({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;
@ -146,6 +151,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgPlanTable({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;
@ -166,6 +172,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgBillingDetails({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;
@ -190,6 +197,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.updateOrgBillingDetails({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
name: req.body.name,
email: req.body.email
@ -212,6 +220,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgPmtMethods({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;
@ -236,6 +245,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.addOrgPmtMethods({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
success_url: req.body.success_url,
cancel_url: req.body.cancel_url
@ -261,6 +271,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.delOrgPmtMethods({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
pmtMethodId: req.params.pmtMethodId
});
@ -284,6 +295,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgTaxIds({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;
@ -310,6 +322,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.addOrgTaxId({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
type: req.body.type,
value: req.body.value
@ -335,6 +348,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.delOrgTaxId({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
taxId: req.params.taxId
});
@ -358,6 +372,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgTaxInvoices({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;
@ -380,6 +395,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
const data = await server.services.license.getOrgLicenses({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return data;

View File

@ -26,7 +26,12 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const role = await server.services.orgRole.createRole(req.permission.id, req.params.organizationId, req.body);
const role = await server.services.orgRole.createRole(
req.permission.id,
req.params.organizationId,
req.body,
req.permission.orgId
);
return { role };
}
});
@ -57,7 +62,8 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
req.permission.id,
req.params.organizationId,
req.params.roleId,
req.body
req.body,
req.permission.orgId
);
return { role };
}
@ -82,7 +88,8 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
const role = await server.services.orgRole.deleteRole(
req.permission.id,
req.params.organizationId,
req.params.roleId
req.params.roleId,
req.permission.orgId
);
return { role };
}
@ -107,7 +114,11 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const roles = await server.services.orgRole.listRoles(req.permission.id, req.params.organizationId);
const roles = await server.services.orgRole.listRoles(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { data: { roles } };
}
});
@ -130,7 +141,8 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
handler: async (req) => {
const { permissions, membership } = await server.services.orgRole.getUserPermission(
req.permission.id,
req.params.organizationId
req.params.organizationId,
req.permission.orgId
);
return { permissions, membership };
}

View File

@ -30,7 +30,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
req.permission.type,
req.permission.id,
req.params.projectId,
req.body
req.body,
req.permission.orgId
);
return { role };
}
@ -63,7 +64,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
req.permission.id,
req.params.projectId,
req.params.roleId,
req.body
req.body,
req.permission.orgId
);
return { role };
}
@ -89,7 +91,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
req.permission.type,
req.permission.id,
req.params.projectId,
req.params.roleId
req.params.roleId,
req.permission.orgId
);
return { role };
}
@ -117,7 +120,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
const roles = await server.services.projectRole.listRoles(
req.permission.type,
req.permission.id,
req.params.projectId
req.params.projectId,
req.permission.orgId
);
return { data: { roles } };
}
@ -143,7 +147,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
handler: async (req) => {
const { permissions, membership } = await server.services.projectRole.getUserPermission(
req.permission.id,
req.params.projectId
req.params.projectId,
req.permission.orgId
);
return { data: { permissions, membership } };
}

View File

@ -31,6 +31,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const secretSnapshots = await server.services.snapshot.listSnapshots({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
...req.query
});
@ -60,6 +61,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const count = await server.services.snapshot.projectSecretSnapshotCount({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
environment: req.query.environment,
path: req.query.path
@ -112,6 +114,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
handler: async (req) => {
const auditLogs = await server.services.auditLog.listProjectAuditLogs({
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
...req.query,
auditLogActor: req.query.actor,

View File

@ -13,7 +13,7 @@ import { FastifyRequest } from "fastify";
import { z } from "zod";
import { SamlConfigsSchema } from "@app/db/schemas";
import { SamlProviders } from "@app/ee/services/saml-config/saml-config-types";
import { SamlProviders, TGetSamlCfgDTO } from "@app/ee/services/saml-config/saml-config-types";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
@ -44,17 +44,30 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
// eslint-disable-next-line
getSamlOptions: async (req, done) => {
try {
const { ssoIdentifier } = req.params;
if (!ssoIdentifier) throw new BadRequestError({ message: "Missing sso identitier" });
const { samlConfigId, orgSlug } = req.params;
const ssoConfig = await server.services.saml.getSaml({
type: "ssoId",
id: ssoIdentifier
});
if (!ssoConfig) throw new BadRequestError({ message: "SSO config not found" });
let ssoLookupDetails: TGetSamlCfgDTO;
if (orgSlug) {
ssoLookupDetails = {
type: "orgSlug",
orgSlug
};
} else if (samlConfigId) {
ssoLookupDetails = {
type: "ssoId",
id: samlConfigId
};
} else {
throw new BadRequestError({ message: "Missing sso identitier or org slug" });
}
const ssoConfig = await server.services.saml.getSaml(ssoLookupDetails);
if (!ssoConfig || !ssoConfig.isActive)
throw new BadRequestError({ message: "Failed to authenticate with SAML SSO" });
const samlConfig: TSAMLConfig = {
callbackUrl: `${appCfg.SITE_URL}/api/v1/sso/saml2/${ssoIdentifier}`,
callbackUrl: `${appCfg.SITE_URL}/api/v1/sso/saml2/${samlConfigId}`,
entryPoint: ssoConfig.entryPoint,
issuer: ssoConfig.issuer,
cert: ssoConfig.cert,
@ -108,11 +121,11 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
);
server.route({
url: "/redirect/saml2/:ssoIdentifier",
url: "/redirect/saml2/organizations/:orgSlug",
method: "GET",
schema: {
params: z.object({
ssoIdentifier: z.string().trim()
orgSlug: z.string().trim()
}),
querystring: z.object({
callback_port: z.string().optional()
@ -134,11 +147,37 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
});
server.route({
url: "/saml2/:ssoIdentifier",
url: "/redirect/saml2/:samlConfigId",
method: "GET",
schema: {
params: z.object({
samlConfigId: z.string().trim()
}),
querystring: z.object({
callback_port: z.string().optional()
})
},
preValidation: (req, res) =>
(
passport.authenticate("saml", {
failureRedirect: "/",
additionalParams: {
RelayState: JSON.stringify({
spInitiated: true,
callbackPort: req.query.callback_port ?? ""
})
}
} as any) as any
)(req, res),
handler: () => {}
});
server.route({
url: "/saml2/:samlConfigId",
method: "POST",
schema: {
params: z.object({
ssoIdentifier: z.string().trim()
samlConfigId: z.string().trim()
})
},
preValidation: passport.authenticate("saml", {
@ -177,7 +216,8 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
isActive: z.boolean(),
entryPoint: z.string(),
issuer: z.string(),
cert: z.string()
cert: z.string(),
lastUsed: z.date().nullable().optional()
})
.optional()
}
@ -186,6 +226,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
const saml = await server.services.saml.getSaml({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.query.organizationId,
type: "org"
});
@ -214,6 +255,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
const saml = await server.services.saml.createSamlCfg({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.body.organizationId,
...req.body
});
@ -244,6 +286,7 @@ export const registerSamlRouter = async (server: FastifyZodProvider) => {
const saml = await server.services.saml.updateSamlCfg({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.body.organizationId,
...req.body
});

View File

@ -34,6 +34,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approval = await server.services.secretApprovalPolicy.createSecretApprovalPolicy({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId,
...req.body,
name: req.body.name ?? `${req.body.environment}-${nanoid(3)}`
@ -71,6 +72,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approval = await server.services.secretApprovalPolicy.updateSecretApprovalPolicy({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body,
secretPolicyId: req.params.sapId
});
@ -96,6 +98,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approval = await server.services.secretApprovalPolicy.deleteSecretApprovalPolicy({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
secretPolicyId: req.params.sapId
});
return { approval };
@ -120,6 +123,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const approvals = await server.services.secretApprovalPolicy.getSecretApprovalPolicyByProjectId({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId
});
return { approvals };
@ -146,6 +150,7 @@ export const registerSecretApprovalPolicyRouter = async (server: FastifyZodProvi
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId,
...req.query
});

View File

@ -52,6 +52,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approvals = await server.services.secretApprovalRequest.getSecretApprovals({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId
});
@ -80,6 +81,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approvals = await server.services.secretApprovalRequest.requestCount({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId
});
return { approvals };
@ -104,6 +106,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const { approval } = await server.services.secretApprovalRequest.mergeSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
approvalId: req.params.id
});
return { approval };
@ -131,6 +134,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const review = await server.services.secretApprovalRequest.reviewApproval({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
approvalId: req.params.id,
status: req.body.status
});
@ -159,6 +163,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approval = await server.services.secretApprovalRequest.updateApprovalStatus({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
approvalId: req.params.id,
status: req.body.status
});
@ -266,6 +271,7 @@ export const registerSecretApprovalRequestRouter = async (server: FastifyZodProv
const approval = await server.services.secretApprovalRequest.getSecretApprovalDetails({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.id
});
return { approval };

View File

@ -30,6 +30,7 @@ export const registerSecretRotationProviderRouter = async (server: FastifyZodPro
const providers = await server.services.secretRotation.getProviderTemplates({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return providers;

View File

@ -40,6 +40,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotation = await server.services.secretRotation.createRotation({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId
});
@ -73,6 +74,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotation = await server.services.secretRotation.restartById({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
rotationId: req.body.id
});
return { secretRotation };
@ -123,6 +125,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotations = await server.services.secretRotation.getByProjectId({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.query.workspaceId
});
return { secretRotations };
@ -155,6 +158,7 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) =
const secretRotation = await server.services.secretRotation.deleteById({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
rotationId: req.params.id
});
return { secretRotation };

View File

@ -22,6 +22,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const session = await server.services.secretScanning.createInstallationSession({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.body.organizationId
});
return session;
@ -45,6 +46,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const { installatedApp } = await server.services.secretScanning.linkInstallationToOrg({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body
});
return installatedApp;
@ -65,6 +67,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const appInstallationCompleted = await server.services.secretScanning.getOrgInstallationStatus({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return { appInstallationCompleted };
@ -85,6 +88,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const { risks } = await server.services.secretScanning.getRisksByOrg({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
return { risks };
@ -106,6 +110,7 @@ export const registerSecretScanningRouter = async (server: FastifyZodProvider) =
const { risk } = await server.services.secretScanning.updateRiskStatus({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
riskId: req.params.riskId,
...req.body

View File

@ -27,6 +27,7 @@ export const registerSecretVersionRouter = async (server: FastifyZodProvider) =>
const secretVersions = await server.services.secret.getSecretVersions({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
limit: req.query.limit,
offset: req.query.offset,
secretId: req.params.secretId

View File

@ -46,6 +46,7 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
const secretSnapshot = await server.services.snapshot.getSnapshotData({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.secretSnapshotId
});
return { secretSnapshot };
@ -70,6 +71,7 @@ export const registerSnapshotRouter = async (server: FastifyZodProvider) => {
const secretSnapshot = await server.services.snapshot.rollbackSnapshot({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.secretSnapshotId
});
return { secretSnapshot };

View File

@ -24,7 +24,8 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
const trustedIps = await server.services.trustedIp.listIpsByProjectId({
projectId: req.params.workspaceId,
actor: req.permission.type,
actorId: req.permission.id
actorId: req.permission.id,
actorOrgId: req.permission.orgId
});
return { trustedIps };
}
@ -54,6 +55,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body
});
await server.services.auditLog.createAuditLog({
@ -97,6 +99,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
trustedIpId: req.params.trustedIpId,
...req.body
});
@ -137,6 +140,7 @@ export const registerTrustedIpRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
trustedIpId: req.params.trustedIpId
});
await server.services.auditLog.createAuditLog({

View File

@ -30,10 +30,11 @@ export const auditLogServiceFactory = ({
startDate,
actor,
actorId,
actorOrgId,
projectId,
auditLogActor
}: TListProjectAuditLogDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.AuditLogs);
const auditLogs = await auditLogDAL.find({
startDate,

View File

@ -175,8 +175,14 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
};
// below all are api calls
const getOrgPlansTableByBillCycle = async ({ orgId, actor, actorId, billingCycle }: TOrgPlansTableDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgPlansTableByBillCycle = async ({
orgId,
actor,
actorId,
actorOrgId,
billingCycle
}: TOrgPlansTableDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const { data } = await licenseServerCloudApi.request.get(
`/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
@ -184,15 +190,15 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data;
};
const getOrgPlan = async ({ orgId, actor, actorId, projectId }: TOrgPlanDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgPlan = async ({ orgId, actor, actorId, actorOrgId, projectId }: TOrgPlanDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const plan = await getPlan(orgId, projectId);
return plan;
};
const startOrgTrial = async ({ orgId, actorId, actor, success_url }: TStartOrgTrialDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const startOrgTrial = async ({ orgId, actorId, actor, actorOrgId, success_url }: TStartOrgTrialDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
@ -213,8 +219,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return { url };
};
const createOrganizationPortalSession = async ({ orgId, actorId, actor }: TCreateOrgPortalSession) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const createOrganizationPortalSession = async ({ orgId, actorId, actor, actorOrgId }: TCreateOrgPortalSession) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Billing);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Billing);
@ -260,8 +266,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return { url };
};
const getOrgBillingInfo = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgBillingInfo = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -277,8 +283,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
};
// returns org current plan feature table
const getOrgPlanTable = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgPlanTable = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -293,8 +299,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data;
};
const getOrgBillingDetails = async ({ orgId, actor, actorId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgBillingDetails = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgBillInfoDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -310,8 +316,15 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data;
};
const updateOrgBillingDetails = async ({ actorId, actor, orgId, name, email }: TUpdateOrgBillingDetailsDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const updateOrgBillingDetails = async ({
actorId,
actor,
actorOrgId,
orgId,
name,
email
}: TUpdateOrgBillingDetailsDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -330,8 +343,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data;
};
const getOrgPmtMethods = async ({ orgId, actor, actorId }: TOrgPmtMethodsDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgPmtMethods = async ({ orgId, actor, actorId, actorOrgId }: TOrgPmtMethodsDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -349,8 +362,15 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return pmtMethods;
};
const addOrgPmtMethods = async ({ orgId, actor, actorId, success_url, cancel_url }: TAddOrgPmtMethodDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const addOrgPmtMethods = async ({
orgId,
actor,
actorId,
actorOrgId,
success_url,
cancel_url
}: TAddOrgPmtMethodDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -371,8 +391,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return { url };
};
const delOrgPmtMethods = async ({ actorId, actor, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const delOrgPmtMethods = async ({ actorId, actor, actorOrgId, orgId, pmtMethodId }: TDelOrgPmtMethodDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -388,8 +408,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data;
};
const getOrgTaxIds = async ({ orgId, actor, actorId }: TGetOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgTaxIds = async ({ orgId, actor, actorId, actorOrgId }: TGetOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -406,8 +426,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return taxIds;
};
const addOrgTaxId = async ({ actorId, actor, orgId, type, value }: TAddOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const addOrgTaxId = async ({ actorId, actor, actorOrgId, orgId, type, value }: TAddOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -427,8 +447,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data;
};
const delOrgTaxId = async ({ orgId, actor, actorId, taxId }: TDelOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const delOrgTaxId = async ({ orgId, actor, actorId, actorOrgId, taxId }: TDelOrgTaxIdDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -444,8 +464,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return data;
};
const getOrgTaxInvoices = async ({ actorId, actor, orgId }: TOrgInvoiceDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgTaxInvoices = async ({ actorId, actor, actorOrgId, orgId }: TOrgInvoiceDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
@ -461,8 +481,8 @@ export const licenseServiceFactory = ({ orgDAL, permissionService, licenseDAL }:
return invoices;
};
const getOrgLicenses = async ({ orgId, actor, actorId }: TOrgLicensesDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgLicenses = async ({ orgId, actor, actorId, actorOrgId }: TOrgLicensesDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);

View File

@ -10,8 +10,10 @@ export const permissionDALFactory = (db: TDbClient) => {
try {
const membership = await db(TableName.OrgMembership)
.leftJoin(TableName.OrgRoles, `${TableName.OrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
.join(TableName.Organization, `${TableName.OrgMembership}.orgId`, `${TableName.Organization}.id`)
.where("userId", userId)
.where(`${TableName.OrgMembership}.orgId`, orgId)
.select(db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"))
.select("permissions")
.select(selectAllTableCols(TableName.OrgMembership))
.first();
@ -26,9 +28,11 @@ export const permissionDALFactory = (db: TDbClient) => {
try {
const membership = await db(TableName.IdentityOrgMembership)
.leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
.join(TableName.Organization, `${TableName.IdentityOrgMembership}.orgId`, `${TableName.Organization}.id`)
.where("identityId", identityId)
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
.select(selectAllTableCols(TableName.IdentityOrgMembership))
.select(db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"))
.select("permissions")
.first();
return membership;
@ -41,9 +45,15 @@ export const permissionDALFactory = (db: TDbClient) => {
try {
const membership = await db(TableName.ProjectMembership)
.leftJoin(TableName.ProjectRoles, `${TableName.ProjectMembership}.roleId`, `${TableName.ProjectRoles}.id`)
.join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`)
.join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`)
.where("userId", userId)
.where(`${TableName.ProjectMembership}.projectId`, projectId)
.select(selectAllTableCols(TableName.ProjectMembership))
.select(
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
db.ref("orgId").withSchema(TableName.Project)
)
.select("permissions")
.first();

View File

@ -94,12 +94,15 @@ export const permissionServiceFactory = ({
/*
* Get user permission in an organization
* */
const getUserOrgPermission = async (userId: string, orgId: string) => {
const getUserOrgPermission = async (userId: string, orgId: string, userOrgId?: string) => {
const membership = await permissionDAL.getOrgPermission(userId, orgId);
if (!membership) throw new UnauthorizedError({ name: "User not in org" });
if (membership.role === OrgMembershipRole.Custom && !membership.permissions) {
throw new BadRequestError({ name: "Custom permission not found" });
}
if (membership.orgAuthEnforced && membership.orgId !== userOrgId) {
throw new BadRequestError({ name: "Cannot access org-scoped resource" });
}
return { permission: buildOrgPermission(membership.role, membership.permissions), membership };
};
@ -112,10 +115,10 @@ export const permissionServiceFactory = ({
return { permission: buildOrgPermission(membership.role, membership.permissions), membership };
};
const getOrgPermission = async (type: ActorType, id: string, orgId: string) => {
const getOrgPermission = async (type: ActorType, id: string, orgId: string, actorOrgId?: string) => {
switch (type) {
case ActorType.USER:
return getUserOrgPermission(id, orgId);
return getUserOrgPermission(id, orgId, actorOrgId);
case ActorType.IDENTITY:
return getIdentityOrgPermission(id, orgId);
default:
@ -142,12 +145,17 @@ export const permissionServiceFactory = ({
};
// user permission for a project in an organization
const getUserProjectPermission = async (userId: string, projectId: string) => {
const getUserProjectPermission = async (userId: string, projectId: string, userOrgId?: string) => {
const membership = await permissionDAL.getProjectPermission(userId, projectId);
if (!membership) throw new UnauthorizedError({ name: "User not in project" });
if (membership.role === ProjectMembershipRole.Custom && !membership.permissions) {
throw new BadRequestError({ name: "Custom permission not found" });
}
if (membership.orgAuthEnforced && membership.orgId !== userOrgId) {
throw new BadRequestError({ name: "Cannot access org-scoped resource" });
}
return {
permission: buildProjectPermission(membership.role, membership.permissions),
membership
@ -160,6 +168,7 @@ export const permissionServiceFactory = ({
if (membership.role === ProjectMembershipRole.Custom && !membership.permissions) {
throw new BadRequestError({ name: "Custom permission not found" });
}
return {
permission: buildProjectPermission(membership.role, membership.permissions),
membership
@ -184,6 +193,8 @@ export const permissionServiceFactory = ({
: {
permission: MongoAbility<ProjectPermissionSet, MongoQuery>;
membership: (T extends ActorType.USER ? TProjectMemberships : TIdentityProjectMemberships) & {
orgAuthEnforced: boolean;
orgId: string;
permissions?: unknown;
};
};
@ -191,11 +202,12 @@ export const permissionServiceFactory = ({
const getProjectPermission = async <T extends ActorType>(
type: T,
id: string,
projectId: string
projectId: string,
actorOrgId?: string
): Promise<TProjectPermissionRT<T>> => {
switch (type) {
case ActorType.USER:
return getUserProjectPermission(id, projectId) as Promise<TProjectPermissionRT<T>>;
return getUserProjectPermission(id, projectId, actorOrgId) as Promise<TProjectPermissionRT<T>>;
case ActorType.SERVICE:
return getServiceTokenProjectPermission(id, projectId) as Promise<TProjectPermissionRT<T>>;
case ActorType.IDENTITY:

View File

@ -1,10 +1,31 @@
import { TDbClient } from "@app/db";
import { TableName } from "@app/db/schemas";
import { DatabaseError } from "@app/lib/errors";
import { ormify } from "@app/lib/knex";
export type TSamlConfigDALFactory = ReturnType<typeof samlConfigDALFactory>;
export const samlConfigDALFactory = (db: TDbClient) => {
const samlCfgOrm = ormify(db, TableName.SamlConfig);
return samlCfgOrm;
const findEnforceableSamlCfg = async (orgId: string) => {
try {
const samlCfg = await db(TableName.SamlConfig)
.where({
orgId,
isActive: true
})
.whereNotNull("lastUsed")
.first();
return samlCfg;
} catch (error) {
throw new DatabaseError({ error, name: "Find org by id" });
}
};
return {
...samlCfgOrm,
findEnforceableSamlCfg
};
};

View File

@ -18,7 +18,7 @@ import {
infisicalSymmetricEncypt
} from "@app/lib/crypto/encryption";
import { BadRequestError } from "@app/lib/errors";
import { AuthTokenType } from "@app/services/auth/auth-type";
import { AuthMethod, AuthTokenType } from "@app/services/auth/auth-type";
import { TOrgBotDALFactory } from "@app/services/org/org-bot-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal";
import { TUserDALFactory } from "@app/services/user/user-dal";
@ -27,18 +27,15 @@ import { TLicenseServiceFactory } from "../license/license-service";
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
import { TPermissionServiceFactory } from "../permission/permission-service";
import { TSamlConfigDALFactory } from "./saml-config-dal";
import {
SamlProviders,
TCreateSamlCfgDTO,
TGetSamlCfgDTO,
TSamlLoginDTO,
TUpdateSamlCfgDTO
} from "./saml-config-types";
import { TCreateSamlCfgDTO, TGetSamlCfgDTO, TSamlLoginDTO, TUpdateSamlCfgDTO } from "./saml-config-types";
type TSamlConfigServiceFactoryDep = {
samlConfigDAL: TSamlConfigDALFactory;
userDAL: Pick<TUserDALFactory, "create" | "findUserByEmail" | "transaction" | "updateById">;
orgDAL: Pick<TOrgDALFactory, "createMembership" | "updateMembershipById" | "findMembership" | "findOrgById">;
orgDAL: Pick<
TOrgDALFactory,
"createMembership" | "updateMembershipById" | "findMembership" | "findOrgById" | "findOne" | "updateById"
>;
orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
@ -57,6 +54,7 @@ export const samlConfigServiceFactory = ({
const createSamlCfg = async ({
cert,
actor,
actorOrgId,
orgId,
issuer,
actorId,
@ -64,7 +62,7 @@ export const samlConfigServiceFactory = ({
entryPoint,
authProvider
}: TCreateSamlCfgDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
const plan = await licenseService.getPlan(orgId);
@ -140,12 +138,14 @@ export const samlConfigServiceFactory = ({
certIV,
certTag
});
return samlConfig;
};
const updateSamlCfg = async ({
orgId,
actor,
actorOrgId,
cert,
actorId,
issuer,
@ -153,7 +153,7 @@ export const samlConfigServiceFactory = ({
entryPoint,
authProvider
}: TUpdateSamlCfgDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
const plan = await licenseService.getPlan(orgId);
if (!plan.samlSSO)
@ -162,7 +162,7 @@ export const samlConfigServiceFactory = ({
"Failed to update SAML SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
});
const updateQuery: TSamlConfigsUpdate = { authProvider, isActive };
const updateQuery: TSamlConfigsUpdate = { authProvider, isActive, lastUsed: null };
const orgBot = await orgBotDAL.findOne({ orgId });
if (!orgBot) throw new BadRequestError({ message: "Org bot not found", name: "OrgBotNotFound" });
const key = infisicalSymmetricDecrypt({
@ -195,6 +195,8 @@ export const samlConfigServiceFactory = ({
updateQuery.certTag = certTag;
}
const [ssoConfig] = await samlConfigDAL.update({ orgId }, updateQuery);
await orgDAL.updateById(orgId, { authEnforced: false });
return ssoConfig;
};
@ -203,6 +205,10 @@ export const samlConfigServiceFactory = ({
if (dto.type === "org") {
ssoConfig = await samlConfigDAL.findOne({ orgId: dto.orgId });
if (!ssoConfig) return;
} else if (dto.type === "orgSlug") {
const org = await orgDAL.findOne({ slug: dto.orgSlug });
if (!org) return;
ssoConfig = await samlConfigDAL.findOne({ orgId: org.id });
} else if (dto.type === "ssoId") {
// TODO:
// We made this change because saml config ids were not moved over during the migration
@ -227,7 +233,12 @@ export const samlConfigServiceFactory = ({
// when dto is type id means it's internally used
if (dto.type === "org") {
const { permission } = await permissionService.getOrgPermission(dto.actor, dto.actorId, ssoConfig.orgId);
const { permission } = await permissionService.getOrgPermission(
dto.actor,
dto.actorId,
ssoConfig.orgId,
dto.actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
}
const {
@ -284,7 +295,8 @@ export const samlConfigServiceFactory = ({
isActive: ssoConfig.isActive,
entryPoint,
issuer,
cert
cert,
lastUsed: ssoConfig.lastUsed
};
};
@ -306,13 +318,7 @@ export const samlConfigServiceFactory = ({
if (!organization) throw new BadRequestError({ message: "Org not found" });
if (user) {
const hasSamlEnabled = (user.authMethods || []).some((method) =>
Object.values(SamlProviders).includes(method as SamlProviders)
);
await userDAL.transaction(async (tx) => {
if (!hasSamlEnabled) {
await userDAL.updateById(user.id, { authMethods: [authProvider] }, tx);
}
const [orgMembership] = await orgDAL.findMembership({ userId: user.id, orgId }, { tx });
if (!orgMembership) {
await orgDAL.createMembership(
@ -342,7 +348,7 @@ export const samlConfigServiceFactory = ({
email,
firstName,
lastName,
authMethods: [authProvider]
authMethods: [AuthMethod.EMAIL]
},
tx
);
@ -378,6 +384,9 @@ export const samlConfigServiceFactory = ({
expiresIn: appCfg.JWT_PROVIDER_AUTH_LIFETIME
}
);
await samlConfigDAL.update({ orgId }, { lastUsed: new Date() });
return { isUserCompleted, providerAuthToken };
};

View File

@ -25,7 +25,11 @@ export type TUpdateSamlCfgDTO = Partial<{
TOrgPermission;
export type TGetSamlCfgDTO =
| { type: "org"; orgId: string; actor: ActorType; actorId: string }
| { type: "org"; orgId: string; actor: ActorType; actorId: string; actorOrgId?: string }
| {
type: "orgSlug";
orgSlug: string;
}
| {
type: "ssoId";
id: string;

View File

@ -44,6 +44,7 @@ export const secretApprovalPolicyServiceFactory = ({
name,
actor,
actorId,
actorOrgId,
approvals,
approvers,
projectId,
@ -53,7 +54,7 @@ export const secretApprovalPolicyServiceFactory = ({
if (approvals > approvers.length)
throw new BadRequestError({ message: "Approvals cannot be greater than approvers" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
ProjectPermissionSub.SecretApproval
@ -96,13 +97,19 @@ export const secretApprovalPolicyServiceFactory = ({
name,
actorId,
actor,
actorOrgId,
approvals,
secretPolicyId
}: TUpdateSapDTO) => {
const secretApprovalPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
if (!secretApprovalPolicy) throw new BadRequestError({ message: "Secret approval policy not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, secretApprovalPolicy.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
secretApprovalPolicy.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretApproval);
const updatedSap = await secretApprovalPolicyDAL.transaction(async (tx) => {
@ -145,11 +152,16 @@ export const secretApprovalPolicyServiceFactory = ({
};
};
const deleteSecretApprovalPolicy = async ({ secretPolicyId, actor, actorId }: TDeleteSapDTO) => {
const deleteSecretApprovalPolicy = async ({ secretPolicyId, actor, actorId, actorOrgId }: TDeleteSapDTO) => {
const sapPolicy = await secretApprovalPolicyDAL.findById(secretPolicyId);
if (!sapPolicy) throw new BadRequestError({ message: "Secret approval policy not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, sapPolicy.projectId);
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
sapPolicy.projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
ProjectPermissionSub.SecretApproval
@ -159,8 +171,8 @@ export const secretApprovalPolicyServiceFactory = ({
return sapPolicy;
};
const getSecretApprovalPolicyByProjectId = async ({ actorId, actor, projectId }: TListSapDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getSecretApprovalPolicyByProjectId = async ({ actorId, actor, actorOrgId, projectId }: TListSapDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretApproval);
const sapPolicies = await secretApprovalPolicyDAL.find({ projectId });
@ -188,10 +200,11 @@ export const secretApprovalPolicyServiceFactory = ({
projectId,
actor,
actorId,
actorOrgId,
environment,
secretPath
}: TGetBoardSapDTO) => {
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, { secretPath, environment })

View File

@ -73,10 +73,15 @@ export const secretApprovalRequestServiceFactory = ({
secretVersionDAL,
secretQueueService
}: TSecretApprovalRequestServiceFactoryDep) => {
const requestCount = async ({ projectId, actor, actorId }: TApprovalRequestCountDTO) => {
const requestCount = async ({ projectId, actor, actorId, actorOrgId }: TApprovalRequestCountDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { membership } = await permissionService.getProjectPermission(actor as ActorType.USER, actorId, projectId);
const { membership } = await permissionService.getProjectPermission(
actor as ActorType.USER,
actorId,
projectId,
actorOrgId
);
const count = await secretApprovalRequestDAL.findProjectRequestCount(projectId, membership.id);
return count;
@ -86,6 +91,7 @@ export const secretApprovalRequestServiceFactory = ({
projectId,
actorId,
actor,
actorOrgId,
status,
environment,
committer,
@ -94,7 +100,7 @@ export const secretApprovalRequestServiceFactory = ({
}: TListApprovalsDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
const approvals = await secretApprovalRequestDAL.findByProjectId({
projectId,
committer,
@ -107,7 +113,7 @@ export const secretApprovalRequestServiceFactory = ({
return approvals;
};
const getSecretApprovalDetails = async ({ actor, actorId, id }: TSecretApprovalDetailsDTO) => {
const getSecretApprovalDetails = async ({ actor, actorId, actorOrgId, id }: TSecretApprovalDetailsDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const secretApprovalRequest = await secretApprovalRequestDAL.findById(id);
@ -117,7 +123,8 @@ export const secretApprovalRequestServiceFactory = ({
const { membership } = await permissionService.getProjectPermission(
actor,
actorId,
secretApprovalRequest.projectId
secretApprovalRequest.projectId,
actorOrgId
);
if (
membership.role !== ProjectMembershipRole.Admin &&
@ -134,7 +141,7 @@ export const secretApprovalRequestServiceFactory = ({
return { ...secretApprovalRequest, secretPath: secretPath?.[0]?.path || "/", commits: secrets };
};
const reviewApproval = async ({ approvalId, actor, status, actorId }: TReviewRequestDTO) => {
const reviewApproval = async ({ approvalId, actor, status, actorId, actorOrgId }: TReviewRequestDTO) => {
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
@ -143,7 +150,8 @@ export const secretApprovalRequestServiceFactory = ({
const { membership } = await permissionService.getProjectPermission(
ActorType.USER,
actorId,
secretApprovalRequest.projectId
secretApprovalRequest.projectId,
actorOrgId
);
if (
membership.role !== ProjectMembershipRole.Admin &&
@ -175,7 +183,7 @@ export const secretApprovalRequestServiceFactory = ({
return reviewStatus;
};
const updateApprovalStatus = async ({ actorId, status, approvalId, actor }: TStatusChangeDTO) => {
const updateApprovalStatus = async ({ actorId, status, approvalId, actor, actorOrgId }: TStatusChangeDTO) => {
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
@ -184,7 +192,8 @@ export const secretApprovalRequestServiceFactory = ({
const { membership } = await permissionService.getProjectPermission(
ActorType.USER,
actorId,
secretApprovalRequest.projectId
secretApprovalRequest.projectId,
actorOrgId
);
if (
membership.role !== ProjectMembershipRole.Admin &&
@ -207,13 +216,18 @@ export const secretApprovalRequestServiceFactory = ({
return { ...secretApprovalRequest, ...updatedRequest };
};
const mergeSecretApprovalRequest = async ({ approvalId, actor, actorId }: TMergeSecretApprovalRequestDTO) => {
const mergeSecretApprovalRequest = async ({
approvalId,
actor,
actorId,
actorOrgId
}: TMergeSecretApprovalRequestDTO) => {
const secretApprovalRequest = await secretApprovalRequestDAL.findById(approvalId);
if (!secretApprovalRequest) throw new BadRequestError({ message: "Secret approval request not found" });
if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" });
const { policy, folderId, projectId } = secretApprovalRequest;
const { membership } = await permissionService.getProjectPermission(ActorType.USER, actorId, projectId);
const { membership } = await permissionService.getProjectPermission(ActorType.USER, actorId, projectId, actorOrgId);
if (
membership.role !== ProjectMembershipRole.Admin &&
secretApprovalRequest.committerId !== membership.id &&
@ -401,6 +415,7 @@ export const secretApprovalRequestServiceFactory = ({
data,
actorId,
actor,
actorOrgId,
policy,
projectId,
secretPath,
@ -408,7 +423,12 @@ export const secretApprovalRequestServiceFactory = ({
}: TGenerateSecretApprovalRequestDTO) => {
if (actor === ActorType.SERVICE) throw new BadRequestError({ message: "Cannot use service token" });
const { permission, membership } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission, membership } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })

View File

@ -14,13 +14,7 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/pr
import { TSecretRotationDALFactory } from "./secret-rotation-dal";
import { TSecretRotationQueueFactory } from "./secret-rotation-queue";
import { TSecretRotationEncData } from "./secret-rotation-queue/secret-rotation-queue-types";
import {
TCreateSecretRotationDTO,
TDeleteDTO,
TGetByIdDTO,
TListByProjectIdDTO,
TRestartDTO
} from "./secret-rotation-types";
import { TCreateSecretRotationDTO, TDeleteDTO, TListByProjectIdDTO, TRestartDTO } from "./secret-rotation-types";
import { rotationTemplates } from "./templates";
type TSecretRotationServiceFactoryDep = {
@ -45,8 +39,8 @@ export const secretRotationServiceFactory = ({
folderDAL,
secretDAL
}: TSecretRotationServiceFactoryDep) => {
const getProviderTemplates = async ({ actor, actorId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getProviderTemplates = async ({ actor, actorId, actorOrgId, projectId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
return {
@ -59,6 +53,7 @@ export const secretRotationServiceFactory = ({
projectId,
actorId,
actor,
actorOrgId,
inputs,
outputs,
interval,
@ -66,7 +61,7 @@ export const secretRotationServiceFactory = ({
secretPath,
environment
}: TCreateSecretRotationDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
ProjectPermissionSub.SecretRotation
@ -144,23 +139,14 @@ export const secretRotationServiceFactory = ({
return secretRotation;
};
const getById = async ({ rotationId, actor, actorId }: TGetByIdDTO) => {
const [doc] = await secretRotationDAL.find({ id: rotationId });
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
return doc;
};
const getByProjectId = async ({ actorId, projectId, actor }: TListByProjectIdDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const getByProjectId = async ({ actorId, projectId, actor, actorOrgId }: TListByProjectIdDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRotation);
const doc = await secretRotationDAL.find({ projectId });
return doc;
};
const restartById = async ({ actor, actorId, rotationId }: TRestartDTO) => {
const restartById = async ({ actor, actorId, actorOrgId, rotationId }: TRestartDTO) => {
const doc = await secretRotationDAL.findById(rotationId);
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
@ -171,18 +157,18 @@ export const secretRotationServiceFactory = ({
message: "Failed to add secret rotation due to plan restriction. Upgrade plan to add secret rotation."
});
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.SecretRotation);
await secretRotationQueue.removeFromQueue(doc.id, doc.interval);
await secretRotationQueue.addToQueue(doc.id, doc.interval);
return doc;
};
const deleteById = async ({ actor, actorId, rotationId }: TDeleteDTO) => {
const deleteById = async ({ actor, actorId, actorOrgId, rotationId }: TDeleteDTO) => {
const doc = await secretRotationDAL.findById(rotationId);
if (!doc) throw new BadRequestError({ message: "Rotation not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, doc.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
ProjectPermissionSub.SecretRotation
@ -197,7 +183,6 @@ export const secretRotationServiceFactory = ({
return {
getProviderTemplates,
getById,
getByProjectId,
createRotation,
restartById,

View File

@ -18,7 +18,3 @@ export type TDeleteDTO = {
export type TRestartDTO = {
rotationId: string;
} & Omit<TProjectPermission, "projectId">;
export type TGetByIdDTO = {
rotationId: string;
} & Omit<TProjectPermission, "projectId">;

View File

@ -39,8 +39,8 @@ export const secretScanningServiceFactory = ({
permissionService,
secretScanningQueue
}: TSecretScanningServiceFactoryDep) => {
const createInstallationSession = async ({ actor, orgId, actorId }: TInstallAppSessionDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const createInstallationSession = async ({ actor, orgId, actorId, actorOrgId }: TInstallAppSessionDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
const sessionId = crypto.randomBytes(16).toString("hex");
@ -48,11 +48,17 @@ export const secretScanningServiceFactory = ({
return { sessionId };
};
const linkInstallationToOrg = async ({ sessionId, actorId, installationId, actor }: TLinkInstallSessionDTO) => {
const linkInstallationToOrg = async ({
sessionId,
actorId,
installationId,
actor,
actorOrgId
}: TLinkInstallSessionDTO) => {
const session = await gitAppInstallSessionDAL.findOne({ sessionId });
if (!session) throw new UnauthorizedError({ message: "Session not found" });
const { permission } = await permissionService.getOrgPermission(actor, actorId, session.orgId);
const { permission } = await permissionService.getOrgPermission(actor, actorId, session.orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
const installatedApp = await gitAppOrgDAL.transaction(async (tx) => {
await gitAppInstallSessionDAL.deleteById(session.id, tx);
@ -83,23 +89,23 @@ export const secretScanningServiceFactory = ({
return { installatedApp };
};
const getOrgInstallationStatus = async ({ actorId, orgId, actor }: TGetOrgInstallStatusDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getOrgInstallationStatus = async ({ actorId, orgId, actor, actorOrgId }: TGetOrgInstallStatusDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
const appInstallation = await gitAppOrgDAL.findOne({ orgId });
return Boolean(appInstallation);
};
const getRisksByOrg = async ({ actor, orgId, actorId }: TGetOrgRisksDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const getRisksByOrg = async ({ actor, orgId, actorId, actorOrgId }: TGetOrgRisksDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] });
return { risks };
};
const updateRiskStatus = async ({ actorId, orgId, actor, riskId, status }: TUpdateRiskStatusDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId);
const updateRiskStatus = async ({ actorId, orgId, actor, actorOrgId, riskId, status }: TUpdateRiskStatusDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.SecretScanning);
const isRiskResolved = Boolean(

View File

@ -58,9 +58,10 @@ export const secretSnapshotServiceFactory = ({
projectId,
actorId,
actor,
actorOrgId,
path
}: TProjectSnapshotCountDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
@ -75,11 +76,12 @@ export const secretSnapshotServiceFactory = ({
projectId,
actorId,
actor,
actorOrgId,
path,
limit = 20,
offset = 0
}: TProjectSnapshotListDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
const folder = await folderDAL.findBySecretPath(projectId, environment, path);
@ -89,10 +91,10 @@ export const secretSnapshotServiceFactory = ({
return snapshots;
};
const getSnapshotData = async ({ actorId, actor, id }: TGetSnapshotDataDTO) => {
const getSnapshotData = async ({ actorId, actor, actorOrgId, id }: TGetSnapshotDataDTO) => {
const snapshot = await snapshotDAL.findSecretSnapshotDataById(id);
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.SecretRollback);
return snapshot;
};
@ -143,11 +145,11 @@ export const secretSnapshotServiceFactory = ({
}
};
const rollbackSnapshot = async ({ id: snapshotId, actor, actorId }: TRollbackSnapshotDTO) => {
const rollbackSnapshot = async ({ id: snapshotId, actor, actorId, actorOrgId }: TRollbackSnapshotDTO) => {
const snapshot = await snapshotDAL.findById(snapshotId);
if (!snapshot) throw new BadRequestError({ message: "Snapshot not found" });
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId);
const { permission } = await permissionService.getProjectPermission(actor, actorId, snapshot.projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
ProjectPermissionSub.SecretRollback

View File

@ -26,8 +26,8 @@ export const trustedIpServiceFactory = ({
licenseService,
projectDAL
}: TTrustedIpServiceFactoryDep) => {
const listIpsByProjectId = async ({ projectId, actor, actorId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const listIpsByProjectId = async ({ projectId, actor, actorId, actorOrgId }: TProjectPermission) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.IpAllowList);
const trustedIps = await trustedIpDAL.find({
projectId
@ -35,8 +35,16 @@ export const trustedIpServiceFactory = ({
return trustedIps;
};
const addProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, isActive }: TCreateIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const addProjectIp = async ({
projectId,
actorId,
actor,
actorOrgId,
ipAddress: ip,
comment,
isActive
}: TCreateIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
const project = await projectDAL.findById(projectId);
@ -65,8 +73,16 @@ export const trustedIpServiceFactory = ({
return { trustedIp, project }; // for audit log
};
const updateProjectIp = async ({ projectId, actorId, actor, ipAddress: ip, comment, trustedIpId }: TUpdateIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const updateProjectIp = async ({
projectId,
actorId,
actor,
actorOrgId,
ipAddress: ip,
comment,
trustedIpId
}: TUpdateIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
const project = await projectDAL.findById(projectId);
@ -97,8 +113,8 @@ export const trustedIpServiceFactory = ({
return { trustedIp, project }; // for audit log
};
const deleteProjectIp = async ({ projectId, actorId, actor, trustedIpId }: TDeleteIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId);
const deleteProjectIp = async ({ projectId, actorId, actor, actorOrgId, trustedIpId }: TDeleteIpDTO) => {
const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.IpAllowList);
const project = await projectDAL.findById(projectId);

View File

@ -19,6 +19,7 @@ const envSchema = z
DB_ROOT_CERT: zpStr(z.string().describe("Postgres database base64-encoded CA cert").optional()),
NODE_ENV: z.enum(["development", "test", "production"]).default("production"),
SALT_ROUNDS: z.coerce.number().default(10),
INITIAL_ORGANIZATION_NAME: zpStr(z.string().optional()),
// TODO(akhilmhdh): will be changed to one
ENCRYPTION_KEY: zpStr(z.string().optional()),
ROOT_ENCRYPTION_KEY: zpStr(z.string().optional()),

View File

@ -4,12 +4,14 @@ export type TOrgPermission = {
actor: ActorType;
actorId: string;
orgId: string;
actorOrgId?: string;
};
export type TProjectPermission = {
actor: ActorType;
actorId: string;
projectId: string;
actorOrgId?: string;
};
export type RequiredKeys<T> = {

View File

@ -10,6 +10,7 @@ import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-to
export type TAuthMode =
| {
orgId?: string;
authMode: AuthMode.JWT;
actor: ActorType.USER;
userId: string;
@ -21,6 +22,7 @@ export type TAuthMode =
actor: ActorType.USER;
userId: string;
user: TUsers;
orgId?: string;
}
| {
authMode: AuthMode.SERVICE_TOKEN;
@ -82,8 +84,8 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
switch (authMode) {
case AuthMode.JWT: {
const { user, tokenVersionId } = await server.services.authToken.fnValidateJwtIdentity(token);
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor };
const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token);
req.auth = { authMode: AuthMode.JWT, user, userId: user.id, tokenVersionId, actor, orgId };
break;
}
case AuthMode.IDENTITY_ACCESS_TOKEN: {

View File

@ -9,7 +9,7 @@ export const injectPermission = fp(async (server) => {
if (!req.auth) return;
if (req.auth.actor === ActorType.USER) {
req.permission = { type: ActorType.USER, id: req.auth.userId };
req.permission = { type: ActorType.USER, id: req.auth.userId, orgId: req.auth?.orgId };
} else if (req.auth.actor === ActorType.IDENTITY) {
req.permission = { type: ActorType.IDENTITY, id: req.auth.identityId };
} else if (req.auth.actor === ActorType.SERVICE) {

View File

@ -88,7 +88,8 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
authTokenType: AuthTokenType.ACCESS_TOKEN,
userId: decodedToken.userId,
tokenVersionId: tokenVersion.id,
accessVersion: tokenVersion.accessVersion
accessVersion: tokenVersion.accessVersion,
organizationId: decodedToken.organizationId
},
appCfg.AUTH_SECRET,
{ expiresIn: appCfg.JWT_AUTH_LIFETIME }

View File

@ -29,6 +29,7 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
const bot = await server.services.projectBot.findBotByProjectId({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId
});
return { bot };
@ -68,6 +69,7 @@ export const registerProjectBotRouter = async (server: FastifyZodProvider) => {
const bot = await server.services.projectBot.setBotActiveState({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
botId: req.params.botId,
botKey: req.body.botKey,
isActive: req.body.isActive

View File

@ -26,6 +26,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.createIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body,
orgId: req.body.organizationId
});
@ -68,6 +69,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.updateIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.identityId,
...req.body
});
@ -106,6 +108,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
const identity = await server.services.identity.deleteIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.identityId
});

View File

@ -112,6 +112,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const identityUniversalAuth = await server.services.identityUa.attachUa({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
});
@ -178,6 +179,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const identityUniversalAuth = await server.services.identityUa.updateUa({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
});
@ -220,6 +222,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const identityUniversalAuth = await server.services.identityUa.getIdentityUa({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId
});
@ -262,6 +265,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const { clientSecret, clientSecretData, orgId } = await server.services.identityUa.createUaClientSecret({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
...req.body
});
@ -300,6 +304,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const { clientSecrets: clientSecretData, orgId } = await server.services.identityUa.getUaClientSecrets({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId
});
@ -336,6 +341,7 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
const clientSecretData = await server.services.identityUa.revokeUaClientSecret({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
clientSecretId: req.params.clientSecretId
});

View File

@ -53,6 +53,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.getIntegrationAuth({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
return { integrationAuth };
@ -78,6 +79,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.deleteIntegrationAuths({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
integration: req.query.integration,
projectId: req.query.projectId
});
@ -115,6 +117,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.deleteIntegrationAuthById({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
@ -154,6 +157,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.oauthExchange({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId,
...req.body
});
@ -196,6 +200,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const integrationAuth = await server.services.integrationAuth.saveIntegrationToken({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId,
...req.body
});
@ -242,6 +247,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const apps = await server.services.integrationAuth.getIntegrationApps({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
...req.query
});
@ -272,6 +278,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const teams = await server.services.integrationAuth.getIntegrationAuthTeams({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
return { teams };
@ -299,6 +306,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const branches = await server.services.integrationAuth.getVercelBranches({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
});
@ -327,6 +335,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const groups = await server.services.integrationAuth.getChecklyGroups({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
accountId: req.query.accountId
});
@ -352,6 +361,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const orgs = await server.services.integrationAuth.getQoveryOrgs({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
return { orgs };
@ -379,6 +389,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const projects = await server.services.integrationAuth.getQoveryProjects({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
orgId: req.query.orgId
});
@ -407,6 +418,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const environments = await server.services.integrationAuth.getQoveryEnvs({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
projectId: req.query.projectId
});
@ -435,6 +447,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const apps = await server.services.integrationAuth.getQoveryApps({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
environmentId: req.query.environmentId
});
@ -463,6 +476,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const containers = await server.services.integrationAuth.getQoveryContainers({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
environmentId: req.query.environmentId
});
@ -491,6 +505,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const jobs = await server.services.integrationAuth.getQoveryJobs({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
environmentId: req.query.environmentId
});
@ -519,6 +534,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const environments = await server.services.integrationAuth.getRailwayEnvironments({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
});
@ -547,6 +563,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const services = await server.services.integrationAuth.getRailwayServices({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
});
@ -582,6 +599,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const workspaces = await server.services.integrationAuth.getBitbucketWorkspaces({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId
});
return { workspaces };
@ -614,6 +632,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const secretGroups = await server.services.integrationAuth.getNorthFlankSecretGroups({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
});
@ -647,6 +666,7 @@ export const registerIntegrationAuthRouter = async (server: FastifyZodProvider)
const buildConfigs = await server.services.integrationAuth.getTeamcityBuildConfigs({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationAuthId,
appId: req.query.appId
});

View File

@ -50,6 +50,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
const { integration, integrationAuth } = await server.services.integration.createIntegration({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body
});
await server.services.auditLog.createAuditLog({
@ -107,6 +108,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
const integration = await server.services.integration.updateIntegration({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationId,
...req.body
});
@ -132,6 +134,7 @@ export const registerIntegrationRouter = async (server: FastifyZodProvider) => {
const integration = await server.services.integration.deleteIntegration({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.integrationId
});

View File

@ -26,7 +26,8 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => {
const completeInviteLink = await server.services.org.inviteUserToOrganization({
orgId: req.body.organizationId,
userId: req.permission.id,
inviteeEmail: req.body.inviteeEmail
inviteeEmail: req.body.inviteeEmail,
actorOrgId: req.permission.orgId
});
return {

View File

@ -37,7 +37,11 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const organization = await server.services.org.findOrganizationById(req.permission.id, req.params.organizationId);
const organization = await server.services.org.findOrganizationById(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { organization };
}
});
@ -68,17 +72,29 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId);
const users = await server.services.org.findAllOrgMembers(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { users };
}
});
server.route({
method: "PATCH",
url: "/:organizationId/name",
url: "/:organizationId",
schema: {
params: z.object({ organizationId: z.string().trim() }),
body: z.object({ name: z.string().trim() }),
body: z.object({
name: z.string().trim().optional(),
slug: z
.string()
.trim()
.regex(/^[a-zA-Z0-9-]+$/, "Name must only contain alphanumeric characters or hyphens")
.optional(),
authEnforced: z.boolean().optional()
}),
response: {
200: z.object({
message: z.string(),
@ -88,11 +104,14 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const organization = await server.services.org.updateOrgName(
req.permission.id,
req.params.organizationId,
req.body.name
);
const organization = await server.services.org.updateOrg({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId,
data: req.body
});
return {
message: "Successfully changed organization name",
organization
@ -115,7 +134,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
handler: async (req) => {
const incidentContactsOrg = await req.server.services.org.findIncidentContacts(
req.permission.id,
req.params.organizationId
req.params.organizationId,
req.permission.orgId
);
return { incidentContactsOrg };
}
@ -138,7 +158,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const incidentContactsOrg = await req.server.services.org.createIncidentContact(
req.permission.id,
req.params.organizationId,
req.body.email
req.body.email,
req.permission.orgId
);
return { incidentContactsOrg };
}
@ -160,7 +181,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const incidentContactsOrg = await req.server.services.org.deleteIncidentContact(
req.permission.id,
req.params.organizationId,
req.params.incidentContactId
req.params.incidentContactId,
req.permission.orgId
);
return { incidentContactsOrg };
}

View File

@ -30,6 +30,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const environment = await server.services.projectEnv.createEnvironment({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
...req.body
});
@ -79,6 +80,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const { environment, old } = await server.services.projectEnv.updateEnvironment({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
id: req.params.id,
...req.body
@ -129,6 +131,7 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => {
const environment = await server.services.projectEnv.deleteEnvironment({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
id: req.params.id
});

View File

@ -30,6 +30,7 @@ export const registerProjectKeyRouter = async (server: FastifyZodProvider) => {
projectId: req.params.workspaceId,
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
nonce: req.body.key.nonce,
receiverId: req.body.key.userId,
encryptedKey: req.body.key.encryptedKey

View File

@ -35,6 +35,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const memberships = await server.services.projectMembership.getProjectMemberships({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return { memberships };
@ -70,6 +71,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const data = await server.services.projectMembership.addUsersToProject({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
members: req.body.members
});
@ -112,6 +114,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const membership = await server.services.projectMembership.updateProjectMembership({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
membershipId: req.params.membershipId,
role: req.body.role
@ -153,6 +156,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
const membership = await server.services.projectMembership.deleteProjectMembership({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
membershipId: req.params.membershipId
});

View File

@ -46,6 +46,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const publicKeys = await server.services.projectKey.getProjectPublicKeys({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return { publicKeys };
@ -81,7 +82,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const users = await server.services.projectMembership.getProjectMemberships({
actorId: req.permission.id,
actor: req.permission.type,
projectId: req.params.workspaceId
projectId: req.params.workspaceId,
actorOrgId: req.permission.orgId
});
return { users };
}
@ -122,6 +124,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.getAProject({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return { workspace };
@ -148,6 +151,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actor: req.permission.type,
orgId: req.body.organizationId,
actorOrgId: req.permission.orgId,
workspaceName: req.body.workspaceName
});
return { workspace };
@ -172,6 +176,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.deleteProject({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return { workspace };
@ -200,6 +205,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.updateName({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
name: req.body.name
});
@ -232,6 +238,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const workspace = await server.services.project.toggleAutoCapitalization({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
autoCapitalization: req.body.autoCapitalization
});
@ -264,6 +271,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const { invitee, latestKey } = await server.services.projectMembership.inviteUserToProject({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId,
email: req.body.email
});
@ -309,6 +317,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const integrations = await server.services.integration.listIntegrationByProject({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return { integrations };
@ -333,6 +342,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const authorizations = await server.services.integrationAuth.listIntegrationAuthByProjectId({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return { authorizations };
@ -357,6 +367,7 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const serviceTokenData = await server.services.serviceToken.getProjectServiceTokens({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
projectId: req.params.workspaceId
});
return { serviceTokenData };

View File

@ -31,6 +31,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folder = await server.services.folder.createFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
path
@ -80,6 +81,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const { folder, old } = await server.services.folder.updateFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
id: req.params.folderId,
@ -129,6 +131,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folder = await server.services.folder.deleteFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
id: req.params.folderId,
@ -174,6 +177,7 @@ export const registerSecretFolderRouter = async (server: FastifyZodProvider) =>
const folders = await server.services.folder.getFolders({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId,
path

View File

@ -36,6 +36,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.createImport({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId,
data: req.body.import
@ -97,6 +98,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.updateImport({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.secretImportId,
...req.body,
projectId: req.body.workspaceId,
@ -150,6 +152,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImport = await server.services.secretImport.deleteImport({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.secretImportId,
...req.body,
projectId: req.body.workspaceId
@ -201,6 +204,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const secretImports = await server.services.secretImport.getImports({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId
});
@ -253,6 +257,7 @@ export const registerSecretImportRouter = async (server: FastifyZodProvider) =>
const importedSecrets = await server.services.secretImport.getSecretsFromImports({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId
});

View File

@ -23,6 +23,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTags = await server.services.secretTag.getProjectTags({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId
});
return { workspaceTags };
@ -52,6 +53,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTag = await server.services.secretTag.createTag({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId,
...req.body
});
@ -78,6 +80,7 @@ export const registerSecretTagRouter = async (server: FastifyZodProvider) => {
const workspaceTag = await server.services.secretTag.deleteTag({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.tagId
});
return { workspaceTag };

View File

@ -47,6 +47,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.createWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.body.workspaceId,
...req.body
});
@ -92,6 +93,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.updateWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.webhookId,
isDisabled: req.body.isDisabled
});
@ -128,6 +130,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.deleteWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.webhookId
});
@ -169,6 +172,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhook = await server.services.webhook.testWebhook({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
id: req.params.webhookId
});
return { message: "Successfully tested webhook", webhook };
@ -200,6 +204,7 @@ export const registerWebhookRouter = async (server: FastifyZodProvider) => {
const webhooks = await server.services.webhook.listWebhooks({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
...req.query,
projectId: req.query.workspaceId
});

View File

@ -34,6 +34,7 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
const identityMemberships = await server.services.identity.listOrgIdentities({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.orgId
});
return { identityMemberships };

View File

@ -32,6 +32,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.createProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
projectId: req.params.projectId,
role: req.body.role
@ -62,6 +63,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.updateProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
projectId: req.params.projectId,
role: req.body.role
@ -89,6 +91,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMembership = await server.services.identityProject.deleteProjectIdentity({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
identityId: req.params.identityId,
projectId: req.params.projectId
});
@ -125,6 +128,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
const identityMemberships = await server.services.identityProject.listProjectIdentities({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
projectId: req.params.projectId
});
return { identityMemberships };

View File

@ -26,7 +26,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
const user = await server.store.user.findById(decodedToken.userId);
if (!user) throw new Error("User not found");
req.mfa = { userId: user.id, user };
req.mfa = { userId: user.id, user, orgId: decodedToken.organizationId };
});
server.route({
@ -75,6 +75,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => {
userAgent,
ip: req.realIp,
userId: req.mfa.userId,
orgId: req.mfa.orgId,
mfaToken: req.body.mfaToken
});

View File

@ -33,7 +33,11 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
handler: async (req) => {
if (req.auth.actor !== ActorType.USER) return;
const users = await server.services.org.findAllOrgMembers(req.permission.id, req.params.organizationId);
const users = await server.services.org.findAllOrgMembers(
req.permission.id,
req.params.organizationId,
req.permission.orgId
);
return { users };
}
});
@ -68,6 +72,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const workspaces = await server.services.org.findAllWorkspaces({
actor: req.permission.type,
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
orgId: req.params.organizationId
});
@ -97,7 +102,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
userId: req.permission.id,
role: req.body.role,
orgId: req.params.organizationId,
membershipId: req.params.membershipId
membershipId: req.params.membershipId,
actorOrgId: req.permission.orgId
});
return { membership };
}
@ -121,7 +127,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const membership = await server.services.org.deleteOrgMembership({
userId: req.permission.id,
orgId: req.params.organizationId,
membershipId: req.params.membershipId
membershipId: req.params.membershipId,
actorOrgId: req.permission.orgId
});
return { membership };
}
@ -172,7 +179,8 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
const organization = await server.services.org.deleteOrganizationById(
req.permission.id,
req.params.organizationId
req.params.organizationId,
req.permission.orgId
);
return { organization };
}

View File

@ -28,7 +28,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
const key = await server.services.projectKey.getLatestProjectKey({
actor: req.permission.type,
actorId: req.permission.id,
projectId: req.params.workspaceId
projectId: req.params.workspaceId,
actorOrgId: req.permission.orgId
});
await server.services.auditLog.createAuditLog({

View File

@ -92,6 +92,7 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
const { serviceToken, token } = await server.services.serviceToken.createServiceToken({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
...req.body,
projectId: req.body.workspaceId
});
@ -129,6 +130,7 @@ export const registerServiceTokenRouter = async (server: FastifyZodProvider) =>
const serviceTokenData = await server.services.serviceToken.deleteServiceToken({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
id: req.params.serviceTokenId
});

View File

@ -21,7 +21,8 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
const count = await server.services.secretBlindIndex.getSecretBlindIndexStatus({
projectId: req.params.projectId,
actorId: req.permission.id,
actor: req.permission.type
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
return count === 0;
}
@ -52,7 +53,8 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
const secrets = await server.services.secretBlindIndex.getProjectSecrets({
projectId: req.params.projectId,
actorId: req.permission.id,
actor: req.permission.type
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
return { secrets };
}
@ -85,7 +87,8 @@ export const registerSecretBlindIndexRouter = async (server: FastifyZodProvider)
projectId: req.params.projectId,
secretsToUpdate: req.body.secretsToUpdate,
actorId: req.permission.id,
actor: req.permission.type
actor: req.permission.type,
actorOrgId: req.permission.orgId
});
return { message: "Successfully named workspace secrets" };
}

View File

@ -81,6 +81,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const { secrets, imports } = await server.services.secret.getSecretsRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment,
projectId: workspaceId,
path: secretPath,
@ -158,6 +159,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.getSecretByNameRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment,
projectId: workspaceId,
path: secretPath,
@ -225,6 +227,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.createSecretRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.body.environment,
projectId: req.body.workspaceId,
secretPath: req.body.secretPath,
@ -293,6 +296,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.updateSecretRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.body.environment,
projectId: req.body.workspaceId,
secretPath: req.body.secretPath,
@ -357,6 +361,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.deleteSecretRaw({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.body.environment,
projectId: req.body.workspaceId,
secretPath: req.body.secretPath,
@ -451,6 +456,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const { secrets, imports } = await server.services.secret.getSecrets({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.query.environment,
projectId: req.query.workspaceId,
path: req.query.secretPath,
@ -536,6 +542,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.getSecretByName({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
environment: req.query.environment,
projectId: req.query.workspaceId,
path: req.query.secretPath,
@ -646,6 +653,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId,
@ -688,6 +696,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.createSecret({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath,
type,
environment: req.body.environment,
@ -811,6 +820,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId
@ -819,6 +829,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId,
@ -863,6 +874,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.updateSecret({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath,
type,
environment,
@ -952,6 +964,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId
@ -960,6 +973,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId,
@ -992,6 +1006,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secret = await server.services.secret.deleteSecret({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath,
type,
environment,
@ -1074,6 +1089,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId
@ -1082,6 +1098,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId,
@ -1110,6 +1127,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.createManySecret({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath,
environment,
projectId,
@ -1192,6 +1210,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId
@ -1200,6 +1219,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId,
@ -1227,6 +1247,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.updateManySecret({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: secretPath,
environment,
projectId,
@ -1298,6 +1319,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const policy = await server.services.secretApprovalPolicy.getSecretApprovalPolicyOfFolder({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId
@ -1306,6 +1328,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const approval = await server.services.secretApprovalRequest.generateSecretApprovalRequest({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
secretPath,
environment,
projectId,
@ -1332,6 +1355,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => {
const secrets = await server.services.secret.deleteManySecret({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
path: req.body.secretPath,
environment,
projectId,

View File

@ -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 {

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) => {

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 };
};
/*

View File

@ -19,6 +19,7 @@ export type TVerifyMfaTokenDTO = {
mfaToken: string;
ip: string;
userAgent: string;
orgId?: string;
};
export type TOauthLoginDTO = {

View File

@ -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 }

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 = {

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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) => {

View File

@ -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);

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,

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 };
};

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,

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;

View File

@ -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) {

View File

@ -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) => {

View File

@ -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);
};

View File

@ -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) => {

View File

@ -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 };
};

View File

@ -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 });

View File

@ -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;
};

View File

@ -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" });
}

View File

@ -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" });

View File

@ -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 })

View File

@ -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"]] });

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 })
@ -537,18 +569,30 @@ export const secretServiceFactory = ({
const secretBlindIndex = await interalGenSecBlindIndexByName(projectId, secretName);
const secret = await (typeof version !== undefined
// Case: The old python SDK uses incorrect logic https://github.com/Infisical/infisical-python/blob/main/infisical/client/infisicalclient.py#L89.
// Fetch secrets using service tokens cannot fetch personal secrets, only shared.
// The mongo backend used to correct this mistake, this line also adds it to current backend
// Mongo backend check: https://github.com/Infisical/infisical-mongo/blob/main/backend/src/helpers/secrets.ts#L658
let secretType = type;
if (actor === ActorType.SERVICE) {
logger.info(
`secretServiceFactory: overriding secret type for service token [projectId=${projectId}] [factoryFunctionName=getSecretByName]`
);
secretType = SecretType.Shared;
}
const secret = await (typeof version === undefined
? secretDAL.findOne({
folderId,
type,
userId: type === SecretType.Personal ? actorId : null,
type: secretType,
userId: secretType === SecretType.Personal ? actorId : null,
secretBlindIndex
})
: secretVersionDAL
.findOne({
folderId,
type,
userId: type === SecretType.Personal ? actorId : null,
type: secretType,
userId: secretType === SecretType.Personal ? actorId : null,
secretBlindIndex
})
.then((el) => SecretsSchema.parse({ ...el, id: el.secretId })));
@ -595,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 })
@ -649,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 })
@ -721,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 })
@ -762,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" });
@ -784,6 +826,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
path,
includeImports
});
@ -806,6 +849,7 @@ export const secretServiceFactory = ({
environment,
projectId,
actorId,
actorOrgId,
secretName,
includeImports,
version
@ -818,6 +862,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
path,
secretName,
type,
@ -833,6 +878,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
type,
secretPath,
secretValue,
@ -854,6 +900,7 @@ export const secretServiceFactory = ({
path: secretPath,
actor,
actorId,
actorOrgId,
secretKeyCiphertext: secretKeyEncrypted.ciphertext,
secretKeyIV: secretKeyEncrypted.iv,
secretKeyTag: secretKeyEncrypted.tag,
@ -878,6 +925,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
type,
secretPath,
secretValue,
@ -896,6 +944,7 @@ export const secretServiceFactory = ({
path: secretPath,
actor,
actorId,
actorOrgId,
secretValueCiphertext: secretValueEncrypted.ciphertext,
secretValueIV: secretValueEncrypted.iv,
secretValueTag: secretValueEncrypted.tag,
@ -914,6 +963,7 @@ export const secretServiceFactory = ({
projectId,
environment,
actor,
actorOrgId,
type,
secretPath
}: TDeleteSecretRawDTO) => {
@ -927,7 +977,8 @@ export const secretServiceFactory = ({
type,
path: secretPath,
actor,
actorId
actorId,
actorOrgId
});
await snapshotService.performSnapshot(secret.folderId);
@ -936,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"]] });
@ -964,7 +1022,6 @@ export const secretServiceFactory = ({
createSecretRaw,
updateSecretRaw,
deleteSecretRaw,
listSecretVersionsBySecretId,
getSecretVersions,
// external services function
fnSecretBulkDelete,

View File

@ -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;

View File

@ -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"]] });

View File

@ -1,4 +1,5 @@
import { TSuperAdmin, TSuperAdminUpdate } from "@app/db/schemas";
import { getConfig } from "@app/lib/config/env";
import { BadRequestError } from "@app/lib/errors";
import { TAuthLoginFactory } from "../auth/auth-login-service";
@ -58,6 +59,7 @@ export const superAdminServiceFactory = ({
ip,
userAgent
}: TAdminSignUpDTO) => {
const appCfg = getConfig();
const existingUser = await userDAL.findOne({ email });
if (existingUser) throw new BadRequestError({ name: "Admin sign up", message: "User already exist" });
@ -91,10 +93,18 @@ export const superAdminServiceFactory = ({
);
return { user: newUser, enc: userEnc };
});
await orgService.createOrganization(userInfo.user.id, userInfo.user.email, "Admin Org");
const initialOrganizationName = appCfg.INITIAL_ORGANIZATION_NAME ?? "Admin Org";
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 };
};

View File

@ -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;
};

View File

@ -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);

View File

@ -74,9 +74,16 @@ description: "Configure Okta SAML 2.0 for Infisical SSO"
At this point, you have configured everything you need within the context of the Okta Admin Portal.
</Step>
<Step title="Enable SAML SSO in Infisical">
Enabling SAML SSO enforces all members in your organization to only be able to log into Infisical via Okta.
Enabling SAML SSO allows members in your organization to log into Infisical via Okta.
![SAML Okta assignment](../../../images/sso/okta/enable-saml.png)
![SAML Okta enable SAML](../../../images/sso/okta/enable-saml.png)
</Step>
<Step title="Enforce SAML SSO in Infisical">
Enforcing SAML SSO requires members in your organization can only access Infisical
by logging into the organization via Okta.
To enforce SAML SSO, you're required to test out the SAML connection by successfully authenticating at least one Okta user with Infisical;
Once you've completed this requirement, you can toggle the **Enforce SAML SSO** button to enforce SAML SSO.
</Step>
</Steps>

View File

@ -1,9 +1,7 @@
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { useRouter } from "next/router";
import { faGithub, faGitlab, faGoogle } from "@fortawesome/free-brands-svg-icons";
import { faEnvelope } from "@fortawesome/free-regular-svg-icons";
import { faLock } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Button } from "../v2";
@ -14,7 +12,6 @@ export default function InitialSignupStep({
setIsSignupWithEmail: (value: boolean) => void;
}) {
const { t } = useTranslation();
const router = useRouter();
return (
<div className="mx-auto flex w-full flex-col items-center justify-center">
@ -76,17 +73,6 @@ export default function InitialSignupStep({
Continue with Email
</Button>
</div>
<div className="mt-4 w-1/4 min-w-[20rem] rounded-md text-center lg:w-1/6">
<Button
colorSchema="primary"
variant="outline_bg"
onClick={() => router.push("/saml-sso")}
leftIcon={<FontAwesomeIcon icon={faLock} className="mr-2" />}
className="mx-0 h-12 w-full"
>
Continue with SSO
</Button>
</div>
<div className="mt-6 w-1/4 min-w-[20rem] px-8 text-center text-xs text-bunker-400 lg:w-1/6">
{t("signup.create-policy")}
</div>

View File

@ -25,7 +25,7 @@ export const OrgProvider = ({ children }: Props): JSX.Element => {
const value = useMemo<TOrgContext>(
() => ({
orgs: userOrgs,
currentOrg: (userOrgs || []).find(({ id }) => id === currentWsOrgID) || (userOrgs || [])[0],
currentOrg: (userOrgs || []).find(({ id }) => id === currentWsOrgID),
isLoading
}),
[currentWsOrgID, userOrgs, isLoading]

View File

@ -17,6 +17,6 @@ export {
useGetOrgPmtMethods,
useGetOrgTaxIds,
useGetOrgTrialUrl,
useRenameOrg,
useUpdateOrg,
useUpdateOrgBillingDetails
} from "./queries";

View File

@ -12,8 +12,8 @@ import {
PlanBillingInfo,
PmtMethod,
ProductsTable,
RenameOrgDTO,
TaxID
TaxID,
UpdateOrgDTO
} from "./types";
export const organizationKeys = {
@ -65,12 +65,20 @@ export const useCreateOrg = () => {
});
};
export const useRenameOrg = () => {
export const useUpdateOrg = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, RenameOrgDTO>({
mutationFn: ({ newOrgName, orgId }) => {
return apiRequest.patch(`/api/v1/organization/${orgId}/name`, { name: newOrgName });
return useMutation<{}, {}, UpdateOrgDTO>({
mutationFn: ({
name,
authEnforced,
slug,
orgId
}) => {
return apiRequest.patch(`/api/v1/organization/${orgId}`, {
name,
authEnforced,
slug
});
},
onSuccess: () => {
queryClient.invalidateQueries(organizationKeys.getUserOrganizations);

View File

@ -3,11 +3,15 @@ export type Organization = {
name: string;
createAt: string;
updatedAt: string;
authEnforced: boolean;
slug: string;
};
export type RenameOrgDTO = {
export type UpdateOrgDTO = {
orgId: string;
newOrgName: string;
name?: string;
authEnforced?: boolean;
slug?: string;
};
export type BillingDetails = {

View File

@ -272,7 +272,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
createNotification({ text: "Failed to create workspace", type: "error" });
}
};
return (
<>
<div className="dark hidden h-screen w-full flex-col overflow-x-hidden md:flex">
@ -310,10 +310,25 @@ export const AppLayout = ({ children }: LayoutProps) => {
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="p-1">
<div className="px-2 py-1 text-xs text-mineshaft-400">{user?.email}</div>
{orgs?.map((org) => (
{orgs?.map((org) => {
return (
<DropdownMenuItem key={org.id}>
<Button
onClick={() => changeOrg(org?.id)}
onClick={async () => {
if (currentOrg?.id === org.id) return;
if (org.authEnforced) {
// org has an org-level auth method enabled (e.g. SAML)
// -> logout + redirect to SAML SSO
await logout.mutateAsync();
window.open(`/api/v1/sso/redirect/saml2/organizations/${org.slug}`);
window.close();
return;
}
changeOrg(org?.id)
}}
variant="plain"
colorSchema="secondary"
size="xs"
@ -329,7 +344,8 @@ export const AppLayout = ({ children }: LayoutProps) => {
</div>
</Button>
</DropdownMenuItem>
))}
)
})}
{/* <DropdownMenuItem key="add-org">
<Button
onClick={() => handlePopUpOpen("createOrg")}
@ -604,16 +620,18 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem>
</a>
</Link>
<Link href={`/org/${currentOrg?.id}/billing`} passHref>
<a>
<MenuItem
isSelected={router.asPath === `/org/${currentOrg?.id}/billing`}
icon="system-outline-103-coin-cash-monetization"
>
Usage & Billing
</MenuItem>
</a>
</Link>
{(window.location.origin.includes("https://app.infisical.com")) && (
<Link href={`/org/${currentOrg?.id}/billing`} passHref>
<a>
<MenuItem
isSelected={router.asPath === `/org/${currentOrg?.id}/billing`}
icon="system-outline-103-coin-cash-monetization"
>
Usage & Billing
</MenuItem>
</a>
</Link>
)}
<Link href={`/org/${currentOrg?.id}/settings`} passHref>
<a>
<MenuItem

View File

@ -10,7 +10,6 @@ import {
MFAStep,
SAMLSSOStep
} from "./components";
// import { navigateUserToOrg } from "../../Login.utils";
import { navigateUserToOrg } from "./Login.utils";
export const Login = () => {

Some files were not shown because too many files have changed in this diff Show More