Skip to content
This repository has been archived by the owner on Jan 23, 2024. It is now read-only.

Commit

Permalink
feat: invites bypass disabled signup (calcom#12626)
Browse files Browse the repository at this point in the history
* invites bypass disabled signup

* nit:remove new line

* add tests

* chore: spelling

---------

Co-authored-by: Udit Takkar <[email protected]>
  • Loading branch information
sean-brydon and Udit-takkar authored Dec 4, 2023
1 parent 80b92b5 commit d185d7f
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 5 deletions.
14 changes: 12 additions & 2 deletions apps/web/pages/api/auth/signup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,18 @@ import { type RequestWithUsernameStatus } from "@calcom/features/auth/signup/use
import { IS_PREMIUM_USERNAME_ENABLED } from "@calcom/lib/constants";
import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { signupSchema } from "@calcom/prisma/zod-utils";

function ensureSignupIsEnabled(req: RequestWithUsernameStatus) {
const { token } = signupSchema
.pick({
token: true,
})
.parse(req.body);

// Stil allow signups if there is a team invite
if (token) return;

function ensureSignupIsEnabled() {
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true") {
throw new HttpError({
statusCode: 403,
Expand All @@ -29,7 +39,7 @@ export default async function handler(req: RequestWithUsernameStatus, res: NextA
// Use a try catch instead of returning res every time
try {
ensureReqIsPost(req);
ensureSignupIsEnabled();
ensureSignupIsEnabled(req);

/**
* Im not sure its worth merging these two handlers. They are different enough to be separate.
Expand Down
2 changes: 1 addition & 1 deletion apps/web/pages/signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
// username + email prepopulated from query params
const { username: preFillusername, email: prefilEmail } = querySchema.parse(ctx.query);

if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" || flags["disable-signup"]) {
if ((process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" && !token) || flags["disable-signup"]) {
return {
notFound: true,
};
Expand Down
57 changes: 55 additions & 2 deletions apps/web/playwright/signup.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@ import { randomBytes } from "crypto";
import { APP_NAME, IS_PREMIUM_USERNAME_ENABLED, IS_MAILHOG_ENABLED } from "@calcom/lib/constants";

import { test } from "./lib/fixtures";
import { getEmailsReceivedByUser } from "./lib/testUtils";
import { getEmailsReceivedByUser, localize } from "./lib/testUtils";
import { expectInvitationEmailToBeReceived } from "./team/expects";

test.describe.configure({ mode: "parallel" });

test.describe("Signup Flow Test", async () => {
test.beforeEach(async ({ features }) => {
features.reset(); // This resets to the inital state not an empt yarray
});
test.afterAll(async ({ users }) => {
test.afterAll(async ({ users, emails }) => {
await users.deleteAll();
emails?.deleteAll();
});
test("Username is taken", async ({ page, users }) => {
// log in trail user
Expand Down Expand Up @@ -228,4 +230,55 @@ test.describe("Signup Flow Test", async () => {
const verifyEmail = receivedEmails?.items[0];
expect(verifyEmail?.subject).toBe(`${APP_NAME}: Verify your account`);
});
test("If signup is disabled allow team invites", async ({ browser, page, users, emails }) => {
// eslint-disable-next-line playwright/no-skipped-test
test.skip(process.env.NEXT_PUBLIC_DISABLE_SIGNUP !== "true", "Skipping due to signup being enabled");

const t = await localize("en");
const teamOwner = await users.create(undefined, { hasTeam: true });
const { team } = await teamOwner.getFirstTeam();
await teamOwner.apiLogin();
await page.goto(`/settings/teams/${team.id}/members`);
await page.waitForLoadState("networkidle");

await test.step("Invite User to team", async () => {
// TODO: This invite logic should live in a fixture - its used in team and orgs invites (Duplicated from team/org invites)
const invitedUserEmail = `rick_${Date.now()}@domain-${Date.now()}.com`;
await page.locator(`button:text("${t("add")}")`).click();
await page.locator('input[name="inviteUser"]').fill(invitedUserEmail);
await page.locator(`button:text("${t("send_invite")}")`).click();
await page.waitForLoadState("networkidle");
const inviteLink = await expectInvitationEmailToBeReceived(
page,
emails,
invitedUserEmail,
`${team.name}'s admin invited you to join the team ${team.name} on Cal.com`,
"signup?token"
);

//Check newly invited member exists and is pending
await expect(
page.locator(`[data-testid="email-${invitedUserEmail.replace("@", "")}-pending"]`)
).toHaveCount(1);

// eslint-disable-next-line playwright/no-conditional-in-test
if (!inviteLink) return;

// Follow invite link to new window
const context = await browser.newContext();
const newPage = await context.newPage();
await newPage.goto(inviteLink);
await newPage.waitForLoadState("networkidle");

const url = new URL(newPage.url());
expect(url.pathname).toBe("/signup");

// Check required fields
await newPage.locator("input[name=password]").fill(`P4ssw0rd!`);
await newPage.locator("button[type=submit]").click();
await newPage.waitForURL("/getting-started?from=signup");
await newPage.close();
await context.close();
});
});
});

0 comments on commit d185d7f

Please sign in to comment.