Paywall resource policies

This commit is contained in:
Owen
2026-05-04 15:30:49 -07:00
parent 20ebdc6289
commit 43f2e32231
10 changed files with 243 additions and 186 deletions

View File

@@ -24,7 +24,8 @@ export enum TierFeature {
DomainNamespaces = "domainNamespaces", // handle downgrade by removing custom domain namespaces
StandaloneHealthChecks = "standaloneHealthChecks",
AlertingRules = "alertingRules",
WildcardSubdomain = "wildcardSubdomain"
WildcardSubdomain = "wildcardSubdomain",
ResourcePolicies = "resourcePolicies"
}
export const tierMatrix: Record<TierFeature, Tier[]> = {
@@ -66,5 +67,6 @@ export const tierMatrix: Record<TierFeature, Tier[]> = {
[TierFeature.DomainNamespaces]: ["tier1", "tier2", "tier3", "enterprise"],
[TierFeature.StandaloneHealthChecks]: ["tier3", "enterprise"],
[TierFeature.AlertingRules]: ["tier3", "enterprise"],
[TierFeature.WildcardSubdomain]: ["tier1", "tier2", "tier3", "enterprise"]
[TierFeature.WildcardSubdomain]: ["tier1", "tier2", "tier3", "enterprise"],
[TierFeature.ResourcePolicies]: ["tier3", "enterprise"]
};

View File

@@ -389,7 +389,7 @@ authenticated.delete(
"/resource-policy/:resourcePolicyId",
verifyResourcePolicyAccess,
verifyValidLicense,
// verifyValidSubscription(tierMatrix.loginPageDomain), // todo: use the correct subscription ?
verifyValidSubscription(tierMatrix.resourcePolicies),
verifyLimits,
verifyUserHasAction(ActionsEnum.deleteResourcePolicy),
logActionAudit(ActionsEnum.deleteResourcePolicy),
@@ -399,7 +399,7 @@ authenticated.delete(
authenticated.get(
"/org/:orgId/resource-policies",
verifyValidLicense,
// verifyValidSubscription(tierMatrix.loginPageDomain), // todo: use the correct subscription ?
verifyValidSubscription(tierMatrix.resourcePolicies),
verifyOrgAccess,
verifyLimits,
verifyUserHasAction(ActionsEnum.listResourcePolicies),
@@ -410,7 +410,7 @@ authenticated.get(
authenticated.post(
"/org/:orgId/resource-policy",
verifyValidLicense,
// verifyValidSubscription(tierMatrix.loginPageDomain), // todo: use the correct subscription ?
verifyValidSubscription(tierMatrix.resourcePolicies),
verifyOrgAccess,
verifyLimits,
verifyUserHasAction(ActionsEnum.createResourcePolicy),

View File

@@ -1,3 +1,16 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025-2026 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.
* You may not use this file except in compliance with the License.
* Unauthorized use, copying, modification, or distribution is strictly prohibited.
*
* This file is not licensed under the AGPLv3.
*/
import { hashPassword } from "@server/auth/password";
import {
db,

View File

@@ -1,7 +1,7 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* Copyright (c) 2025-2026 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.

View File

@@ -1,7 +1,7 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* Copyright (c) 2025-2026 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.

View File

@@ -1,7 +1,7 @@
/*
* This file is part of a proprietary work.
*
* Copyright (c) 2025 Fossorial, Inc.
* Copyright (c) 2025-2026 Fossorial, Inc.
* All rights reserved.
*
* This file is licensed under the Fossorial Commercial License.

View File

@@ -25,7 +25,10 @@ import {
import { registry } from "@server/openApi";
import { OpenAPITags } from "@server/openApi";
import { createCertificate } from "#dynamic/routers/certificates/createCertificate";
import { validateAndConstructDomain, checkWildcardDomainConflict } from "@server/lib/domainUtils";
import {
validateAndConstructDomain,
checkWildcardDomainConflict
} from "@server/lib/domainUtils";
import { build } from "@server/build";
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
import { tierMatrix } from "@server/lib/billing/tierMatrix";
@@ -304,11 +307,30 @@ async function updateHttpResource(
const updateData = parsedBody.data;
const isLicensed = await isLicensedOrSubscribed(
resource.orgId,
tierMatrix.wildcardSubdomain
);
if (updateData.resourcePolicyId != null) {
if (!isLicensed) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Resource policies are not supported on your current plan. Please upgrade to access this feature."
)
);
}
const [existingPolicy] = await db
.select()
.from(resourcePolicies)
.where(eq(resourcePolicies.resourcePolicyId, updateData.resourcePolicyId))
.where(
eq(
resourcePolicies.resourcePolicyId,
updateData.resourcePolicyId
)
)
.limit(1);
if (!existingPolicy) {
@@ -346,10 +368,6 @@ async function updateHttpResource(
// Wildcard subdomains are a paid feature
if (updateData.subdomain && updateData.subdomain.includes("*")) {
const isLicensed = await isLicensedOrSubscribed(
resource.orgId,
tierMatrix.wildcardSubdomain
);
if (!isLicensed) {
return next(
createHttpError(
@@ -494,10 +512,6 @@ async function updateHttpResource(
headers = null;
}
const isLicensed = await isLicensedOrSubscribed(
resource.orgId,
tierMatrix.maintencePage
);
if (!isLicensed) {
updateData.maintenanceModeEnabled = undefined;
updateData.maintenanceModeType = undefined;
@@ -560,7 +574,12 @@ async function updateRawResource(
const [existingPolicy] = await db
.select()
.from(resourcePolicies)
.where(eq(resourcePolicies.resourcePolicyId, updateData.resourcePolicyId))
.where(
eq(
resourcePolicies.resourcePolicyId,
updateData.resourcePolicyId
)
)
.limit(1);
if (!existingPolicy) {