chore: Remove DEPLOYMENT and SUBDOMAINS_ENABLED (#5742)
This commit is contained in:
@@ -18,7 +18,6 @@ import InputColor from "~/components/InputColor";
|
|||||||
import Scene from "~/components/Scene";
|
import Scene from "~/components/Scene";
|
||||||
import Switch from "~/components/Switch";
|
import Switch from "~/components/Switch";
|
||||||
import Text from "~/components/Text";
|
import Text from "~/components/Text";
|
||||||
import env from "~/env";
|
|
||||||
import useCurrentTeam from "~/hooks/useCurrentTeam";
|
import useCurrentTeam from "~/hooks/useCurrentTeam";
|
||||||
import usePolicy from "~/hooks/usePolicy";
|
import usePolicy from "~/hooks/usePolicy";
|
||||||
import useStores from "~/hooks/useStores";
|
import useStores from "~/hooks/useStores";
|
||||||
@@ -255,7 +254,7 @@ function Details() {
|
|||||||
<Heading as="h2">{t("Behavior")}</Heading>
|
<Heading as="h2">{t("Behavior")}</Heading>
|
||||||
|
|
||||||
<SettingRow
|
<SettingRow
|
||||||
visible={env.SUBDOMAINS_ENABLED && isCloudHosted}
|
visible={isCloudHosted}
|
||||||
label={t("Subdomain")}
|
label={t("Subdomain")}
|
||||||
name="subdomain"
|
name="subdomain"
|
||||||
description={
|
description={
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import env from "~/env";
|
|||||||
import { client } from "~/utils/ApiClient";
|
import { client } from "~/utils/ApiClient";
|
||||||
import Desktop from "~/utils/Desktop";
|
import Desktop from "~/utils/Desktop";
|
||||||
import Logger from "~/utils/Logger";
|
import Logger from "~/utils/Logger";
|
||||||
|
import isCloudHosted from "~/utils/isCloudHosted";
|
||||||
|
|
||||||
const AUTH_STORE = "AUTH_STORE";
|
const AUTH_STORE = "AUTH_STORE";
|
||||||
const NO_REDIRECT_PATHS = ["/", "/create", "/home", "/logout"];
|
const NO_REDIRECT_PATHS = ["/", "/create", "/home", "/logout"];
|
||||||
@@ -212,7 +213,7 @@ export default class AuthStore {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
env.SUBDOMAINS_ENABLED &&
|
isCloudHosted &&
|
||||||
parseDomain(hostname).teamSubdomain !== (team.subdomain ?? "")
|
parseDomain(hostname).teamSubdomain !== (team.subdomain ?? "")
|
||||||
) {
|
) {
|
||||||
window.location.href = `${team.url}${pathname}`;
|
window.location.href = `${team.url}${pathname}`;
|
||||||
@@ -372,7 +373,7 @@ export default class AuthStore {
|
|||||||
const sessions = JSON.parse(getCookie("sessions") || "{}");
|
const sessions = JSON.parse(getCookie("sessions") || "{}");
|
||||||
delete sessions[team.id];
|
delete sessions[team.id];
|
||||||
setCookie("sessions", JSON.stringify(sessions), {
|
setCookie("sessions", JSON.stringify(sessions), {
|
||||||
domain: getCookieDomain(window.location.hostname),
|
domain: getCookieDomain(window.location.hostname, isCloudHosted),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import env from "~/env";
|
|||||||
/**
|
/**
|
||||||
* True if the current installation is the cloud hosted version at getoutline.com
|
* True if the current installation is the cloud hosted version at getoutline.com
|
||||||
*/
|
*/
|
||||||
const isCloudHosted = env.DEPLOYMENT === "hosted";
|
const isCloudHosted = [
|
||||||
|
"https://app.getoutline.com",
|
||||||
|
"https://app.outline.dev",
|
||||||
|
"https://app.outline.dev:3000",
|
||||||
|
].includes(env.URL);
|
||||||
|
|
||||||
export default isCloudHosted;
|
export default isCloudHosted;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import sharedEnv from "@shared/env";
|
|
||||||
import SigninEmail from "@server/emails/templates/SigninEmail";
|
import SigninEmail from "@server/emails/templates/SigninEmail";
|
||||||
import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
||||||
import env from "@server/env";
|
|
||||||
import { AuthenticationProvider } from "@server/models";
|
import { AuthenticationProvider } from "@server/models";
|
||||||
import { buildUser, buildGuestUser, buildTeam } from "@server/test/factories";
|
import { buildUser, buildGuestUser, buildTeam } from "@server/test/factories";
|
||||||
import { getTestServer } from "@server/test/support";
|
import { getTestServer, setCloudHosted } from "@server/test/support";
|
||||||
|
|
||||||
const server = getTestServer();
|
const server = getTestServer();
|
||||||
|
|
||||||
describe("email", () => {
|
describe("email", () => {
|
||||||
|
beforeEach(setCloudHosted);
|
||||||
|
|
||||||
it("should require email param", async () => {
|
it("should require email param", async () => {
|
||||||
const res = await server.post("/auth/email", {
|
const res = await server.post("/auth/email", {
|
||||||
body: {},
|
body: {},
|
||||||
@@ -21,11 +21,19 @@ describe("email", () => {
|
|||||||
|
|
||||||
it("should respond with redirect location when user is SSO enabled", async () => {
|
it("should respond with redirect location when user is SSO enabled", async () => {
|
||||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||||
const user = await buildUser();
|
const team = await buildTeam({
|
||||||
|
subdomain: "example",
|
||||||
|
});
|
||||||
|
const user = await buildUser({
|
||||||
|
teamId: team.id,
|
||||||
|
});
|
||||||
const res = await server.post("/auth/email", {
|
const res = await server.post("/auth/email", {
|
||||||
body: {
|
body: {
|
||||||
email: user.email,
|
email: user.email,
|
||||||
},
|
},
|
||||||
|
headers: {
|
||||||
|
host: "example.outline.dev",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
expect(res.status).toEqual(200);
|
expect(res.status).toEqual(200);
|
||||||
@@ -71,10 +79,6 @@ describe("email", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should not send email when user is on another subdomain but respond with success", async () => {
|
it("should not send email when user is on another subdomain but respond with success", async () => {
|
||||||
env.URL = sharedEnv.URL = "https://app.outline.dev";
|
|
||||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
|
|
||||||
const user = await buildUser();
|
const user = await buildUser();
|
||||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||||
await buildTeam({
|
await buildTeam({
|
||||||
@@ -138,11 +142,10 @@ describe("email", () => {
|
|||||||
expect(spy).not.toHaveBeenCalled();
|
expect(spy).not.toHaveBeenCalled();
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("with multiple users matching email", () => {
|
describe("with multiple users matching email", () => {
|
||||||
it("should default to current subdomain with SSO", async () => {
|
it("should default to current subdomain with SSO", async () => {
|
||||||
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
||||||
env.URL = sharedEnv.URL = "https://app.outline.dev";
|
|
||||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
|
||||||
const email = "sso-user@example.org";
|
const email = "sso-user@example.org";
|
||||||
const team = await buildTeam({
|
const team = await buildTeam({
|
||||||
subdomain: "example",
|
subdomain: "example",
|
||||||
@@ -171,8 +174,6 @@ describe("email", () => {
|
|||||||
|
|
||||||
it("should default to current subdomain with guest email", async () => {
|
it("should default to current subdomain with guest email", async () => {
|
||||||
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
const spy = jest.spyOn(SigninEmail.prototype, "schedule");
|
||||||
env.URL = sharedEnv.URL = "https://app.outline.dev";
|
|
||||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
|
||||||
const email = "guest-user@example.org";
|
const email = "guest-user@example.org";
|
||||||
const team = await buildTeam({
|
const team = await buildTeam({
|
||||||
subdomain: "example",
|
subdomain: "example",
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ router.post(
|
|||||||
const domain = parseDomain(ctx.request.hostname);
|
const domain = parseDomain(ctx.request.hostname);
|
||||||
|
|
||||||
let team: Team | null | undefined;
|
let team: Team | null | undefined;
|
||||||
if (!env.isCloudHosted()) {
|
if (!env.isCloudHosted) {
|
||||||
team = await Team.scope("withAuthenticationProviders").findOne();
|
team = await Team.scope("withAuthenticationProviders").findOne();
|
||||||
} else if (domain.custom) {
|
} else if (domain.custom) {
|
||||||
team = await Team.scope("withAuthenticationProviders").findOne({
|
team = await Team.scope("withAuthenticationProviders").findOne({
|
||||||
where: { domain: domain.host },
|
where: { domain: domain.host },
|
||||||
});
|
});
|
||||||
} else if (env.SUBDOMAINS_ENABLED && domain.teamSubdomain) {
|
} else if (domain.teamSubdomain) {
|
||||||
team = await Team.scope("withAuthenticationProviders").findOne({
|
team = await Team.scope("withAuthenticationProviders").findOne({
|
||||||
where: { subdomain: domain.teamSubdomain },
|
where: { subdomain: domain.teamSubdomain },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ export default class DeliverWebhookTask extends BaseTask<Props> {
|
|||||||
});
|
});
|
||||||
status = response.ok ? "success" : "failed";
|
status = response.ok ? "success" : "failed";
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof FetchError && env.DEPLOYMENT === "hosted") {
|
if (err instanceof FetchError && env.isCloudHosted) {
|
||||||
Logger.warn(`Failed to send webhook: ${err.message}`, {
|
Logger.warn(`Failed to send webhook: ${err.message}`, {
|
||||||
event,
|
event,
|
||||||
deliveryId: delivery.id,
|
deliveryId: delivery.id,
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
||||||
import env from "@server/env";
|
|
||||||
import { TeamDomain } from "@server/models";
|
import { TeamDomain } from "@server/models";
|
||||||
import Collection from "@server/models/Collection";
|
import Collection from "@server/models/Collection";
|
||||||
import UserAuthentication from "@server/models/UserAuthentication";
|
import UserAuthentication from "@server/models/UserAuthentication";
|
||||||
import { buildUser, buildTeam } from "@server/test/factories";
|
import { buildUser, buildTeam } from "@server/test/factories";
|
||||||
import { setupTestDatabase, seed } from "@server/test/support";
|
import {
|
||||||
|
setupTestDatabase,
|
||||||
|
seed,
|
||||||
|
setCloudHosted,
|
||||||
|
setSelfHosted,
|
||||||
|
} from "@server/test/support";
|
||||||
import accountProvisioner from "./accountProvisioner";
|
import accountProvisioner from "./accountProvisioner";
|
||||||
|
|
||||||
setupTestDatabase();
|
setupTestDatabase();
|
||||||
@@ -13,9 +17,7 @@ describe("accountProvisioner", () => {
|
|||||||
const ip = "127.0.0.1";
|
const ip = "127.0.0.1";
|
||||||
|
|
||||||
describe("hosted", () => {
|
describe("hosted", () => {
|
||||||
beforeEach(() => {
|
beforeEach(setCloudHosted);
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should create a new user and team", async () => {
|
it("should create a new user and team", async () => {
|
||||||
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
const spy = jest.spyOn(WelcomeEmail.prototype, "schedule");
|
||||||
@@ -325,9 +327,7 @@ describe("accountProvisioner", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("self hosted", () => {
|
describe("self hosted", () => {
|
||||||
beforeEach(() => {
|
beforeEach(setSelfHosted);
|
||||||
env.DEPLOYMENT = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should fail if existing team and domain not in allowed list", async () => {
|
it("should fail if existing team and domain not in allowed list", async () => {
|
||||||
let error;
|
let error;
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import env from "@server/env";
|
|
||||||
import TeamDomain from "@server/models/TeamDomain";
|
import TeamDomain from "@server/models/TeamDomain";
|
||||||
import { buildTeam, buildUser } from "@server/test/factories";
|
import { buildTeam, buildUser } from "@server/test/factories";
|
||||||
import { setupTestDatabase } from "@server/test/support";
|
import {
|
||||||
|
setCloudHosted,
|
||||||
|
setSelfHosted,
|
||||||
|
setupTestDatabase,
|
||||||
|
} from "@server/test/support";
|
||||||
import teamProvisioner from "./teamProvisioner";
|
import teamProvisioner from "./teamProvisioner";
|
||||||
|
|
||||||
setupTestDatabase();
|
setupTestDatabase();
|
||||||
@@ -10,9 +13,7 @@ describe("teamProvisioner", () => {
|
|||||||
const ip = "127.0.0.1";
|
const ip = "127.0.0.1";
|
||||||
|
|
||||||
describe("hosted", () => {
|
describe("hosted", () => {
|
||||||
beforeEach(() => {
|
beforeEach(setCloudHosted);
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should create team and authentication provider", async () => {
|
it("should create team and authentication provider", async () => {
|
||||||
const result = await teamProvisioner({
|
const result = await teamProvisioner({
|
||||||
@@ -127,9 +128,7 @@ describe("teamProvisioner", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("self hosted", () => {
|
describe("self hosted", () => {
|
||||||
beforeEach(() => {
|
beforeEach(setSelfHosted);
|
||||||
env.DEPLOYMENT = undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should allow creating first team", async () => {
|
it("should allow creating first team", async () => {
|
||||||
const { team, isNewTeam } = await teamProvisioner({
|
const { team, isNewTeam } = await teamProvisioner({
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ async function teamProvisioner({
|
|||||||
};
|
};
|
||||||
} else if (teamId) {
|
} else if (teamId) {
|
||||||
// The user is attempting to log into a team with an unfamiliar SSO provider
|
// The user is attempting to log into a team with an unfamiliar SSO provider
|
||||||
if (env.isCloudHosted()) {
|
if (env.isCloudHosted) {
|
||||||
throw InvalidAuthenticationError();
|
throw InvalidAuthenticationError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const teamUpdater = async ({
|
|||||||
preferences,
|
preferences,
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
if (subdomain !== undefined && env.SUBDOMAINS_ENABLED) {
|
if (subdomain !== undefined && env.isCloudHosted) {
|
||||||
team.subdomain = subdomain === "" ? null : subdomain;
|
team.subdomain = subdomain === "" ? null : subdomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ export class Mailer {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
attachments: env.isCloudHosted()
|
attachments: env.isCloudHosted
|
||||||
? undefined
|
? undefined
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default () => (
|
|||||||
<img
|
<img
|
||||||
alt={env.APP_NAME}
|
alt={env.APP_NAME}
|
||||||
src={
|
src={
|
||||||
env.isCloudHosted()
|
env.isCloudHosted
|
||||||
? `${url}/email/header-logo.png`
|
? `${url}/email/header-logo.png`
|
||||||
: "cid:header-image"
|
: "cid:header-image"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
IsUrl,
|
IsUrl,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsByteLength,
|
IsByteLength,
|
||||||
Equals,
|
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsIn,
|
IsIn,
|
||||||
IsEmail,
|
IsEmail,
|
||||||
@@ -206,13 +205,6 @@ export class Environment {
|
|||||||
@CannotUseWithout("SSL_KEY")
|
@CannotUseWithout("SSL_KEY")
|
||||||
public SSL_CERT = this.toOptionalString(process.env.SSL_CERT);
|
public SSL_CERT = this.toOptionalString(process.env.SSL_CERT);
|
||||||
|
|
||||||
/**
|
|
||||||
* Should always be left unset in a self-hosted environment.
|
|
||||||
*/
|
|
||||||
@Equals("hosted")
|
|
||||||
@IsOptional()
|
|
||||||
public DEPLOYMENT = this.toOptionalString(process.env.DEPLOYMENT);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default interface language. See translate.getoutline.com for a list of
|
* The default interface language. See translate.getoutline.com for a list of
|
||||||
* available language codes and their percentage translated.
|
* available language codes and their percentage translated.
|
||||||
@@ -240,15 +232,6 @@ export class Environment {
|
|||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
public FORCE_HTTPS = this.toBoolean(process.env.FORCE_HTTPS ?? "true");
|
public FORCE_HTTPS = this.toBoolean(process.env.FORCE_HTTPS ?? "true");
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to support multiple subdomains in a single instance.
|
|
||||||
*/
|
|
||||||
@IsBoolean()
|
|
||||||
@Deprecated("The community edition of Outline does not support subdomains")
|
|
||||||
public SUBDOMAINS_ENABLED = this.toBoolean(
|
|
||||||
process.env.SUBDOMAINS_ENABLED ?? "false"
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should the installation send anonymized statistics to the maintainers.
|
* Should the installation send anonymized statistics to the maintainers.
|
||||||
* Defaults to true.
|
* Defaults to true.
|
||||||
@@ -666,8 +649,12 @@ export class Environment {
|
|||||||
* Returns true if the current installation is the cloud hosted version at
|
* Returns true if the current installation is the cloud hosted version at
|
||||||
* getoutline.com
|
* getoutline.com
|
||||||
*/
|
*/
|
||||||
public isCloudHosted() {
|
public get isCloudHosted() {
|
||||||
return this.DEPLOYMENT === "hosted";
|
return [
|
||||||
|
"https://app.getoutline.com",
|
||||||
|
"https://app.outline.dev",
|
||||||
|
"https://app.outline.dev:3000",
|
||||||
|
].includes(this.URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private toOptionalString(value: string | undefined) {
|
private toOptionalString(value: string | undefined) {
|
||||||
|
|||||||
@@ -70,9 +70,9 @@ class Team extends ParanoidModel {
|
|||||||
@Unique
|
@Unique
|
||||||
@Length({
|
@Length({
|
||||||
min: 2,
|
min: 2,
|
||||||
max: env.isCloudHosted() ? 32 : 255,
|
max: env.isCloudHosted ? 32 : 255,
|
||||||
msg: `subdomain must be between 2 and ${
|
msg: `subdomain must be between 2 and ${
|
||||||
env.isCloudHosted() ? 32 : 255
|
env.isCloudHosted ? 32 : 255
|
||||||
} characters`,
|
} characters`,
|
||||||
})
|
})
|
||||||
@Is({
|
@Is({
|
||||||
@@ -169,7 +169,7 @@ class Team extends ParanoidModel {
|
|||||||
return `${url.protocol}//${this.domain}${url.port ? `:${url.port}` : ""}`;
|
return `${url.protocol}//${this.domain}${url.port ? `:${url.port}` : ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.subdomain || !env.SUBDOMAINS_ENABLED) {
|
if (!this.subdomain || !env.isCloudHosted) {
|
||||||
return env.URL;
|
return env.URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import env from "@server/env";
|
|
||||||
import { buildAdmin, buildTeam } from "@server/test/factories";
|
import { buildAdmin, buildTeam } from "@server/test/factories";
|
||||||
import { setupTestDatabase } from "@server/test/support";
|
import { setCloudHosted, setupTestDatabase } from "@server/test/support";
|
||||||
import TeamDomain from "./TeamDomain";
|
import TeamDomain from "./TeamDomain";
|
||||||
|
|
||||||
setupTestDatabase();
|
setupTestDatabase();
|
||||||
|
|
||||||
describe("team domain model", () => {
|
describe("team domain model", () => {
|
||||||
|
beforeEach(setCloudHosted);
|
||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
it("should allow creation of domains", async () => {
|
it("should allow creation of domains", async () => {
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
@@ -37,7 +38,6 @@ describe("team domain model", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should not allow creation of domains within restricted list", async () => {
|
it("should not allow creation of domains within restricted list", async () => {
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
const TeamDomain = await import("./TeamDomain");
|
const TeamDomain = await import("./TeamDomain");
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const user = await buildAdmin({ teamId: team.id });
|
const user = await buildAdmin({ teamId: team.id });
|
||||||
@@ -57,7 +57,6 @@ describe("team domain model", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should ignore casing and spaces when creating domains", async () => {
|
it("should ignore casing and spaces when creating domains", async () => {
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
const TeamDomain = await import("./TeamDomain");
|
const TeamDomain = await import("./TeamDomain");
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const user = await buildAdmin({ teamId: team.id });
|
const user = await buildAdmin({ teamId: team.id });
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import Length from "./validators/Length";
|
|||||||
@Fix
|
@Fix
|
||||||
class TeamDomain extends IdModel {
|
class TeamDomain extends IdModel {
|
||||||
@NotIn({
|
@NotIn({
|
||||||
args: env.isCloudHosted() ? [emailProviders] : [],
|
args: env.isCloudHosted ? [emailProviders] : [],
|
||||||
msg: "You chose a restricted domain, please try another.",
|
msg: "You chose a restricted domain, please try another.",
|
||||||
})
|
})
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export default class AuthenticationHelper {
|
|||||||
* @returns A list of authentication providers
|
* @returns A list of authentication providers
|
||||||
*/
|
*/
|
||||||
public static providersForTeam(team?: Team) {
|
public static providersForTeam(team?: Team) {
|
||||||
const isCloudHosted = env.isCloudHosted();
|
const isCloudHosted = env.isCloudHosted;
|
||||||
|
|
||||||
return AuthenticationHelper.providers
|
return AuthenticationHelper.providers
|
||||||
.sort((config) => (config.id === "email" ? 1 : -1))
|
.sort((config) => (config.id === "email" ? 1 : -1))
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import env from "@server/env";
|
|
||||||
import { buildUser, buildTeam, buildAdmin } from "@server/test/factories";
|
import { buildUser, buildTeam, buildAdmin } from "@server/test/factories";
|
||||||
import { setupTestDatabase } from "@server/test/support";
|
import {
|
||||||
|
setCloudHosted,
|
||||||
|
setSelfHosted,
|
||||||
|
setupTestDatabase,
|
||||||
|
} from "@server/test/support";
|
||||||
import { serialize } from "./index";
|
import { serialize } from "./index";
|
||||||
|
|
||||||
setupTestDatabase();
|
setupTestDatabase();
|
||||||
|
|
||||||
it("should allow reading only", async () => {
|
it("should allow reading only", async () => {
|
||||||
|
setSelfHosted();
|
||||||
|
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const user = await buildUser({
|
const user = await buildUser({
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
@@ -21,6 +26,8 @@ it("should allow reading only", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should allow admins to manage", async () => {
|
it("should allow admins to manage", async () => {
|
||||||
|
setSelfHosted();
|
||||||
|
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const admin = await buildAdmin({
|
const admin = await buildAdmin({
|
||||||
teamId: team.id,
|
teamId: team.id,
|
||||||
@@ -36,7 +43,7 @@ it("should allow admins to manage", async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should allow creation on hosted envs", async () => {
|
it("should allow creation on hosted envs", async () => {
|
||||||
env.DEPLOYMENT = "hosted";
|
setCloudHosted();
|
||||||
|
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const admin = await buildAdmin({
|
const admin = await buildAdmin({
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ allow(User, "share", Team, (user, team) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
allow(User, "createTeam", Team, () => {
|
allow(User, "createTeam", Team, () => {
|
||||||
if (!env.isCloudHosted()) {
|
if (!env.isCloudHosted) {
|
||||||
throw IncorrectEditionError("Functionality is only available on cloud");
|
throw IncorrectEditionError("Functionality is only available on cloud");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -27,7 +27,7 @@ allow(User, "update", Team, (user, team) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
allow(User, ["delete", "audit"], Team, (user, team) => {
|
allow(User, ["delete", "audit"], Team, (user, team) => {
|
||||||
if (!env.isCloudHosted()) {
|
if (!env.isCloudHosted) {
|
||||||
throw IncorrectEditionError("Functionality is only available on cloud");
|
throw IncorrectEditionError("Functionality is only available on cloud");
|
||||||
}
|
}
|
||||||
if (!team || user.isViewer || user.teamId !== team.id) {
|
if (!team || user.isViewer || user.teamId !== team.id) {
|
||||||
|
|||||||
@@ -16,14 +16,12 @@ export default function present(
|
|||||||
COLLABORATION_URL: (env.COLLABORATION_URL || env.URL)
|
COLLABORATION_URL: (env.COLLABORATION_URL || env.URL)
|
||||||
.replace(/\/$/, "")
|
.replace(/\/$/, "")
|
||||||
.replace(/^http/, "ws"),
|
.replace(/^http/, "ws"),
|
||||||
DEPLOYMENT: env.DEPLOYMENT,
|
|
||||||
ENVIRONMENT: env.ENVIRONMENT,
|
ENVIRONMENT: env.ENVIRONMENT,
|
||||||
SENTRY_DSN: env.SENTRY_DSN,
|
SENTRY_DSN: env.SENTRY_DSN,
|
||||||
SENTRY_TUNNEL: env.SENTRY_TUNNEL,
|
SENTRY_TUNNEL: env.SENTRY_TUNNEL,
|
||||||
SLACK_CLIENT_ID: env.SLACK_CLIENT_ID,
|
SLACK_CLIENT_ID: env.SLACK_CLIENT_ID,
|
||||||
SLACK_APP_ID: env.SLACK_APP_ID,
|
SLACK_APP_ID: env.SLACK_APP_ID,
|
||||||
MAXIMUM_IMPORT_SIZE: env.MAXIMUM_IMPORT_SIZE,
|
MAXIMUM_IMPORT_SIZE: env.MAXIMUM_IMPORT_SIZE,
|
||||||
SUBDOMAINS_ENABLED: env.SUBDOMAINS_ENABLED,
|
|
||||||
PDF_EXPORT_ENABLED: false,
|
PDF_EXPORT_ENABLED: false,
|
||||||
DEFAULT_LANGUAGE: env.DEFAULT_LANGUAGE,
|
DEFAULT_LANGUAGE: env.DEFAULT_LANGUAGE,
|
||||||
EMAIL_ENABLED: !!env.SMTP_HOST || env.ENVIRONMENT === "development",
|
EMAIL_ENABLED: !!env.SMTP_HOST || env.ENVIRONMENT === "development",
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import sharedEnv from "@shared/env";
|
|
||||||
import env from "@server/env";
|
|
||||||
import { buildUser, buildTeam } from "@server/test/factories";
|
import { buildUser, buildTeam } from "@server/test/factories";
|
||||||
import { getTestServer } from "@server/test/support";
|
import {
|
||||||
|
getTestServer,
|
||||||
|
setCloudHosted,
|
||||||
|
setSelfHosted,
|
||||||
|
} from "@server/test/support";
|
||||||
|
|
||||||
const mockTeamInSessionId = "1e023d05-951c-41c6-9012-c9fa0402e1c3";
|
const mockTeamInSessionId = "1e023d05-951c-41c6-9012-c9fa0402e1c3";
|
||||||
|
|
||||||
@@ -14,6 +16,8 @@ jest.mock("@server/utils/authentication", () => ({
|
|||||||
const server = getTestServer();
|
const server = getTestServer();
|
||||||
|
|
||||||
describe("#auth.info", () => {
|
describe("#auth.info", () => {
|
||||||
|
beforeEach(setCloudHosted);
|
||||||
|
|
||||||
it("should return current authentication", async () => {
|
it("should return current authentication", async () => {
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const team2 = await buildTeam();
|
const team2 = await buildTeam();
|
||||||
@@ -93,8 +97,6 @@ describe("#auth.delete", () => {
|
|||||||
|
|
||||||
describe("#auth.config", () => {
|
describe("#auth.config", () => {
|
||||||
it("should return available SSO providers", async () => {
|
it("should return available SSO providers", async () => {
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
|
|
||||||
const res = await server.post("/api/auth.config");
|
const res = await server.post("/api/auth.config");
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
expect(res.status).toEqual(200);
|
expect(res.status).toEqual(200);
|
||||||
@@ -105,10 +107,6 @@ describe("#auth.config", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return available providers for team subdomain", async () => {
|
it("should return available providers for team subdomain", async () => {
|
||||||
env.URL = sharedEnv.URL = "https://app.outline.dev";
|
|
||||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
|
|
||||||
await buildTeam({
|
await buildTeam({
|
||||||
guestSignin: false,
|
guestSignin: false,
|
||||||
subdomain: "example",
|
subdomain: "example",
|
||||||
@@ -131,8 +129,6 @@ describe("#auth.config", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return available providers for team custom domain", async () => {
|
it("should return available providers for team custom domain", async () => {
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
|
|
||||||
await buildTeam({
|
await buildTeam({
|
||||||
guestSignin: false,
|
guestSignin: false,
|
||||||
domain: "docs.mycompany.com",
|
domain: "docs.mycompany.com",
|
||||||
@@ -155,9 +151,6 @@ describe("#auth.config", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return email provider for team when guest signin enabled", async () => {
|
it("should return email provider for team when guest signin enabled", async () => {
|
||||||
env.URL = sharedEnv.URL = "https://app.outline.dev";
|
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
|
|
||||||
await buildTeam({
|
await buildTeam({
|
||||||
guestSignin: true,
|
guestSignin: true,
|
||||||
subdomain: "example",
|
subdomain: "example",
|
||||||
@@ -181,9 +174,6 @@ describe("#auth.config", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should not return provider when disabled", async () => {
|
it("should not return provider when disabled", async () => {
|
||||||
env.URL = sharedEnv.URL = "https://app.outline.dev";
|
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
|
|
||||||
await buildTeam({
|
await buildTeam({
|
||||||
guestSignin: false,
|
guestSignin: false,
|
||||||
subdomain: "example",
|
subdomain: "example",
|
||||||
@@ -206,8 +196,9 @@ describe("#auth.config", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("self hosted", () => {
|
describe("self hosted", () => {
|
||||||
|
beforeEach(setSelfHosted);
|
||||||
|
|
||||||
it("should return all configured providers but respect email setting", async () => {
|
it("should return all configured providers but respect email setting", async () => {
|
||||||
env.DEPLOYMENT = "";
|
|
||||||
await buildTeam({
|
await buildTeam({
|
||||||
guestSignin: false,
|
guestSignin: false,
|
||||||
authenticationProviders: [
|
authenticationProviders: [
|
||||||
@@ -227,7 +218,6 @@ describe("#auth.config", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return email provider for team when guest signin enabled", async () => {
|
it("should return email provider for team when guest signin enabled", async () => {
|
||||||
env.DEPLOYMENT = "";
|
|
||||||
await buildTeam({
|
await buildTeam({
|
||||||
guestSignin: true,
|
guestSignin: true,
|
||||||
authenticationProviders: [
|
authenticationProviders: [
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ router.post("auth.config", async (ctx: APIContext<T.AuthConfigReq>) => {
|
|||||||
// If self hosted AND there is only one team then that team becomes the
|
// If self hosted AND there is only one team then that team becomes the
|
||||||
// brand for the knowledge base and it's guest signin option is used for the
|
// brand for the knowledge base and it's guest signin option is used for the
|
||||||
// root login page.
|
// root login page.
|
||||||
if (!env.isCloudHosted()) {
|
if (!env.isCloudHosted) {
|
||||||
const team = await Team.scope("withAuthenticationProviders").findOne();
|
const team = await Team.scope("withAuthenticationProviders").findOne();
|
||||||
|
|
||||||
if (team) {
|
if (team) {
|
||||||
@@ -75,7 +75,7 @@ router.post("auth.config", async (ctx: APIContext<T.AuthConfigReq>) => {
|
|||||||
|
|
||||||
// If subdomain signin page then we return minimal team details to allow
|
// If subdomain signin page then we return minimal team details to allow
|
||||||
// for a custom screen showing only relevant signin options for that team.
|
// for a custom screen showing only relevant signin options for that team.
|
||||||
else if (env.SUBDOMAINS_ENABLED && domain.teamSubdomain) {
|
else if (env.isCloudHosted && domain.teamSubdomain) {
|
||||||
const team = await Team.scope("withAuthenticationProviders").findOne({
|
const team = await Team.scope("withAuthenticationProviders").findOne({
|
||||||
where: {
|
where: {
|
||||||
subdomain: domain.teamSubdomain,
|
subdomain: domain.teamSubdomain,
|
||||||
@@ -179,7 +179,7 @@ router.post(
|
|||||||
|
|
||||||
ctx.cookies.set("accessToken", "", {
|
ctx.cookies.set("accessToken", "", {
|
||||||
expires: subMinutes(new Date(), 1),
|
expires: subMinutes(new Date(), 1),
|
||||||
domain: getCookieDomain(ctx.hostname),
|
domain: getCookieDomain(ctx.hostname, env.isCloudHosted),
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import env from "@server/env";
|
|
||||||
import { buildEvent, buildUser } from "@server/test/factories";
|
import { buildEvent, buildUser } from "@server/test/factories";
|
||||||
import { seed, getTestServer } from "@server/test/support";
|
import { seed, getTestServer, setCloudHosted } from "@server/test/support";
|
||||||
|
|
||||||
const server = getTestServer();
|
const server = getTestServer();
|
||||||
|
|
||||||
describe("#events.list", () => {
|
describe("#events.list", () => {
|
||||||
beforeEach(() => {
|
beforeEach(setCloudHosted);
|
||||||
env.DEPLOYMENT = "hosted";
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should only return activity events", async () => {
|
it("should only return activity events", async () => {
|
||||||
const { user, admin, document, collection } = await seed();
|
const { user, admin, document, collection } = await seed();
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
import env from "@server/env";
|
|
||||||
import { TeamDomain } from "@server/models";
|
import { TeamDomain } from "@server/models";
|
||||||
import { buildAdmin, buildCollection, buildTeam } from "@server/test/factories";
|
import { buildAdmin, buildCollection, buildTeam } from "@server/test/factories";
|
||||||
import { seed, getTestServer } from "@server/test/support";
|
import {
|
||||||
|
seed,
|
||||||
|
getTestServer,
|
||||||
|
setCloudHosted,
|
||||||
|
setSelfHosted,
|
||||||
|
} from "@server/test/support";
|
||||||
|
|
||||||
const server = getTestServer();
|
const server = getTestServer();
|
||||||
|
|
||||||
describe("teams.create", () => {
|
describe("teams.create", () => {
|
||||||
it("creates a team", async () => {
|
it("creates a team", async () => {
|
||||||
env.DEPLOYMENT = "hosted";
|
setCloudHosted();
|
||||||
|
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const user = await buildAdmin({ teamId: team.id });
|
const user = await buildAdmin({ teamId: team.id });
|
||||||
const res = await server.post("/api/teams.create", {
|
const res = await server.post("/api/teams.create", {
|
||||||
@@ -23,7 +28,8 @@ describe("teams.create", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("requires a cloud hosted deployment", async () => {
|
it("requires a cloud hosted deployment", async () => {
|
||||||
env.DEPLOYMENT = "";
|
setSelfHosted();
|
||||||
|
|
||||||
const team = await buildTeam();
|
const team = await buildTeam();
|
||||||
const user = await buildAdmin({ teamId: team.id });
|
const user = await buildAdmin({ teamId: team.id });
|
||||||
const res = await server.post("/api/teams.create", {
|
const res = await server.post("/api/teams.create", {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ env.OIDC_TOKEN_URI = "http://localhost/token";
|
|||||||
env.OIDC_USERINFO_URI = "http://localhost/userinfo";
|
env.OIDC_USERINFO_URI = "http://localhost/userinfo";
|
||||||
|
|
||||||
env.RATE_LIMITER_ENABLED = false;
|
env.RATE_LIMITER_ENABLED = false;
|
||||||
env.DEPLOYMENT = undefined;
|
|
||||||
|
|
||||||
if (process.env.DATABASE_URL_TEST) {
|
if (process.env.DATABASE_URL_TEST) {
|
||||||
env.DATABASE_URL = process.env.DATABASE_URL_TEST;
|
env.DATABASE_URL = process.env.DATABASE_URL_TEST;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import TestServer from "fetch-test-server";
|
import TestServer from "fetch-test-server";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import sharedEnv from "@shared/env";
|
||||||
import { CollectionPermission } from "@shared/types";
|
import { CollectionPermission } from "@shared/types";
|
||||||
|
import env from "@server/env";
|
||||||
import { User, Document, Collection, Team } from "@server/models";
|
import { User, Document, Collection, Team } from "@server/models";
|
||||||
import onerror from "@server/onerror";
|
import onerror from "@server/onerror";
|
||||||
import webService from "@server/services/web";
|
import webService from "@server/services/web";
|
||||||
@@ -137,3 +139,17 @@ export function setupTestDatabase() {
|
|||||||
afterAll(disconnect);
|
afterAll(disconnect);
|
||||||
beforeEach(flush);
|
beforeEach(flush);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the environment to be cloud hosted
|
||||||
|
*/
|
||||||
|
export function setCloudHosted() {
|
||||||
|
return (env.URL = sharedEnv.URL = "https://app.outline.dev");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the environment to be self hosted
|
||||||
|
*/
|
||||||
|
export function setSelfHosted() {
|
||||||
|
return (env.URL = sharedEnv.URL = "https://wiki.example.com");
|
||||||
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export async function signIn(
|
|||||||
},
|
},
|
||||||
ip: ctx.request.ip,
|
ip: ctx.request.ip,
|
||||||
});
|
});
|
||||||
const domain = getCookieDomain(ctx.request.hostname);
|
const domain = getCookieDomain(ctx.request.hostname, env.isCloudHosted);
|
||||||
const expires = addMonths(new Date(), 3);
|
const expires = addMonths(new Date(), 3);
|
||||||
|
|
||||||
// set a cookie for which service we last signed in with. This is
|
// set a cookie for which service we last signed in with. This is
|
||||||
@@ -85,7 +85,7 @@ export async function signIn(
|
|||||||
|
|
||||||
// set a transfer cookie for the access token itself and redirect
|
// set a transfer cookie for the access token itself and redirect
|
||||||
// to the teams subdomain if subdomains are enabled
|
// to the teams subdomain if subdomains are enabled
|
||||||
if (env.SUBDOMAINS_ENABLED && team.subdomain) {
|
if (env.isCloudHosted && team.subdomain) {
|
||||||
// get any existing sessions (teams signed in) and add this team
|
// get any existing sessions (teams signed in) and add this team
|
||||||
const existing = getSessionsInCookie(ctx);
|
const existing = getSessionsInCookie(ctx);
|
||||||
const sessions = encodeURIComponent(
|
const sessions = encodeURIComponent(
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default class AzureClient extends OAuthClient {
|
|||||||
refreshToken?: string;
|
refreshToken?: string;
|
||||||
expiresAt: Date;
|
expiresAt: Date;
|
||||||
}> {
|
}> {
|
||||||
if (env.isCloudHosted()) {
|
if (env.isCloudHosted) {
|
||||||
return super.rotateToken(accessToken, refreshToken);
|
return super.rotateToken(accessToken, refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,10 @@ export default function fetch(
|
|||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
// In self-hosted, webhooks support proxying and are also allowed to connect
|
// In self-hosted, webhooks support proxying and are also allowed to connect
|
||||||
// to internal services, so use fetchWithProxy without the filtering agent.
|
// to internal services, so use fetchWithProxy without the filtering agent.
|
||||||
const fetch = env.isCloudHosted() ? nodeFetch : fetchWithProxy;
|
const fetch = env.isCloudHosted ? nodeFetch : fetchWithProxy;
|
||||||
|
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
...init,
|
...init,
|
||||||
agent: env.isCloudHosted() ? useAgent(url) : undefined,
|
agent: env.isCloudHosted ? useAgent(url) : undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class StateStore {
|
|||||||
|
|
||||||
ctx.cookies.set(this.key, state, {
|
ctx.cookies.set(this.key, state, {
|
||||||
expires: addMinutes(new Date(), 10),
|
expires: addMinutes(new Date(), 10),
|
||||||
domain: getCookieDomain(ctx.hostname),
|
domain: getCookieDomain(ctx.hostname, env.isCloudHosted),
|
||||||
});
|
});
|
||||||
|
|
||||||
callback(null, token);
|
callback(null, token);
|
||||||
@@ -54,7 +54,7 @@ export class StateStore {
|
|||||||
// Destroy the one-time pad token and ensure it matches
|
// Destroy the one-time pad token and ensure it matches
|
||||||
ctx.cookies.set(this.key, "", {
|
ctx.cookies.set(this.key, "", {
|
||||||
expires: subMinutes(new Date(), 1),
|
expires: subMinutes(new Date(), 1),
|
||||||
domain: getCookieDomain(ctx.hostname),
|
domain: getCookieDomain(ctx.hostname, env.isCloudHosted),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!token || token !== providedToken) {
|
if (!token || token !== providedToken) {
|
||||||
@@ -100,11 +100,11 @@ export async function getTeamFromContext(ctx: Context) {
|
|||||||
const domain = parseDomain(host);
|
const domain = parseDomain(host);
|
||||||
|
|
||||||
let team;
|
let team;
|
||||||
if (!env.isCloudHosted()) {
|
if (!env.isCloudHosted) {
|
||||||
team = await Team.findOne();
|
team = await Team.findOne();
|
||||||
} else if (domain.custom) {
|
} else if (domain.custom) {
|
||||||
team = await Team.findOne({ where: { domain: domain.host } });
|
team = await Team.findOne({ where: { domain: domain.host } });
|
||||||
} else if (env.SUBDOMAINS_ENABLED && domain.teamSubdomain) {
|
} else if (domain.teamSubdomain) {
|
||||||
team = await Team.findOne({
|
team = await Team.findOne({
|
||||||
where: { subdomain: domain.teamSubdomain },
|
where: { subdomain: domain.teamSubdomain },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import env from "@server/env";
|
import env from "@server/env";
|
||||||
|
|
||||||
export const robotsResponse = () => {
|
export const robotsResponse = () => {
|
||||||
if (env.isCloudHosted()) {
|
if (env.isCloudHosted) {
|
||||||
return `
|
return `
|
||||||
User-agent: *
|
User-agent: *
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export async function checkPendingMigrations() {
|
|||||||
try {
|
try {
|
||||||
const pending = await migrations.pending();
|
const pending = await migrations.pending();
|
||||||
if (!isEmpty(pending)) {
|
if (!isEmpty(pending)) {
|
||||||
if (env.isCloudHosted()) {
|
if (env.isCloudHosted) {
|
||||||
Logger.warn(chalk.red("Migrations are pending"));
|
Logger.warn(chalk.red("Migrations are pending"));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
} else {
|
} else {
|
||||||
@@ -34,7 +34,7 @@ export async function checkPendingMigrations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function checkDataMigrations() {
|
export async function checkDataMigrations() {
|
||||||
if (env.isCloudHosted()) {
|
if (env.isCloudHosted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,14 +44,12 @@ export type PublicEnv = {
|
|||||||
COLLABORATION_URL: string;
|
COLLABORATION_URL: string;
|
||||||
AWS_S3_UPLOAD_BUCKET_URL: string;
|
AWS_S3_UPLOAD_BUCKET_URL: string;
|
||||||
AWS_S3_ACCELERATE_URL: string;
|
AWS_S3_ACCELERATE_URL: string;
|
||||||
DEPLOYMENT: string | undefined;
|
|
||||||
ENVIRONMENT: string;
|
ENVIRONMENT: string;
|
||||||
SENTRY_DSN: string | undefined;
|
SENTRY_DSN: string | undefined;
|
||||||
SENTRY_TUNNEL: string | undefined;
|
SENTRY_TUNNEL: string | undefined;
|
||||||
SLACK_CLIENT_ID: string | undefined;
|
SLACK_CLIENT_ID: string | undefined;
|
||||||
SLACK_APP_ID: string | undefined;
|
SLACK_APP_ID: string | undefined;
|
||||||
MAXIMUM_IMPORT_SIZE: number;
|
MAXIMUM_IMPORT_SIZE: number;
|
||||||
SUBDOMAINS_ENABLED: boolean;
|
|
||||||
EMAIL_ENABLED: boolean;
|
EMAIL_ENABLED: boolean;
|
||||||
PDF_EXPORT_ENABLED: boolean;
|
PDF_EXPORT_ENABLED: boolean;
|
||||||
DEFAULT_LANGUAGE: string;
|
DEFAULT_LANGUAGE: string;
|
||||||
|
|||||||
@@ -169,27 +169,27 @@ describe("#slugifyDomain", () => {
|
|||||||
describe("#getCookieDomain", () => {
|
describe("#getCookieDomain", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
env.URL = "https://example.com";
|
env.URL = "https://example.com";
|
||||||
env.SUBDOMAINS_ENABLED = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns the normalized app host when on the host domain", () => {
|
it("returns the normalized app host when on the host domain", () => {
|
||||||
expect(getCookieDomain("subdomain.example.com")).toBe("example.com");
|
expect(getCookieDomain("subdomain.example.com", true)).toBe("example.com");
|
||||||
expect(getCookieDomain("www.example.com")).toBe("example.com");
|
expect(getCookieDomain("www.example.com", true)).toBe("example.com");
|
||||||
expect(getCookieDomain("http://example.com:3000")).toBe("example.com");
|
expect(getCookieDomain("http://example.com:3000", true)).toBe(
|
||||||
expect(getCookieDomain("myteam.example.com/document/12345?q=query")).toBe(
|
|
||||||
"example.com"
|
"example.com"
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
getCookieDomain("myteam.example.com/document/12345?q=query", true)
|
||||||
|
).toBe("example.com");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns the input if not on the host domain", () => {
|
it("returns the input if not on the host domain", () => {
|
||||||
expect(getCookieDomain("www.blogspot.com")).toBe("www.blogspot.com");
|
expect(getCookieDomain("www.blogspot.com", true)).toBe("www.blogspot.com");
|
||||||
expect(getCookieDomain("anything else")).toBe("anything else");
|
expect(getCookieDomain("anything else", true)).toBe("anything else");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("always returns the input when subdomains are not enabled", () => {
|
it("always returns the input when not cloud hosted", () => {
|
||||||
env.SUBDOMAINS_ENABLED = false;
|
expect(getCookieDomain("example.com", false)).toBe("example.com");
|
||||||
expect(getCookieDomain("example.com")).toBe("example.com");
|
expect(getCookieDomain("www.blogspot.com", false)).toBe("www.blogspot.com");
|
||||||
expect(getCookieDomain("www.blogspot.com")).toBe("www.blogspot.com");
|
expect(getCookieDomain("anything else", false)).toBe("anything else");
|
||||||
expect(getCookieDomain("anything else")).toBe("anything else");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ export function parseDomain(url: string): Domain {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCookieDomain(domain: string) {
|
export function getCookieDomain(domain: string, isCloudHosted: boolean) {
|
||||||
// always use the base URL for cookies when in hosted mode
|
// always use the base URL for cookies when in hosted mode
|
||||||
// and the domain is not custom
|
// and the domain is not custom
|
||||||
if (env.SUBDOMAINS_ENABLED) {
|
if (isCloudHosted) {
|
||||||
const parsed = parseDomain(domain);
|
const parsed = parseDomain(domain);
|
||||||
|
|
||||||
if (!parsed.custom) {
|
if (!parsed.custom) {
|
||||||
|
|||||||
Reference in New Issue
Block a user