mirror of
https://github.com/outline/outline.git
synced 2026-06-13 11:25:03 +03:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1ed57d5ad |
@@ -10,7 +10,6 @@ import Heading from "~/components/Heading";
|
||||
import Input from "~/components/Input";
|
||||
import Scene from "~/components/Scene";
|
||||
import Text from "~/components/Text";
|
||||
import env from "~/env";
|
||||
import useCurrentTeam from "~/hooks/useCurrentTeam";
|
||||
import useStores from "~/hooks/useStores";
|
||||
import useToasts from "~/hooks/useToasts";
|
||||
@@ -135,7 +134,7 @@ function Details() {
|
||||
/>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
visible={env.SUBDOMAINS_ENABLED && isCloudHosted}
|
||||
visible={isCloudHosted}
|
||||
label={t("Subdomain")}
|
||||
name="subdomain"
|
||||
description={
|
||||
|
||||
@@ -10,6 +10,7 @@ import User from "~/models/User";
|
||||
import env from "~/env";
|
||||
import { client } from "~/utils/ApiClient";
|
||||
import Storage from "~/utils/Storage";
|
||||
import isCloudHosted from "~/utils/isCloudHosted";
|
||||
|
||||
const AUTH_STORE = "AUTH_STORE";
|
||||
const NO_REDIRECT_PATHS = ["/", "/create", "/home"];
|
||||
@@ -172,7 +173,7 @@ export default class AuthStore {
|
||||
return;
|
||||
}
|
||||
} else if (
|
||||
env.SUBDOMAINS_ENABLED &&
|
||||
isCloudHosted &&
|
||||
parseDomain(hostname).teamSubdomain !== (team.subdomain ?? "")
|
||||
) {
|
||||
window.location.href = `${team.url}${pathname}`;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { sequelize } from "@server/database/sequelize";
|
||||
import env from "@server/env";
|
||||
import {
|
||||
DomainNotAllowedError,
|
||||
InvalidAuthenticationError,
|
||||
@@ -9,6 +8,7 @@ import Logger from "@server/logging/Logger";
|
||||
import { APM } from "@server/logging/tracing";
|
||||
import { Team, AuthenticationProvider, Event } from "@server/models";
|
||||
import { generateAvatarUrl } from "@server/utils/avatars";
|
||||
import isCloudHosted from "@server/utils/isCloudHosted";
|
||||
|
||||
type TeamProvisionerResult = {
|
||||
team: Team;
|
||||
@@ -79,7 +79,7 @@ async function teamProvisioner({
|
||||
// This team has never been seen before, if self hosted the logic is different
|
||||
// to the multi-tenant version, we want to restrict to a single team that MAY
|
||||
// have multiple authentication providers
|
||||
if (env.DEPLOYMENT !== "hosted") {
|
||||
if (!isCloudHosted) {
|
||||
const team = await Team.findOne();
|
||||
|
||||
// If the self-hosted installation has a single team and the domain for the
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Transaction } from "sequelize";
|
||||
import { sequelize } from "@server/database/sequelize";
|
||||
import env from "@server/env";
|
||||
import { Event, Team, TeamDomain, User } from "@server/models";
|
||||
|
||||
type TeamUpdaterProps = {
|
||||
@@ -28,7 +27,7 @@ const teamUpdater = async ({ params, user, team, ip }: TeamUpdaterProps) => {
|
||||
|
||||
const transaction: Transaction = await sequelize.transaction();
|
||||
|
||||
if (subdomain !== undefined && env.SUBDOMAINS_ENABLED) {
|
||||
if (subdomain !== undefined) {
|
||||
team.subdomain = subdomain === "" ? null : subdomain;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ import Oy from "oy-vey";
|
||||
import env from "@server/env";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { APM } from "@server/logging/tracing";
|
||||
import isCloudHosted from "@server/utils/isCloudHosted";
|
||||
import { baseStyles } from "./templates/components/EmailLayout";
|
||||
|
||||
const isCloudHosted = env.DEPLOYMENT === "hosted";
|
||||
const useTestEmailService =
|
||||
env.ENVIRONMENT === "development" && !env.SMTP_USERNAME;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Table, TBody, TR, TD } from "oy-vey";
|
||||
import * as React from "react";
|
||||
import env from "@server/env";
|
||||
import isCloudHosted from "@server/utils/isCloudHosted";
|
||||
import EmptySpace from "./EmptySpace";
|
||||
|
||||
const url = env.CDN_URL ?? env.URL;
|
||||
const isCloudHosted = env.DEPLOYMENT === "hosted";
|
||||
|
||||
export default () => {
|
||||
return (
|
||||
|
||||
@@ -229,15 +229,6 @@ export class Environment {
|
||||
@IsBoolean()
|
||||
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.
|
||||
* Defaults to true.
|
||||
|
||||
@@ -144,7 +144,7 @@ class Team extends ParanoidModel {
|
||||
return `https://${this.domain}`;
|
||||
}
|
||||
|
||||
if (!this.subdomain || !env.SUBDOMAINS_ENABLED) {
|
||||
if (!this.subdomain) {
|
||||
return env.URL;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ export default function present(env: Environment): PublicEnv {
|
||||
SLACK_CLIENT_ID: env.SLACK_CLIENT_ID,
|
||||
SLACK_APP_ID: env.SLACK_APP_ID,
|
||||
MAXIMUM_IMPORT_SIZE: env.MAXIMUM_IMPORT_SIZE,
|
||||
SUBDOMAINS_ENABLED: env.SUBDOMAINS_ENABLED,
|
||||
DEFAULT_LANGUAGE: env.DEFAULT_LANGUAGE,
|
||||
EMAIL_ENABLED: !!env.SMTP_HOST || env.ENVIRONMENT === "development",
|
||||
GOOGLE_ANALYTICS_ID: env.GOOGLE_ANALYTICS_ID,
|
||||
|
||||
@@ -86,7 +86,6 @@ describe("#auth.config", () => {
|
||||
|
||||
it("should return available providers for team subdomain", async () => {
|
||||
env.URL = sharedEnv.URL = "http://localoutline.com";
|
||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
||||
env.DEPLOYMENT = "hosted";
|
||||
|
||||
await buildTeam({
|
||||
@@ -187,7 +186,7 @@ describe("#auth.config", () => {
|
||||
|
||||
describe("self hosted", () => {
|
||||
it("should return all configured providers but respect email setting", async () => {
|
||||
env.DEPLOYMENT = "";
|
||||
env.DEPLOYMENT = undefined;
|
||||
await buildTeam({
|
||||
guestSignin: false,
|
||||
authenticationProviders: [
|
||||
@@ -206,7 +205,7 @@ describe("#auth.config", () => {
|
||||
});
|
||||
|
||||
it("should return email provider for team when guest signin enabled", async () => {
|
||||
env.DEPLOYMENT = "";
|
||||
env.DEPLOYMENT = undefined;
|
||||
await buildTeam({
|
||||
guestSignin: true,
|
||||
authenticationProviders: [
|
||||
|
||||
@@ -2,11 +2,11 @@ import Router from "koa-router";
|
||||
import { find } from "lodash";
|
||||
import { parseDomain } from "@shared/utils/domains";
|
||||
import { sequelize } from "@server/database/sequelize";
|
||||
import env from "@server/env";
|
||||
import auth from "@server/middlewares/authentication";
|
||||
import { Event, Team } from "@server/models";
|
||||
import { presentUser, presentTeam, presentPolicies } from "@server/presenters";
|
||||
import ValidateSSOAccessTask from "@server/queues/tasks/ValidateSSOAccessTask";
|
||||
import isCloudHosted from "@server/utils/isCloudHosted";
|
||||
import providers from "../auth/providers";
|
||||
|
||||
const router = new Router();
|
||||
@@ -23,7 +23,7 @@ function filterProviders(team?: Team) {
|
||||
|
||||
return (
|
||||
!team ||
|
||||
env.DEPLOYMENT !== "hosted" ||
|
||||
!isCloudHosted ||
|
||||
find(team.authenticationProviders, {
|
||||
name: provider.id,
|
||||
enabled: true,
|
||||
@@ -41,7 +41,7 @@ router.post("auth.config", async (ctx) => {
|
||||
// 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
|
||||
// root login page.
|
||||
if (env.DEPLOYMENT !== "hosted") {
|
||||
if (!isCloudHosted) {
|
||||
const team = await Team.scope("withAuthenticationProviders").findOne();
|
||||
|
||||
if (team) {
|
||||
@@ -78,7 +78,7 @@ router.post("auth.config", async (ctx) => {
|
||||
|
||||
// If subdomain signin page then we return minimal team details to allow
|
||||
// for a custom screen showing only relevant signin options for that team.
|
||||
else if (env.SUBDOMAINS_ENABLED && domain.teamSubdomain) {
|
||||
else if (domain.teamSubdomain) {
|
||||
const team = await Team.scope("withAuthenticationProviders").findOne({
|
||||
where: {
|
||||
subdomain: domain.teamSubdomain,
|
||||
|
||||
@@ -40,7 +40,6 @@ describe("email", () => {
|
||||
|
||||
it("should respond with redirect location when user is SSO enabled on another subdomain", async () => {
|
||||
env.URL = sharedEnv.URL = "http://localoutline.com";
|
||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
||||
const user = await buildUser();
|
||||
const spy = jest.spyOn(WelcomeEmail, "schedule");
|
||||
await buildTeam({
|
||||
@@ -93,7 +92,6 @@ describe("email", () => {
|
||||
it("should default to current subdomain with SSO", async () => {
|
||||
const spy = jest.spyOn(SigninEmail, "schedule");
|
||||
env.URL = sharedEnv.URL = "http://localoutline.com";
|
||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
||||
const email = "sso-user@example.org";
|
||||
const team = await buildTeam({
|
||||
subdomain: "example",
|
||||
@@ -123,7 +121,8 @@ describe("email", () => {
|
||||
it("should default to current subdomain with guest email", async () => {
|
||||
const spy = jest.spyOn(SigninEmail, "schedule");
|
||||
env.URL = sharedEnv.URL = "http://localoutline.com";
|
||||
env.SUBDOMAINS_ENABLED = sharedEnv.SUBDOMAINS_ENABLED = true;
|
||||
env.DEPLOYMENT = sharedEnv.DEPLOYMENT = "hosted";
|
||||
|
||||
const email = "guest-user@example.org";
|
||||
const team = await buildTeam({
|
||||
subdomain: "example",
|
||||
|
||||
@@ -5,7 +5,6 @@ import { RateLimiterStrategy } from "@server/RateLimiter";
|
||||
import InviteAcceptedEmail from "@server/emails/templates/InviteAcceptedEmail";
|
||||
import SigninEmail from "@server/emails/templates/SigninEmail";
|
||||
import WelcomeEmail from "@server/emails/templates/WelcomeEmail";
|
||||
import env from "@server/env";
|
||||
import { AuthorizationError } from "@server/errors";
|
||||
import errorHandling from "@server/middlewares/errorHandling";
|
||||
import methodOverride from "@server/middlewares/methodOverride";
|
||||
@@ -47,7 +46,7 @@ router.post(
|
||||
domain: ctx.request.hostname,
|
||||
},
|
||||
});
|
||||
} else if (env.SUBDOMAINS_ENABLED && domain.teamSubdomain) {
|
||||
} else if (domain.teamSubdomain) {
|
||||
team = await Team.scope("withAuthenticationProviders").findOne({
|
||||
where: {
|
||||
subdomain: domain.teamSubdomain,
|
||||
|
||||
@@ -3,9 +3,9 @@ import { addMonths } from "date-fns";
|
||||
import { Context } from "koa";
|
||||
import { pick } from "lodash";
|
||||
import { getCookieDomain } from "@shared/utils/domains";
|
||||
import env from "@server/env";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import { User, Event, Team, Collection, View } from "@server/models";
|
||||
import isCloudHosted from "./isCloudHosted";
|
||||
|
||||
export async function signIn(
|
||||
ctx: Context,
|
||||
@@ -66,7 +66,7 @@ export async function signIn(
|
||||
|
||||
// set a transfer cookie for the access token itself and redirect
|
||||
// to the teams subdomain if subdomains are enabled
|
||||
if (env.SUBDOMAINS_ENABLED && team.subdomain) {
|
||||
if (isCloudHosted && team.subdomain) {
|
||||
// get any existing sessions (teams signed in) and add this team
|
||||
const existing = JSON.parse(
|
||||
decodeURIComponent(ctx.cookies.get("sessions") || "") || "{}"
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import env from "@server/env";
|
||||
|
||||
/**
|
||||
* True if the current installation is the cloud hosted version at getoutline.com
|
||||
*/
|
||||
const isCloudHosted = env.DEPLOYMENT === "hosted";
|
||||
|
||||
export default isCloudHosted;
|
||||
@@ -7,9 +7,9 @@ import {
|
||||
StateStoreVerifyCallback,
|
||||
} from "passport-oauth2";
|
||||
import { getCookieDomain, parseDomain } from "@shared/utils/domains";
|
||||
import env from "@server/env";
|
||||
import { Team } from "@server/models";
|
||||
import { OAuthStateMismatchError } from "../errors";
|
||||
import isCloudHosted from "./isCloudHosted";
|
||||
|
||||
export class StateStore {
|
||||
key = "state";
|
||||
@@ -94,11 +94,11 @@ export async function getTeamFromContext(ctx: Context) {
|
||||
const domain = parseDomain(host);
|
||||
|
||||
let team;
|
||||
if (env.DEPLOYMENT !== "hosted") {
|
||||
if (!isCloudHosted) {
|
||||
team = await Team.findOne();
|
||||
} else if (domain.custom) {
|
||||
team = await Team.findOne({ where: { domain: domain.host } });
|
||||
} else if (env.SUBDOMAINS_ENABLED && domain.teamSubdomain) {
|
||||
} else if (domain.teamSubdomain) {
|
||||
team = await Team.findOne({
|
||||
where: { subdomain: domain.teamSubdomain },
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import env from "@server/env";
|
||||
import isCloudHosted from "./isCloudHosted";
|
||||
|
||||
export const robotsResponse = () => {
|
||||
if (env.DEPLOYMENT === "hosted") {
|
||||
if (isCloudHosted) {
|
||||
return `
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
@@ -4,6 +4,7 @@ import env from "@server/env";
|
||||
import Logger from "@server/logging/Logger";
|
||||
import AuthenticationProvider from "@server/models/AuthenticationProvider";
|
||||
import Team from "@server/models/Team";
|
||||
import isCloudHosted from "./isCloudHosted";
|
||||
|
||||
export function checkPendingMigrations() {
|
||||
try {
|
||||
@@ -46,7 +47,7 @@ export function checkPendingMigrations() {
|
||||
}
|
||||
|
||||
export async function checkMigrations() {
|
||||
if (env.DEPLOYMENT === "hosted") {
|
||||
if (isCloudHosted) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ export type PublicEnv = {
|
||||
SLACK_CLIENT_ID: string | undefined;
|
||||
SLACK_APP_ID: string | undefined;
|
||||
MAXIMUM_IMPORT_SIZE: number;
|
||||
SUBDOMAINS_ENABLED: boolean;
|
||||
EMAIL_ENABLED: boolean;
|
||||
DEFAULT_LANGUAGE: string;
|
||||
GOOGLE_ANALYTICS_ID: string | undefined;
|
||||
|
||||
@@ -169,7 +169,7 @@ describe("#slugifyDomain", () => {
|
||||
describe("#getCookieDomain", () => {
|
||||
beforeEach(() => {
|
||||
env.URL = "https://example.com";
|
||||
env.SUBDOMAINS_ENABLED = true;
|
||||
env.DEPLOYMENT = "hosted";
|
||||
});
|
||||
|
||||
it("returns the normalized app host when on the host domain", () => {
|
||||
@@ -187,7 +187,7 @@ describe("#getCookieDomain", () => {
|
||||
});
|
||||
|
||||
it("always returns the input when subdomains are not enabled", () => {
|
||||
env.SUBDOMAINS_ENABLED = false;
|
||||
env.DEPLOYMENT = undefined;
|
||||
expect(getCookieDomain("example.com")).toBe("example.com");
|
||||
expect(getCookieDomain("www.blogspot.com")).toBe("www.blogspot.com");
|
||||
expect(getCookieDomain("anything else")).toBe("anything else");
|
||||
|
||||
@@ -68,7 +68,7 @@ export function parseDomain(url: string): Domain {
|
||||
export function getCookieDomain(domain: string) {
|
||||
// always use the base URL for cookies when in hosted mode
|
||||
// and the domain is not custom
|
||||
if (env.SUBDOMAINS_ENABLED) {
|
||||
if (env.DEPLOYMENT === "hosted") {
|
||||
const parsed = parseDomain(domain);
|
||||
|
||||
if (!parsed.custom) {
|
||||
@@ -94,6 +94,7 @@ export const RESERVED_SUBDOMAINS = [
|
||||
"cache",
|
||||
"cdn",
|
||||
"code",
|
||||
"collaboration",
|
||||
"community",
|
||||
"dashboard",
|
||||
"developer",
|
||||
|
||||
Reference in New Issue
Block a user