112 lines
3.1 KiB
TypeScript
112 lines
3.1 KiB
TypeScript
import createUsersAndConnectToOrg from "@calcom/features/ee/dsync/lib/users/createUsersAndConnectToOrg";
|
|
import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
|
|
import type { PrismaClient } from "@calcom/prisma";
|
|
import { IdentityProvider } from "@calcom/prisma/enums";
|
|
import { TRPCError } from "@calcom/trpc/server";
|
|
|
|
import jackson from "./jackson";
|
|
import { tenantPrefix, samlProductID } from "./saml";
|
|
|
|
const getAllAcceptedMemberships = async ({ prisma, email }: { prisma: PrismaClient; email: string }) => {
|
|
return await prisma.membership.findMany({
|
|
select: {
|
|
teamId: true,
|
|
},
|
|
where: {
|
|
accepted: true,
|
|
user: {
|
|
email,
|
|
},
|
|
},
|
|
});
|
|
};
|
|
|
|
const getVerifiedOrganizationByAutoAcceptEmailDomain = async ({
|
|
prisma,
|
|
domain,
|
|
}: {
|
|
prisma: PrismaClient;
|
|
domain: string;
|
|
}) => {
|
|
return await prisma.team.findFirst({
|
|
where: {
|
|
organizationSettings: {
|
|
isOrganizationVerified: true,
|
|
orgAutoAcceptEmail: domain,
|
|
},
|
|
},
|
|
select: {
|
|
id: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
export const ssoTenantProduct = async (prisma: PrismaClient, email: string) => {
|
|
const { connectionController } = await jackson();
|
|
|
|
let memberships = await getAllAcceptedMemberships({ prisma, email });
|
|
|
|
if (!memberships || memberships.length === 0) {
|
|
if (!HOSTED_CAL_FEATURES)
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "no_account_exists",
|
|
});
|
|
|
|
const domain = email.split("@")[1];
|
|
const organization = await getVerifiedOrganizationByAutoAcceptEmailDomain({ prisma, domain });
|
|
|
|
if (!organization)
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "no_account_exists",
|
|
});
|
|
|
|
const organizationId = organization.id;
|
|
const createUsersAndConnectToOrgProps = {
|
|
emailsToCreate: [email],
|
|
organizationId,
|
|
identityProvider: IdentityProvider.SAML,
|
|
identityProviderId: email,
|
|
};
|
|
|
|
await createUsersAndConnectToOrg(createUsersAndConnectToOrgProps);
|
|
memberships = await getAllAcceptedMemberships({ prisma, email });
|
|
|
|
if (!memberships || memberships.length === 0)
|
|
throw new TRPCError({
|
|
code: "UNAUTHORIZED",
|
|
message: "no_account_exists",
|
|
});
|
|
}
|
|
|
|
// Check SSO connections for each team user is a member of
|
|
// We'll use the first one we find
|
|
const promises = memberships.map(({ teamId }) =>
|
|
connectionController.getConnections({
|
|
tenant: `${tenantPrefix}${teamId}`,
|
|
product: samlProductID,
|
|
})
|
|
);
|
|
|
|
const connectionResults = await Promise.allSettled(promises);
|
|
|
|
const connectionsFound = connectionResults
|
|
.filter((result) => result.status === "fulfilled")
|
|
.map((result) => (result.status === "fulfilled" ? result.value : []))
|
|
.filter((connections) => connections.length > 0);
|
|
|
|
if (connectionsFound.length === 0) {
|
|
throw new TRPCError({
|
|
code: "BAD_REQUEST",
|
|
message:
|
|
"Could not find a SSO Identity Provider for your email. Please contact your admin to ensure you have been given access to Cal",
|
|
});
|
|
}
|
|
|
|
return {
|
|
tenant: connectionsFound[0][0].tenant,
|
|
product: samlProductID,
|
|
};
|
|
};
|