test: Hotfix/Orgs rewrite causing 404 with 3 or more dots domains (#9803)
* Fix RegExp * Used ORGANIZATIONS_ENABLED to opt-out of orgs behaviour * Add comments * Add a new testcase * Add response headers for easier debugging and Checkly tests in productionpull/9728/head^2
parent
66d47974cb
commit
8384c3f9ff
|
@ -0,0 +1,15 @@
|
|||
const getDefaultSubdomain = (url) => {
|
||||
if (!url.startsWith("http:") && !url.startsWith("https:")) {
|
||||
// Make it a valid URL. Mabe we can simply return null and opt-out from orgs support till the use a URL scheme.
|
||||
url = `https://${url}`;
|
||||
}
|
||||
const _url = new URL(url);
|
||||
const regex = new RegExp(/^([a-z]+\:\/{2})?((?<subdomain>[\w-.]+)\.[\w-]+\.\w+)$/);
|
||||
//console.log(_url.hostname, _url.hostname.match(regex));
|
||||
return _url.hostname.match(regex)?.groups?.subdomain || null;
|
||||
};
|
||||
exports.getSubdomainRegExp = (url) => {
|
||||
const defaultSubdomain = getDefaultSubdomain(url);
|
||||
const subdomain = defaultSubdomain ? `(?!${defaultSubdomain})[^.]+` : "[^.]+";
|
||||
return subdomain;
|
||||
};
|
|
@ -5,6 +5,7 @@ const englishTranslation = require("./public/static/locales/en/common.json");
|
|||
const { withAxiom } = require("next-axiom");
|
||||
const { i18n } = require("./next-i18next.config");
|
||||
const { pages } = require("./pages");
|
||||
const { getSubdomainRegExp } = require("./getSubdomainRegExp");
|
||||
|
||||
if (!process.env.NEXTAUTH_SECRET) throw new Error("Please set NEXTAUTH_SECRET");
|
||||
if (!process.env.CALENDSO_ENCRYPTION_KEY) throw new Error("Please set CALENDSO_ENCRYPTION_KEY");
|
||||
|
@ -70,14 +71,6 @@ const informAboutDuplicateTranslations = () => {
|
|||
};
|
||||
|
||||
informAboutDuplicateTranslations();
|
||||
|
||||
const getSubdomain = () => {
|
||||
const _url = new URL(process.env.NEXT_PUBLIC_WEBAPP_URL);
|
||||
const regex = new RegExp(/^([a-z]+\:\/{2})?((?<subdomain>[\w-]+)\.[\w-]+\.\w+)$/);
|
||||
//console.log(_url.hostname, _url.hostname.match(regex));
|
||||
return _url.hostname.match(regex)?.groups?.subdomain || null;
|
||||
};
|
||||
|
||||
const plugins = [];
|
||||
if (process.env.ANALYZE === "true") {
|
||||
// only load dependency if env `ANALYZE` was set
|
||||
|
@ -102,6 +95,39 @@ const teamTypeRouteRegExp = "/team/:slug/:type((?!book$)[^/]+)";
|
|||
const privateLinkRouteRegExp = "/d/:link/:slug((?!book$)[^/]+)";
|
||||
const embedUserTypeRouteRegExp = `/:user((?!${pages.join("/|")})[^/]*)/:type/embed`;
|
||||
const embedTeamTypeRouteRegExp = "/team/:slug/:type/embed";
|
||||
const subdomainRegExp = getSubdomainRegExp(process.env.NEXT_PUBLIC_WEBAPP_URL);
|
||||
// Important Note: Do update the RegExp in apps/web/test/lib/next-config.test.ts when changing it.
|
||||
const orgHostRegExp = `^(?<orgSlug>${subdomainRegExp})\\..*`;
|
||||
|
||||
const matcherConfigRootPath = {
|
||||
has: [
|
||||
{
|
||||
type: "host",
|
||||
value: orgHostRegExp,
|
||||
},
|
||||
],
|
||||
source: "/",
|
||||
};
|
||||
|
||||
const matcherConfigOrgMemberPath = {
|
||||
has: [
|
||||
{
|
||||
type: "host",
|
||||
value: orgHostRegExp,
|
||||
},
|
||||
],
|
||||
source: `/:user((?!${pages.join("|")}|_next|public)[a-zA-Z0-9\-_]+)`,
|
||||
};
|
||||
|
||||
const matcherConfigUserPath = {
|
||||
has: [
|
||||
{
|
||||
type: "host",
|
||||
value: `^(?<orgSlug>${subdomainRegExp}[^.]+)\\..*`,
|
||||
},
|
||||
],
|
||||
source: `/:user((?!${pages.join("|")}|_next|public))/:path*`,
|
||||
};
|
||||
|
||||
/** @type {import("next").NextConfig} */
|
||||
const nextConfig = {
|
||||
|
@ -193,40 +219,23 @@ const nextConfig = {
|
|||
return config;
|
||||
},
|
||||
async rewrites() {
|
||||
const defaultSubdomain = getSubdomain();
|
||||
const subdomain = defaultSubdomain ? `(?!${defaultSubdomain})[^.]+` : "[^.]+";
|
||||
|
||||
const beforeFiles = [
|
||||
{
|
||||
has: [
|
||||
{
|
||||
type: "host",
|
||||
value: `^(?<orgSlug>${subdomain})\\..*`,
|
||||
},
|
||||
],
|
||||
source: "/",
|
||||
destination: "/team/:orgSlug",
|
||||
},
|
||||
{
|
||||
has: [
|
||||
{
|
||||
type: "host",
|
||||
value: `^(?<orgSlug>${subdomain})\\..*`,
|
||||
},
|
||||
],
|
||||
source: `/:user((?!${pages.join("|")}|_next|public)[a-zA-Z0-9\-_]+)`,
|
||||
destination: "/org/:orgSlug/:user",
|
||||
},
|
||||
{
|
||||
has: [
|
||||
{
|
||||
type: "host",
|
||||
value: `^(?<orgSlug>${subdomain}[^.]+)\\..*`,
|
||||
},
|
||||
],
|
||||
source: `/:user((?!${pages.join("|")}|_next|public))/:path*`,
|
||||
destination: "/:user/:path*",
|
||||
},
|
||||
...(process.env.ORGANIZATIONS_ENABLED
|
||||
? [
|
||||
{
|
||||
...matcherConfigRootPath,
|
||||
destination: "/team/:orgSlug",
|
||||
},
|
||||
{
|
||||
...matcherConfigOrgMemberPath,
|
||||
destination: "/org/:orgSlug/:user",
|
||||
},
|
||||
{
|
||||
...matcherConfigUserPath,
|
||||
destination: "/:user/:path*",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
let afterFiles = [
|
||||
|
@ -381,6 +390,35 @@ const nextConfig = {
|
|||
},
|
||||
],
|
||||
},
|
||||
...[
|
||||
{
|
||||
...matcherConfigRootPath,
|
||||
headers: [
|
||||
{
|
||||
key: "X-Cal-Org-path",
|
||||
value: "/team/:orgSlug",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
...matcherConfigOrgMemberPath,
|
||||
headers: [
|
||||
{
|
||||
key: "X-Cal-Org-path",
|
||||
value: "/org/:orgSlug/:user",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
...matcherConfigUserPath,
|
||||
headers: [
|
||||
{
|
||||
key: "X-Cal-Org-path",
|
||||
value: "/:user/:path",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
];
|
||||
},
|
||||
async redirects() {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
|
||||
import { it, expect, describe, beforeAll, afterAll } from "vitest";
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { getSubdomainRegExp } = require("../../getSubdomainRegExp");
|
||||
let userTypeRouteRegExp: RegExp;
|
||||
let teamTypeRouteRegExp:RegExp;
|
||||
let privateLinkRouteRegExp:RegExp
|
||||
|
@ -161,3 +163,36 @@ describe('next.config.js - RegExp', ()=>{
|
|||
})
|
||||
})
|
||||
|
||||
|
||||
describe('next.config.js - Org Rewrite', ()=> {
|
||||
// RegExp copied from next.config.js
|
||||
const orgHostRegExp = (subdomainRegExp:string)=> new RegExp(`^(?<orgSlug>${subdomainRegExp})\\..*`)
|
||||
describe('SubDomain Retrieval from NEXT_PUBLIC_WEBAPP_URL', ()=>{
|
||||
it('https://app.cal.com', ()=>{
|
||||
const subdomainRegExp = getSubdomainRegExp('https://app.cal.com');
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('app.cal.com')).toEqual(null)
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('company.app.cal.com')?.groups?.orgSlug).toEqual('company')
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('org.cal.com')?.groups?.orgSlug).toEqual('org')
|
||||
})
|
||||
|
||||
it('app.cal.com', ()=>{
|
||||
const subdomainRegExp = getSubdomainRegExp('app.cal.com');
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('app.cal.com')).toEqual(null)
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('company.app.cal.com')?.groups?.orgSlug).toEqual('company')
|
||||
})
|
||||
|
||||
it('https://calcom.app.company.com', ()=>{
|
||||
const subdomainRegExp = getSubdomainRegExp('https://calcom.app.company.com');
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('calcom.app.company.com')).toEqual(null)
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('acme.calcom.app.company.com')?.groups?.orgSlug).toEqual('acme')
|
||||
})
|
||||
|
||||
it('https://calcom.example.com', ()=>{
|
||||
const subdomainRegExp = getSubdomainRegExp('https://calcom.example.com');
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('calcom.example.com')).toEqual(null)
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('acme.calcom.example.com')?.groups?.orgSlug).toEqual('acme')
|
||||
// The following also matches which causes anything other than the domain in NEXT_PUBLIC_WEBAPP_URL to give 404
|
||||
expect(orgHostRegExp(subdomainRegExp).exec('some-other.company.com')?.groups?.orgSlug).toEqual('some-other')
|
||||
})
|
||||
})
|
||||
})
|
|
@ -22,7 +22,8 @@ export function defaultCookies(useSecureCookies: boolean): CookiesOptions {
|
|||
const defaultOptions: CookieOption["options"] = {
|
||||
domain: isENVDev
|
||||
? process.env.ORGANIZATIONS_ENABLED
|
||||
? ".cal.local"
|
||||
? //FIXME: This is causing login to not work if someone uses anything other .cal.local for testing
|
||||
".cal.local"
|
||||
: undefined
|
||||
: NEXTAUTH_COOKIE_DOMAIN,
|
||||
// To enable cookies on widgets,
|
||||
|
|
Loading…
Reference in New Issue