mirror of
https://github.com/docmost/docmost.git
synced 2025-11-10 00:22:05 +10:00
custom domain support (cloud)
This commit is contained in:
@ -82,6 +82,7 @@
|
||||
"sanitize-filename-ts": "^1.0.2",
|
||||
"socket.io": "^4.8.1",
|
||||
"stripe": "^17.5.0",
|
||||
"tld-extract": "^2.1.0",
|
||||
"tmp-promise": "^3.0.3",
|
||||
"ws": "^8.18.2",
|
||||
"yauzl": "^3.2.0"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Injectable, NestMiddleware, NotFoundException } from '@nestjs/common';
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import { EnvironmentService } from '../../integrations/environment/environment.service';
|
||||
import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo';
|
||||
@ -27,8 +27,19 @@ export class DomainMiddleware implements NestMiddleware {
|
||||
(req as any).workspace = workspace;
|
||||
} else if (this.environmentService.isCloud()) {
|
||||
const header = req.headers.host;
|
||||
const subdomain = header.split('.')[0];
|
||||
|
||||
// First, try to find workspace by custom domain
|
||||
const workspaceByCustomDomain =
|
||||
await this.workspaceRepo.findByCustomDomain(header);
|
||||
|
||||
if (workspaceByCustomDomain) {
|
||||
(req as any).workspaceId = workspaceByCustomDomain.id;
|
||||
(req as any).workspace = workspaceByCustomDomain;
|
||||
return next();
|
||||
}
|
||||
|
||||
// Fall back to subdomain logic
|
||||
const subdomain = header.split('.')[0];
|
||||
const workspace = await this.workspaceRepo.findByHostname(subdomain);
|
||||
|
||||
if (!workspace) {
|
||||
|
||||
@ -134,7 +134,7 @@ export class AuthService {
|
||||
|
||||
const token = nanoIdGen(16);
|
||||
|
||||
const resetLink = `${this.domainService.getUrl(workspace.hostname)}/password-reset?token=${token}`;
|
||||
const resetLink = `${this.domainService.getUrl(workspace.hostname, workspace.customDomain)}/password-reset?token=${token}`;
|
||||
|
||||
await this.userTokenRepo.insertUserToken({
|
||||
token: token,
|
||||
|
||||
@ -171,7 +171,7 @@ export class WorkspaceInvitationService {
|
||||
invitation.email,
|
||||
invitation.token,
|
||||
authUser.name,
|
||||
workspace.hostname,
|
||||
workspace,
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -317,7 +317,7 @@ export class WorkspaceInvitationService {
|
||||
invitation.email,
|
||||
invitation.token,
|
||||
invitedByUser.name,
|
||||
workspace.hostname,
|
||||
workspace,
|
||||
);
|
||||
}
|
||||
|
||||
@ -340,17 +340,17 @@ export class WorkspaceInvitationService {
|
||||
return this.buildInviteLink({
|
||||
invitationId,
|
||||
inviteToken: token.token,
|
||||
hostname: workspace.hostname,
|
||||
workspace: workspace,
|
||||
});
|
||||
}
|
||||
|
||||
async buildInviteLink(opts: {
|
||||
invitationId: string;
|
||||
inviteToken: string;
|
||||
hostname?: string;
|
||||
workspace: Workspace;
|
||||
}): Promise<string> {
|
||||
const { invitationId, inviteToken, hostname } = opts;
|
||||
return `${this.domainService.getUrl(hostname)}/invites/${invitationId}?token=${inviteToken}`;
|
||||
const { invitationId, inviteToken, workspace } = opts;
|
||||
return `${this.domainService.getUrl(workspace.hostname, workspace.customDomain)}/invites/${invitationId}?token=${inviteToken}`;
|
||||
}
|
||||
|
||||
async sendInvitationMail(
|
||||
@ -358,12 +358,12 @@ export class WorkspaceInvitationService {
|
||||
inviteeEmail: string,
|
||||
inviteToken: string,
|
||||
invitedByName: string,
|
||||
hostname?: string,
|
||||
workspace: Workspace,
|
||||
): Promise<void> {
|
||||
const inviteLink = await this.buildInviteLink({
|
||||
invitationId,
|
||||
inviteToken,
|
||||
hostname,
|
||||
workspace,
|
||||
});
|
||||
|
||||
const emailTemplate = InvitationEmail({
|
||||
|
||||
@ -83,6 +83,14 @@ export class WorkspaceRepo {
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
async findByCustomDomain(domain: string): Promise<Workspace> {
|
||||
return await this.db
|
||||
.selectFrom('workspaces')
|
||||
.selectAll()
|
||||
.where(sql`LOWER(custom_domain)`, '=', sql`LOWER(${domain})`)
|
||||
.executeTakeFirst();
|
||||
}
|
||||
|
||||
async hostnameExists(
|
||||
hostname: string,
|
||||
trx?: KyselyTransaction,
|
||||
|
||||
Submodule apps/server/src/ee updated: 19197d2610...1e127cec1d
@ -5,10 +5,13 @@ import { EnvironmentService } from './environment.service';
|
||||
export class DomainService {
|
||||
constructor(private environmentService: EnvironmentService) {}
|
||||
|
||||
getUrl(hostname?: string): string {
|
||||
getUrl(hostname?: string, customDomain?: string): string {
|
||||
if (!this.environmentService.isCloud()) {
|
||||
return this.environmentService.getAppUrl();
|
||||
}
|
||||
if (customDomain) {
|
||||
return customDomain;
|
||||
}
|
||||
|
||||
const domain = this.environmentService.getSubdomainHost();
|
||||
if (!hostname || !domain) {
|
||||
|
||||
@ -68,6 +68,10 @@ export class EnvironmentVariables {
|
||||
)
|
||||
@ValidateIf((obj) => obj.CLOUD === 'true'.toLowerCase())
|
||||
SUBDOMAIN_HOST: string;
|
||||
|
||||
@IsOptional()
|
||||
@ValidateIf((obj) => obj.CLOUD === 'true'.toLowerCase())
|
||||
APP_IP: string;
|
||||
}
|
||||
|
||||
export function validate(config: Record<string, any>) {
|
||||
|
||||
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@ -567,6 +567,9 @@ importers:
|
||||
stripe:
|
||||
specifier: ^17.5.0
|
||||
version: 17.5.0
|
||||
tld-extract:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
tmp-promise:
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3
|
||||
@ -8864,6 +8867,9 @@ packages:
|
||||
tiptap-extension-global-drag-handle@0.1.18:
|
||||
resolution: {integrity: sha512-jwFuy1K8DP3a4bFy76Hpc63w1Sil0B7uZ3mvhQomVvUFCU787Lg2FowNhn7NFzeyok761qY2VG+PZ/FDthWUdg==}
|
||||
|
||||
tld-extract@2.1.0:
|
||||
resolution: {integrity: sha512-Y9QHWIoDQPJJVm3/pOC7kOfOj7vsNSVZl4JGoEHb605FiwZgIfzSMyU0HC0wYw5Cx8435vaG1yGZtIm1yiQGOw==}
|
||||
|
||||
tldts-core@6.1.72:
|
||||
resolution: {integrity: sha512-FW3H9aCaGTJ8l8RVCR3EX8GxsxDbQXuwetwwgXA2chYdsX+NY1ytCBl61narjjehWmCw92tc1AxlcY3668CU8g==}
|
||||
|
||||
@ -19538,6 +19544,8 @@ snapshots:
|
||||
|
||||
tiptap-extension-global-drag-handle@0.1.18: {}
|
||||
|
||||
tld-extract@2.1.0: {}
|
||||
|
||||
tldts-core@6.1.72: {}
|
||||
|
||||
tldts@6.1.72:
|
||||
|
||||
Reference in New Issue
Block a user