mirror of
https://github.com/fosrl/pangolin.git
synced 2026-04-13 13:26:36 +00:00
Merge branch 'dev' into private-site-ha
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db, loginPage } from "@server/db";
|
||||
import { db, domainNamespaces, loginPage } from "@server/db";
|
||||
import {
|
||||
domains,
|
||||
orgDomains,
|
||||
@@ -24,6 +24,8 @@ import { build } from "@server/build";
|
||||
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
|
||||
import { getUniqueResourceName } from "@server/db/names";
|
||||
import { validateAndConstructDomain } from "@server/lib/domainUtils";
|
||||
import { isSubscribed } from "#dynamic/lib/isSubscribed";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
|
||||
const createResourceParamsSchema = z.strictObject({
|
||||
orgId: z.string()
|
||||
@@ -112,7 +114,10 @@ export async function createResource(
|
||||
|
||||
const { orgId } = parsedParams.data;
|
||||
|
||||
if (req.user && (!req.userOrgRoleIds || req.userOrgRoleIds.length === 0)) {
|
||||
if (
|
||||
req.user &&
|
||||
(!req.userOrgRoleIds || req.userOrgRoleIds.length === 0)
|
||||
) {
|
||||
return next(
|
||||
createHttpError(HttpCode.FORBIDDEN, "User does not have a role")
|
||||
);
|
||||
@@ -193,6 +198,29 @@ async function createHttpResource(
|
||||
const subdomain = parsedBody.data.subdomain;
|
||||
const stickySession = parsedBody.data.stickySession;
|
||||
|
||||
if (build == "saas" && !isSubscribed(orgId!, tierMatrix.domainNamespaces)) {
|
||||
// grandfather in existing users
|
||||
const lastAllowedDate = new Date("2026-04-12");
|
||||
const userCreatedDate = new Date(req.user?.dateCreated || new Date());
|
||||
if (userCreatedDate > lastAllowedDate) {
|
||||
// check if this domain id is a namespace domain and if so, reject
|
||||
const domain = await db
|
||||
.select()
|
||||
.from(domainNamespaces)
|
||||
.where(eq(domainNamespaces.domainId, domainId))
|
||||
.limit(1);
|
||||
|
||||
if (domain.length > 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Your current subscription does not support custom domain namespaces. Please upgrade to access this feature."
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate domain and construct full domain
|
||||
const domainResult = await validateAndConstructDomain(
|
||||
domainId,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db, loginPage } from "@server/db";
|
||||
import { db, domainNamespaces, loginPage } from "@server/db";
|
||||
import {
|
||||
domains,
|
||||
Org,
|
||||
@@ -25,6 +25,7 @@ import { validateAndConstructDomain } from "@server/lib/domainUtils";
|
||||
import { build } from "@server/build";
|
||||
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||
import { isSubscribed } from "#dynamic/lib/isSubscribed";
|
||||
|
||||
const updateResourceParamsSchema = z.strictObject({
|
||||
resourceId: z.string().transform(Number).pipe(z.int().positive())
|
||||
@@ -120,7 +121,9 @@ const updateHttpResourceBodySchema = z
|
||||
if (data.headers) {
|
||||
// HTTP header values must be visible ASCII or horizontal whitespace, no control chars (RFC 7230)
|
||||
const validHeaderValue = /^[\t\x20-\x7E]*$/;
|
||||
return data.headers.every((h) => validHeaderValue.test(h.value));
|
||||
return data.headers.every((h) =>
|
||||
validHeaderValue.test(h.value)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
@@ -318,6 +321,34 @@ async function updateHttpResource(
|
||||
if (updateData.domainId) {
|
||||
const domainId = updateData.domainId;
|
||||
|
||||
if (
|
||||
build == "saas" &&
|
||||
!isSubscribed(resource.orgId, tierMatrix.domainNamespaces)
|
||||
) {
|
||||
// grandfather in existing users
|
||||
const lastAllowedDate = new Date("2026-04-12");
|
||||
const userCreatedDate = new Date(
|
||||
req.user?.dateCreated || new Date()
|
||||
);
|
||||
if (userCreatedDate > lastAllowedDate) {
|
||||
// check if this domain id is a namespace domain and if so, reject
|
||||
const domain = await db
|
||||
.select()
|
||||
.from(domainNamespaces)
|
||||
.where(eq(domainNamespaces.domainId, domainId))
|
||||
.limit(1);
|
||||
|
||||
if (domain.length > 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Your current subscription does not support custom domain namespaces. Please upgrade to access this feature."
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate domain and construct full domain
|
||||
const domainResult = await validateAndConstructDomain(
|
||||
domainId,
|
||||
@@ -366,7 +397,7 @@ async function updateHttpResource(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (build != "oss") {
|
||||
const existingLoginPages = await db
|
||||
.select()
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } from "@server/db";
|
||||
import { orgs, roles, userInviteRoles, userInvites, userOrgs, users } from "@server/db";
|
||||
import {
|
||||
orgs,
|
||||
roles,
|
||||
userInviteRoles,
|
||||
userInvites,
|
||||
userOrgs,
|
||||
users
|
||||
} from "@server/db";
|
||||
import { and, eq, inArray } from "drizzle-orm";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
@@ -37,8 +44,7 @@ const inviteUserBodySchema = z
|
||||
regenerate: z.boolean().optional()
|
||||
})
|
||||
.refine(
|
||||
(d) =>
|
||||
(d.roleIds != null && d.roleIds.length > 0) || d.roleId != null,
|
||||
(d) => (d.roleIds != null && d.roleIds.length > 0) || d.roleId != null,
|
||||
{ message: "roleIds or roleId is required", path: ["roleIds"] }
|
||||
)
|
||||
.transform((data) => ({
|
||||
@@ -265,7 +271,7 @@ export async function inviteUser(
|
||||
)
|
||||
);
|
||||
|
||||
const inviteLink = `${config.getRawConfig().app.dashboard_url}/invite?token=${inviteId}-${token}&email=${encodeURIComponent(email)}`;
|
||||
const inviteLink = `${config.getRawConfig().app.dashboard_url}/invite?token=${inviteId}-${token}&email=${email}`;
|
||||
|
||||
if (doEmail) {
|
||||
await sendEmail(
|
||||
@@ -314,12 +320,12 @@ export async function inviteUser(
|
||||
expiresAt,
|
||||
tokenHash
|
||||
});
|
||||
await trx.insert(userInviteRoles).values(
|
||||
uniqueRoleIds.map((roleId) => ({ inviteId, roleId }))
|
||||
);
|
||||
await trx
|
||||
.insert(userInviteRoles)
|
||||
.values(uniqueRoleIds.map((roleId) => ({ inviteId, roleId })));
|
||||
});
|
||||
|
||||
const inviteLink = `${config.getRawConfig().app.dashboard_url}/invite?token=${inviteId}-${token}&email=${encodeURIComponent(email)}`;
|
||||
const inviteLink = `${config.getRawConfig().app.dashboard_url}/invite?token=${inviteId}-${token}&email=${email}`;
|
||||
|
||||
if (doEmail) {
|
||||
await sendEmail(
|
||||
|
||||
Reference in New Issue
Block a user