diff --git a/LICENSE b/LICENSE
index 8c5cfb89..0ad25db4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,35 +1,3 @@
-Copyright (c) 2025 Fossorial, LLC.
-
-Portions of this software are licensed as follows:
-
-* All files that include a header specifying they are licensed under the
- "Fossorial Commercial License" are governed by the Fossorial Commercial
- License terms. The specific terms applicable to each customer depend on the
- commercial license tier agreed upon in writing with Fossorial LLC.
- Unauthorized use, copying, modification, or distribution is strictly
- prohibited.
-
-* All files that include a header specifying they are licensed under the GNU
- Affero General Public License, Version 3 ("AGPL-3"), are governed by the
- AGPL-3 terms. A full copy of the AGPL-3 license is provided below. However,
- these files are also available under the Fossorial Commercial License if a
- separate commercial license agreement has been executed between the customer
- and Fossorial LLC.
-
-* All files without a license header are, by default, licensed under the GNU
- Affero General Public License, Version 3 (AGPL-3). These files may also be
- made available under the Fossorial Commercial License upon agreement with
- Fossorial LLC.
-
-* All third-party components included in this repository are licensed under
- their respective original licenses, as provided by their authors.
-
-Please consult the header of each individual file to determine the applicable
-license. For AGPL-3 licensed files, dual-licensing under the Fossorial
-Commercial License is available subject to written agreement with Fossorial
-LLC.
-
-
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
diff --git a/server/index.ts b/server/index.ts
index 4c16caaa..33502609 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -6,7 +6,7 @@ import { createNextServer } from "./nextServer";
import { createInternalServer } from "./internalServer";
import { ApiKey, ApiKeyOrg, Session, User, UserOrg } from "./db/schemas";
import { createIntegrationApiServer } from "./integrationApiServer";
-import license from "./license/license.js";
+import config from "@server/lib/config";
async function startServers() {
await runSetupFunctions();
@@ -17,7 +17,7 @@ async function startServers() {
const nextServer = await createNextServer();
let integrationServer;
- if (await license.isUnlocked()) {
+ if (config.getRawConfig().flags?.enable_integration_api) {
integrationServer = createIntegrationApiServer();
}
diff --git a/server/integrationApiServer.ts b/server/integrationApiServer.ts
index ff5dca51..f3dfbbef 100644
--- a/server/integrationApiServer.ts
+++ b/server/integrationApiServer.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import express from "express";
import cors from "cors";
import cookieParser from "cookie-parser";
@@ -11,7 +6,6 @@ import logger from "@server/logger";
import {
errorHandlerMiddleware,
notFoundMiddleware,
- verifyValidLicense
} from "@server/middlewares";
import { authenticated, unauthenticated } from "@server/routers/integration";
import { logIncomingMiddleware } from "./middlewares/logIncoming";
@@ -26,8 +20,6 @@ const externalPort = config.getRawConfig().server.integration_port;
export function createIntegrationApiServer() {
const apiServer = express();
- apiServer.use(verifyValidLicense);
-
if (config.getRawConfig().server.trust_proxy) {
apiServer.set("trust proxy", 1);
}
diff --git a/server/lib/config.ts b/server/lib/config.ts
index 678724a4..33239cbb 100644
--- a/server/lib/config.ts
+++ b/server/lib/config.ts
@@ -4,7 +4,216 @@ import db from "@server/db";
import { SupporterKey, supporterKey } from "@server/db/schemas";
import { eq } from "drizzle-orm";
import { license } from "@server/license/license";
-import { configSchema, readConfigFile } from "./readConfigFile";
+import { readConfigFile } from "./readConfigFile";
+import stoi from "./stoi";
+import { passwordSchema } from "@server/auth/passwordSchema";
+
+const portSchema = z.number().positive().gt(0).lte(65535);
+
+const getEnvOrYaml = (envVar: string) => (valFromYaml: any) => {
+ return process.env[envVar] ?? valFromYaml;
+};
+
+const configSchema = z.object({
+ app: z.object({
+ dashboard_url: z
+ .string()
+ .url()
+ .optional()
+ .pipe(z.string().url())
+ .transform((url) => url.toLowerCase()),
+ log_level: z
+ .enum(["debug", "info", "warn", "error"])
+ .optional()
+ .default("info"),
+ save_logs: z.boolean().optional().default(false),
+ log_failed_attempts: z.boolean().optional().default(false)
+ }),
+ domains: z
+ .record(
+ z.string(),
+ z.object({
+ base_domain: z
+ .string()
+ .nonempty("base_domain must not be empty")
+ .transform((url) => url.toLowerCase()),
+ cert_resolver: z.string().optional().default("letsencrypt"),
+ prefer_wildcard_cert: z.boolean().optional().default(false)
+ })
+ )
+ .refine(
+ (domains) => {
+ const keys = Object.keys(domains);
+
+ if (keys.length === 0) {
+ return false;
+ }
+
+ return true;
+ },
+ {
+ message: "At least one domain must be defined"
+ }
+ ),
+ server: z.object({
+ integration_port: portSchema
+ .optional()
+ .default(3003)
+ .transform(stoi)
+ .pipe(portSchema.optional()),
+ external_port: portSchema
+ .optional()
+ .default(3000)
+ .transform(stoi)
+ .pipe(portSchema),
+ internal_port: portSchema
+ .optional()
+ .default(3001)
+ .transform(stoi)
+ .pipe(portSchema),
+ next_port: portSchema
+ .optional()
+ .default(3002)
+ .transform(stoi)
+ .pipe(portSchema),
+ internal_hostname: z
+ .string()
+ .optional()
+ .default("pangolin")
+ .transform((url) => url.toLowerCase()),
+ session_cookie_name: z.string().optional().default("p_session_token"),
+ resource_access_token_param: z.string().optional().default("p_token"),
+ resource_access_token_headers: z
+ .object({
+ id: z.string().optional().default("P-Access-Token-Id"),
+ token: z.string().optional().default("P-Access-Token")
+ })
+ .optional()
+ .default({}),
+ resource_session_request_param: z
+ .string()
+ .optional()
+ .default("resource_session_request_param"),
+ dashboard_session_length_hours: z
+ .number()
+ .positive()
+ .gt(0)
+ .optional()
+ .default(720),
+ resource_session_length_hours: z
+ .number()
+ .positive()
+ .gt(0)
+ .optional()
+ .default(720),
+ cors: z
+ .object({
+ origins: z.array(z.string()).optional(),
+ methods: z.array(z.string()).optional(),
+ allowed_headers: z.array(z.string()).optional(),
+ credentials: z.boolean().optional()
+ })
+ .optional(),
+ trust_proxy: z.boolean().optional().default(true),
+ secret: z
+ .string()
+ .optional()
+ .transform(getEnvOrYaml("SERVER_SECRET"))
+ .pipe(z.string().min(8))
+ }),
+ traefik: z
+ .object({
+ http_entrypoint: z.string().optional().default("web"),
+ https_entrypoint: z.string().optional().default("websecure"),
+ additional_middlewares: z.array(z.string()).optional()
+ })
+ .optional()
+ .default({}),
+ gerbil: z
+ .object({
+ start_port: portSchema
+ .optional()
+ .default(51820)
+ .transform(stoi)
+ .pipe(portSchema),
+ base_endpoint: z
+ .string()
+ .optional()
+ .pipe(z.string())
+ .transform((url) => url.toLowerCase()),
+ use_subdomain: z.boolean().optional().default(false),
+ subnet_group: z.string().optional().default("100.89.137.0/20"),
+ block_size: z.number().positive().gt(0).optional().default(24),
+ site_block_size: z.number().positive().gt(0).optional().default(30)
+ })
+ .optional()
+ .default({}),
+ rate_limits: z
+ .object({
+ global: z
+ .object({
+ window_minutes: z
+ .number()
+ .positive()
+ .gt(0)
+ .optional()
+ .default(1),
+ max_requests: z
+ .number()
+ .positive()
+ .gt(0)
+ .optional()
+ .default(500)
+ })
+ .optional()
+ .default({}),
+ auth: z
+ .object({
+ window_minutes: z.number().positive().gt(0),
+ max_requests: z.number().positive().gt(0)
+ })
+ .optional()
+ })
+ .optional()
+ .default({}),
+ email: z
+ .object({
+ smtp_host: z.string().optional(),
+ smtp_port: portSchema.optional(),
+ smtp_user: z.string().optional(),
+ smtp_pass: z.string().optional(),
+ smtp_secure: z.boolean().optional(),
+ smtp_tls_reject_unauthorized: z.boolean().optional(),
+ no_reply: z.string().email().optional()
+ })
+ .optional(),
+ users: z.object({
+ server_admin: z.object({
+ email: z
+ .string()
+ .email()
+ .optional()
+ .transform(getEnvOrYaml("USERS_SERVERADMIN_EMAIL"))
+ .pipe(z.string().email())
+ .transform((v) => v.toLowerCase()),
+ password: passwordSchema
+ .optional()
+ .transform(getEnvOrYaml("USERS_SERVERADMIN_PASSWORD"))
+ .pipe(passwordSchema)
+ })
+ }),
+ flags: z
+ .object({
+ require_email_verification: z.boolean().optional(),
+ disable_signup_without_invite: z.boolean().optional(),
+ disable_user_create_org: z.boolean().optional(),
+ allow_raw_resources: z.boolean().optional(),
+ allow_base_domain_resources: z.boolean().optional(),
+ allow_local_sites: z.boolean().optional(),
+ enable_integration_api: z.boolean().optional()
+ })
+ .optional()
+});
export class Config {
private rawConfig!: z.infer;
diff --git a/server/lib/consts.ts b/server/lib/consts.ts
index c7c4e872..ed61e8ca 100644
--- a/server/lib/consts.ts
+++ b/server/lib/consts.ts
@@ -2,7 +2,7 @@ import path from "path";
import { fileURLToPath } from "url";
// This is a placeholder value replaced by the build process
-export const APP_VERSION = "1.3.2";
+export const APP_VERSION = "1.4.0";
export const __FILENAME = fileURLToPath(import.meta.url);
export const __DIRNAME = path.dirname(__FILENAME);
diff --git a/server/license/license.ts b/server/license/license.ts
index e97b8f50..bd596e4b 100644
--- a/server/license/license.ts
+++ b/server/license/license.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import db from "@server/db";
import { hostMeta, licenseKey, sites } from "@server/db/schemas";
import logger from "@server/logger";
diff --git a/server/license/licenseJwt.ts b/server/license/licenseJwt.ts
index ed7f4a0a..3d148e51 100644
--- a/server/license/licenseJwt.ts
+++ b/server/license/licenseJwt.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import * as crypto from "crypto";
/**
diff --git a/server/middlewares/integration/index.ts b/server/middlewares/integration/index.ts
index c16e1294..19bf128e 100644
--- a/server/middlewares/integration/index.ts
+++ b/server/middlewares/integration/index.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
export * from "./verifyApiKey";
export * from "./verifyApiKeyOrgAccess";
export * from "./verifyApiKeyHasAction";
diff --git a/server/middlewares/integration/verifyAccessTokenAccess.ts b/server/middlewares/integration/verifyAccessTokenAccess.ts
index 82badcd4..e9069ba4 100644
--- a/server/middlewares/integration/verifyAccessTokenAccess.ts
+++ b/server/middlewares/integration/verifyAccessTokenAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { resourceAccessToken, resources, apiKeyOrg } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKey.ts b/server/middlewares/integration/verifyApiKey.ts
index 39fc3de6..0b0602ea 100644
--- a/server/middlewares/integration/verifyApiKey.ts
+++ b/server/middlewares/integration/verifyApiKey.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { verifyPassword } from "@server/auth/password";
import db from "@server/db";
import { apiKeys } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKeyApiKeyAccess.ts b/server/middlewares/integration/verifyApiKeyApiKeyAccess.ts
index aedc60c1..435f01d0 100644
--- a/server/middlewares/integration/verifyApiKeyApiKeyAccess.ts
+++ b/server/middlewares/integration/verifyApiKeyApiKeyAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { apiKeys, apiKeyOrg } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKeyHasAction.ts b/server/middlewares/integration/verifyApiKeyHasAction.ts
index 0326c465..35f4398e 100644
--- a/server/middlewares/integration/verifyApiKeyHasAction.ts
+++ b/server/middlewares/integration/verifyApiKeyHasAction.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
diff --git a/server/middlewares/integration/verifyApiKeyIsRoot.ts b/server/middlewares/integration/verifyApiKeyIsRoot.ts
index 35cd0faf..2ce9c84d 100644
--- a/server/middlewares/integration/verifyApiKeyIsRoot.ts
+++ b/server/middlewares/integration/verifyApiKeyIsRoot.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode";
import { Request, Response, NextFunction } from "express";
diff --git a/server/middlewares/integration/verifyApiKeyOrgAccess.ts b/server/middlewares/integration/verifyApiKeyOrgAccess.ts
index e1e1e0d4..902ccf5e 100644
--- a/server/middlewares/integration/verifyApiKeyOrgAccess.ts
+++ b/server/middlewares/integration/verifyApiKeyOrgAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { apiKeyOrg } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKeyResourceAccess.ts b/server/middlewares/integration/verifyApiKeyResourceAccess.ts
index 49180b59..f4e3ed0f 100644
--- a/server/middlewares/integration/verifyApiKeyResourceAccess.ts
+++ b/server/middlewares/integration/verifyApiKeyResourceAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { resources, apiKeyOrg } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKeyRoleAccess.ts b/server/middlewares/integration/verifyApiKeyRoleAccess.ts
index a7abf9a6..4d769413 100644
--- a/server/middlewares/integration/verifyApiKeyRoleAccess.ts
+++ b/server/middlewares/integration/verifyApiKeyRoleAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { roles, apiKeyOrg } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKeySetResourceUsers.ts b/server/middlewares/integration/verifyApiKeySetResourceUsers.ts
index d43021ba..1c3b5b12 100644
--- a/server/middlewares/integration/verifyApiKeySetResourceUsers.ts
+++ b/server/middlewares/integration/verifyApiKeySetResourceUsers.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { userOrgs } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKeySiteAccess.ts b/server/middlewares/integration/verifyApiKeySiteAccess.ts
index 7d10ddee..2c83eadd 100644
--- a/server/middlewares/integration/verifyApiKeySiteAccess.ts
+++ b/server/middlewares/integration/verifyApiKeySiteAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import {
diff --git a/server/middlewares/integration/verifyApiKeyTargetAccess.ts b/server/middlewares/integration/verifyApiKeyTargetAccess.ts
index bd6e5bc0..7da1f29f 100644
--- a/server/middlewares/integration/verifyApiKeyTargetAccess.ts
+++ b/server/middlewares/integration/verifyApiKeyTargetAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { resources, targets, apiKeyOrg } from "@server/db/schemas";
diff --git a/server/middlewares/integration/verifyApiKeyUserAccess.ts b/server/middlewares/integration/verifyApiKeyUserAccess.ts
index e1b5d3d3..69f27e9a 100644
--- a/server/middlewares/integration/verifyApiKeyUserAccess.ts
+++ b/server/middlewares/integration/verifyApiKeyUserAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { userOrgs } from "@server/db/schemas";
diff --git a/server/middlewares/verifyApiKeyAccess.ts b/server/middlewares/verifyApiKeyAccess.ts
index 0bba8f4b..ad21b37e 100644
--- a/server/middlewares/verifyApiKeyAccess.ts
+++ b/server/middlewares/verifyApiKeyAccess.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { db } from "@server/db";
import { userOrgs, apiKeys, apiKeyOrg } from "@server/db/schemas";
diff --git a/server/middlewares/verifyValidLicense.ts b/server/middlewares/verifyValidLicense.ts
index 7f4de34a..7e3bfee3 100644
--- a/server/middlewares/verifyValidLicense.ts
+++ b/server/middlewares/verifyValidLicense.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
diff --git a/server/routers/apiKeys/createOrgApiKey.ts b/server/routers/apiKeys/createOrgApiKey.ts
index 2fb9fd20..bf8ff8c3 100644
--- a/server/routers/apiKeys/createOrgApiKey.ts
+++ b/server/routers/apiKeys/createOrgApiKey.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { NextFunction, Request, Response } from "express";
import db from "@server/db";
import HttpCode from "@server/types/HttpCode";
diff --git a/server/routers/apiKeys/createRootApiKey.ts b/server/routers/apiKeys/createRootApiKey.ts
index 775ae576..7a5d2d81 100644
--- a/server/routers/apiKeys/createRootApiKey.ts
+++ b/server/routers/apiKeys/createRootApiKey.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { NextFunction, Request, Response } from "express";
import db from "@server/db";
import HttpCode from "@server/types/HttpCode";
diff --git a/server/routers/apiKeys/deleteApiKey.ts b/server/routers/apiKeys/deleteApiKey.ts
index 2af4ae23..e1a74a45 100644
--- a/server/routers/apiKeys/deleteApiKey.ts
+++ b/server/routers/apiKeys/deleteApiKey.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/apiKeys/deleteOrgApiKey.ts b/server/routers/apiKeys/deleteOrgApiKey.ts
index 1834c82c..dbaf47fe 100644
--- a/server/routers/apiKeys/deleteOrgApiKey.ts
+++ b/server/routers/apiKeys/deleteOrgApiKey.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/apiKeys/getApiKey.ts b/server/routers/apiKeys/getApiKey.ts
index bd495bdd..e0354cf1 100644
--- a/server/routers/apiKeys/getApiKey.ts
+++ b/server/routers/apiKeys/getApiKey.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/apiKeys/index.ts b/server/routers/apiKeys/index.ts
index 84d4ee68..62ede75c 100644
--- a/server/routers/apiKeys/index.ts
+++ b/server/routers/apiKeys/index.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
export * from "./createRootApiKey";
export * from "./deleteApiKey";
export * from "./getApiKey";
diff --git a/server/routers/apiKeys/listApiKeyActions.ts b/server/routers/apiKeys/listApiKeyActions.ts
index 0cf694a0..5bd14411 100644
--- a/server/routers/apiKeys/listApiKeyActions.ts
+++ b/server/routers/apiKeys/listApiKeyActions.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { db } from "@server/db";
import { actions, apiKeyActions, apiKeyOrg, apiKeys } from "@server/db/schemas";
import logger from "@server/logger";
diff --git a/server/routers/apiKeys/listOrgApiKeys.ts b/server/routers/apiKeys/listOrgApiKeys.ts
index a0169074..9833ef0f 100644
--- a/server/routers/apiKeys/listOrgApiKeys.ts
+++ b/server/routers/apiKeys/listOrgApiKeys.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { db } from "@server/db";
import { apiKeyOrg, apiKeys } from "@server/db/schemas";
import logger from "@server/logger";
diff --git a/server/routers/apiKeys/listRootApiKeys.ts b/server/routers/apiKeys/listRootApiKeys.ts
index 7feca733..c639ce51 100644
--- a/server/routers/apiKeys/listRootApiKeys.ts
+++ b/server/routers/apiKeys/listRootApiKeys.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { db } from "@server/db";
import { apiKeys } from "@server/db/schemas";
import logger from "@server/logger";
diff --git a/server/routers/apiKeys/setApiKeyActions.ts b/server/routers/apiKeys/setApiKeyActions.ts
index 187dd114..602c7798 100644
--- a/server/routers/apiKeys/setApiKeyActions.ts
+++ b/server/routers/apiKeys/setApiKeyActions.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/apiKeys/setApiKeyOrgs.ts b/server/routers/apiKeys/setApiKeyOrgs.ts
index ee0611d3..c42046de 100644
--- a/server/routers/apiKeys/setApiKeyOrgs.ts
+++ b/server/routers/apiKeys/setApiKeyOrgs.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/external.ts b/server/routers/external.ts
index d631c377..41979651 100644
--- a/server/routers/external.ts
+++ b/server/routers/external.ts
@@ -30,7 +30,6 @@ import {
verifyUserIsServerAdmin,
verifyIsLoggedInUser,
verifyApiKeyAccess,
- verifyValidLicense
} from "@server/middlewares";
import { verifyUserHasAction } from "../middlewares/verifyUserHasAction";
import { ActionsEnum } from "@server/auth/actions";
@@ -531,28 +530,24 @@ authenticated.get("/idp/:idpId", verifyUserIsServerAdmin, idp.getIdp);
authenticated.put(
"/idp/:idpId/org/:orgId",
- verifyValidLicense,
verifyUserIsServerAdmin,
idp.createIdpOrgPolicy
);
authenticated.post(
"/idp/:idpId/org/:orgId",
- verifyValidLicense,
verifyUserIsServerAdmin,
idp.updateIdpOrgPolicy
);
authenticated.delete(
"/idp/:idpId/org/:orgId",
- verifyValidLicense,
verifyUserIsServerAdmin,
idp.deleteIdpOrgPolicy
);
authenticated.get(
"/idp/:idpId/org",
- verifyValidLicense,
verifyUserIsServerAdmin,
idp.listIdpOrgPolicies
);
@@ -586,49 +581,42 @@ authenticated.post(
authenticated.get(
`/api-key/:apiKeyId`,
- verifyValidLicense,
verifyUserIsServerAdmin,
apiKeys.getApiKey
);
authenticated.put(
`/api-key`,
- verifyValidLicense,
verifyUserIsServerAdmin,
apiKeys.createRootApiKey
);
authenticated.delete(
`/api-key/:apiKeyId`,
- verifyValidLicense,
verifyUserIsServerAdmin,
apiKeys.deleteApiKey
);
authenticated.get(
`/api-keys`,
- verifyValidLicense,
verifyUserIsServerAdmin,
apiKeys.listRootApiKeys
);
authenticated.get(
`/api-key/:apiKeyId/actions`,
- verifyValidLicense,
verifyUserIsServerAdmin,
apiKeys.listApiKeyActions
);
authenticated.post(
`/api-key/:apiKeyId/actions`,
- verifyValidLicense,
verifyUserIsServerAdmin,
apiKeys.setApiKeyActions
);
authenticated.get(
`/org/:orgId/api-keys`,
- verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.listApiKeys),
apiKeys.listOrgApiKeys
@@ -636,7 +624,6 @@ authenticated.get(
authenticated.post(
`/org/:orgId/api-key/:apiKeyId/actions`,
- verifyValidLicense,
verifyOrgAccess,
verifyApiKeyAccess,
verifyUserHasAction(ActionsEnum.setApiKeyActions),
@@ -645,7 +632,6 @@ authenticated.post(
authenticated.get(
`/org/:orgId/api-key/:apiKeyId/actions`,
- verifyValidLicense,
verifyOrgAccess,
verifyApiKeyAccess,
verifyUserHasAction(ActionsEnum.listApiKeyActions),
@@ -654,7 +640,6 @@ authenticated.get(
authenticated.put(
`/org/:orgId/api-key`,
- verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createApiKey),
apiKeys.createOrgApiKey
@@ -662,7 +647,6 @@ authenticated.put(
authenticated.delete(
`/org/:orgId/api-key/:apiKeyId`,
- verifyValidLicense,
verifyOrgAccess,
verifyApiKeyAccess,
verifyUserHasAction(ActionsEnum.deleteApiKey),
@@ -671,7 +655,6 @@ authenticated.delete(
authenticated.get(
`/org/:orgId/api-key/:apiKeyId`,
- verifyValidLicense,
verifyOrgAccess,
verifyApiKeyAccess,
verifyUserHasAction(ActionsEnum.getApiKey),
diff --git a/server/routers/idp/createIdpOrgPolicy.ts b/server/routers/idp/createIdpOrgPolicy.ts
index ae5acce4..808c7ca7 100644
--- a/server/routers/idp/createIdpOrgPolicy.ts
+++ b/server/routers/idp/createIdpOrgPolicy.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/idp/createOidcIdp.ts b/server/routers/idp/createOidcIdp.ts
index d663afef..22c569f2 100644
--- a/server/routers/idp/createOidcIdp.ts
+++ b/server/routers/idp/createOidcIdp.ts
@@ -81,10 +81,6 @@ export async function createOidcIdp(
autoProvision
} = parsedBody.data;
- if (!(await license.isUnlocked())) {
- autoProvision = false;
- }
-
const key = config.getRawConfig().server.secret;
const encryptedSecret = encrypt(clientSecret, key);
diff --git a/server/routers/idp/deleteIdpOrgPolicy.ts b/server/routers/idp/deleteIdpOrgPolicy.ts
index 5c41c958..9a6f6e72 100644
--- a/server/routers/idp/deleteIdpOrgPolicy.ts
+++ b/server/routers/idp/deleteIdpOrgPolicy.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/idp/listIdpOrgPolicies.ts b/server/routers/idp/listIdpOrgPolicies.ts
index 9ff9c97a..08ad110c 100644
--- a/server/routers/idp/listIdpOrgPolicies.ts
+++ b/server/routers/idp/listIdpOrgPolicies.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/idp/oidcAutoProvision.ts b/server/routers/idp/oidcAutoProvision.ts
deleted file mode 100644
index 7861fc41..00000000
--- a/server/routers/idp/oidcAutoProvision.ts
+++ /dev/null
@@ -1,233 +0,0 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
-import {
- createSession,
- generateId,
- generateSessionToken,
- serializeSessionCookie
-} from "@server/auth/sessions/app";
-import db from "@server/db";
-import { Idp, idpOrg, orgs, roles, User, userOrgs, users } from "@server/db/schemas";
-import logger from "@server/logger";
-import { UserType } from "@server/types/UserTypes";
-import { eq, and, inArray } from "drizzle-orm";
-import jmespath from "jmespath";
-import { Request, Response } from "express";
-
-export async function oidcAutoProvision({
- idp,
- claims,
- existingUser,
- userIdentifier,
- email,
- name,
- req,
- res
-}: {
- idp: Idp;
- claims: any;
- existingUser?: User;
- userIdentifier: string;
- email?: string;
- name?: string;
- req: Request;
- res: Response;
-}) {
- const allOrgs = await db.select().from(orgs);
-
- const defaultRoleMapping = idp.defaultRoleMapping;
- const defaultOrgMapping = idp.defaultOrgMapping;
-
- let userOrgInfo: { orgId: string; roleId: number }[] = [];
- for (const org of allOrgs) {
- const [idpOrgRes] = await db
- .select()
- .from(idpOrg)
- .where(
- and(eq(idpOrg.idpId, idp.idpId), eq(idpOrg.orgId, org.orgId))
- );
-
- let roleId: number | undefined = undefined;
-
- const orgMapping = idpOrgRes?.orgMapping || defaultOrgMapping;
- const hydratedOrgMapping = hydrateOrgMapping(orgMapping, org.orgId);
-
- if (hydratedOrgMapping) {
- logger.debug("Hydrated Org Mapping", {
- hydratedOrgMapping
- });
- const orgId = jmespath.search(claims, hydratedOrgMapping);
- logger.debug("Extraced Org ID", { orgId });
- if (orgId !== true && orgId !== org.orgId) {
- // user not allowed to access this org
- continue;
- }
- }
-
- const roleMapping = idpOrgRes?.roleMapping || defaultRoleMapping;
- if (roleMapping) {
- logger.debug("Role Mapping", { roleMapping });
- const roleName = jmespath.search(claims, roleMapping);
-
- if (!roleName) {
- logger.error("Role name not found in the ID token", {
- roleName
- });
- continue;
- }
-
- const [roleRes] = await db
- .select()
- .from(roles)
- .where(
- and(eq(roles.orgId, org.orgId), eq(roles.name, roleName))
- );
-
- if (!roleRes) {
- logger.error("Role not found", {
- orgId: org.orgId,
- roleName
- });
- continue;
- }
-
- roleId = roleRes.roleId;
-
- userOrgInfo.push({
- orgId: org.orgId,
- roleId
- });
- }
- }
-
- logger.debug("User org info", { userOrgInfo });
-
- let existingUserId = existingUser?.userId;
-
- // sync the user with the orgs and roles
- await db.transaction(async (trx) => {
- let userId = existingUser?.userId;
-
- // create user if not exists
- if (!existingUser) {
- userId = generateId(15);
-
- await trx.insert(users).values({
- userId,
- username: userIdentifier,
- email: email || null,
- name: name || null,
- type: UserType.OIDC,
- idpId: idp.idpId,
- emailVerified: true, // OIDC users are always verified
- dateCreated: new Date().toISOString()
- });
- } else {
- // set the name and email
- await trx
- .update(users)
- .set({
- username: userIdentifier,
- email: email || null,
- name: name || null
- })
- .where(eq(users.userId, userId!));
- }
-
- existingUserId = userId;
-
- // get all current user orgs
- const currentUserOrgs = await trx
- .select()
- .from(userOrgs)
- .where(eq(userOrgs.userId, userId!));
-
- // Delete orgs that are no longer valid
- const orgsToDelete = currentUserOrgs.filter(
- (currentOrg) =>
- !userOrgInfo.some((newOrg) => newOrg.orgId === currentOrg.orgId)
- );
-
- if (orgsToDelete.length > 0) {
- await trx.delete(userOrgs).where(
- and(
- eq(userOrgs.userId, userId!),
- inArray(
- userOrgs.orgId,
- orgsToDelete.map((org) => org.orgId)
- )
- )
- );
- }
-
- // Update roles for existing orgs where the role has changed
- const orgsToUpdate = currentUserOrgs.filter((currentOrg) => {
- const newOrg = userOrgInfo.find(
- (newOrg) => newOrg.orgId === currentOrg.orgId
- );
- return newOrg && newOrg.roleId !== currentOrg.roleId;
- });
-
- if (orgsToUpdate.length > 0) {
- for (const org of orgsToUpdate) {
- const newRole = userOrgInfo.find(
- (newOrg) => newOrg.orgId === org.orgId
- );
- if (newRole) {
- await trx
- .update(userOrgs)
- .set({ roleId: newRole.roleId })
- .where(
- and(
- eq(userOrgs.userId, userId!),
- eq(userOrgs.orgId, org.orgId)
- )
- );
- }
- }
- }
-
- // Add new orgs that don't exist yet
- const orgsToAdd = userOrgInfo.filter(
- (newOrg) =>
- !currentUserOrgs.some(
- (currentOrg) => currentOrg.orgId === newOrg.orgId
- )
- );
-
- if (orgsToAdd.length > 0) {
- await trx.insert(userOrgs).values(
- orgsToAdd.map((org) => ({
- userId: userId!,
- orgId: org.orgId,
- roleId: org.roleId,
- dateCreated: new Date().toISOString()
- }))
- );
- }
- });
-
- const token = generateSessionToken();
- const sess = await createSession(token, existingUserId!);
- const isSecure = req.protocol === "https";
- const cookie = serializeSessionCookie(
- token,
- isSecure,
- new Date(sess.expiresAt)
- );
-
- res.appendHeader("Set-Cookie", cookie);
-}
-
-function hydrateOrgMapping(
- orgMapping: string | null,
- orgId: string
-): string | undefined {
- if (!orgMapping) {
- return undefined;
- }
- return orgMapping.split("{{orgId}}").join(orgId);
-}
diff --git a/server/routers/idp/updateIdpOrgPolicy.ts b/server/routers/idp/updateIdpOrgPolicy.ts
index 6f8580ac..a5898943 100644
--- a/server/routers/idp/updateIdpOrgPolicy.ts
+++ b/server/routers/idp/updateIdpOrgPolicy.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import { z } from "zod";
import { db } from "@server/db";
diff --git a/server/routers/idp/updateOidcIdp.ts b/server/routers/idp/updateOidcIdp.ts
index d24e319e..11040679 100644
--- a/server/routers/idp/updateOidcIdp.ts
+++ b/server/routers/idp/updateOidcIdp.ts
@@ -100,10 +100,6 @@ export async function updateOidcIdp(
defaultOrgMapping
} = parsedBody.data;
- if (!(await license.isUnlocked())) {
- autoProvision = false;
- }
-
// Check if IDP exists and is of type OIDC
const [existingIdp] = await db
.select()
diff --git a/server/routers/idp/validateOidcCallback.ts b/server/routers/idp/validateOidcCallback.ts
index 4fb52bee..d0c847da 100644
--- a/server/routers/idp/validateOidcCallback.ts
+++ b/server/routers/idp/validateOidcCallback.ts
@@ -6,7 +6,15 @@ import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
import logger from "@server/logger";
import { fromError } from "zod-validation-error";
-import { idp, idpOidcConfig, users } from "@server/db/schemas";
+import {
+ idp,
+ idpOidcConfig,
+ idpOrg,
+ orgs,
+ roles,
+ userOrgs,
+ users
+} from "@server/db/schemas";
import { and, eq, inArray } from "drizzle-orm";
import * as arctic from "arctic";
import { generateOidcRedirectUrl } from "@server/lib/idp/generateRedirectUrl";
@@ -15,12 +23,12 @@ import jsonwebtoken from "jsonwebtoken";
import config from "@server/lib/config";
import {
createSession,
+ generateId,
generateSessionToken,
serializeSessionCookie
} from "@server/auth/sessions/app";
import { decrypt } from "@server/lib/crypto";
-import { oidcAutoProvision } from "./oidcAutoProvision";
-import license from "@server/license/license";
+import { UserType } from "@server/types/UserTypes";
const ensureTrailingSlash = (url: string): string => {
return url;
@@ -212,25 +220,203 @@ export async function validateOidcCallback(
);
if (existingIdp.idp.autoProvision) {
- if (!(await license.isUnlocked())) {
- return next(
- createHttpError(
- HttpCode.FORBIDDEN,
- "Auto-provisioning is not available"
- )
+ const allOrgs = await db.select().from(orgs);
+
+ const defaultRoleMapping = existingIdp.idp.defaultRoleMapping;
+ const defaultOrgMapping = existingIdp.idp.defaultOrgMapping;
+
+ let userOrgInfo: { orgId: string; roleId: number }[] = [];
+ for (const org of allOrgs) {
+ const [idpOrgRes] = await db
+ .select()
+ .from(idpOrg)
+ .where(
+ and(
+ eq(idpOrg.idpId, existingIdp.idp.idpId),
+ eq(idpOrg.orgId, org.orgId)
+ )
+ );
+
+ let roleId: number | undefined = undefined;
+
+ const orgMapping = idpOrgRes?.orgMapping || defaultOrgMapping;
+ const hydratedOrgMapping = hydrateOrgMapping(
+ orgMapping,
+ org.orgId
);
+
+ if (hydratedOrgMapping) {
+ logger.debug("Hydrated Org Mapping", {
+ hydratedOrgMapping
+ });
+ const orgId = jmespath.search(claims, hydratedOrgMapping);
+ logger.debug("Extraced Org ID", { orgId });
+ if (orgId !== true && orgId !== org.orgId) {
+ // user not allowed to access this org
+ continue;
+ }
+ }
+
+ const roleMapping =
+ idpOrgRes?.roleMapping || defaultRoleMapping;
+ if (roleMapping) {
+ logger.debug("Role Mapping", { roleMapping });
+ const roleName = jmespath.search(claims, roleMapping);
+
+ if (!roleName) {
+ logger.error("Role name not found in the ID token", {
+ roleName
+ });
+ continue;
+ }
+
+ const [roleRes] = await db
+ .select()
+ .from(roles)
+ .where(
+ and(
+ eq(roles.orgId, org.orgId),
+ eq(roles.name, roleName)
+ )
+ );
+
+ if (!roleRes) {
+ logger.error("Role not found", {
+ orgId: org.orgId,
+ roleName
+ });
+ continue;
+ }
+
+ roleId = roleRes.roleId;
+
+ userOrgInfo.push({
+ orgId: org.orgId,
+ roleId
+ });
+ }
}
- await oidcAutoProvision({
- idp: existingIdp.idp,
- userIdentifier,
- email,
- name,
- claims,
- existingUser,
- req,
- res
+
+ logger.debug("User org info", { userOrgInfo });
+
+ let existingUserId = existingUser?.userId;
+
+ // sync the user with the orgs and roles
+ await db.transaction(async (trx) => {
+ let userId = existingUser?.userId;
+
+ // create user if not exists
+ if (!existingUser) {
+ userId = generateId(15);
+
+ await trx.insert(users).values({
+ userId,
+ username: userIdentifier,
+ email: email || null,
+ name: name || null,
+ type: UserType.OIDC,
+ idpId: existingIdp.idp.idpId,
+ emailVerified: true, // OIDC users are always verified
+ dateCreated: new Date().toISOString()
+ });
+ } else {
+ // set the name and email
+ await trx
+ .update(users)
+ .set({
+ username: userIdentifier,
+ email: email || null,
+ name: name || null
+ })
+ .where(eq(users.userId, userId!));
+ }
+
+ existingUserId = userId;
+
+ // get all current user orgs
+ const currentUserOrgs = await trx
+ .select()
+ .from(userOrgs)
+ .where(eq(userOrgs.userId, userId!));
+
+ // Delete orgs that are no longer valid
+ const orgsToDelete = currentUserOrgs.filter(
+ (currentOrg) =>
+ !userOrgInfo.some(
+ (newOrg) => newOrg.orgId === currentOrg.orgId
+ )
+ );
+
+ if (orgsToDelete.length > 0) {
+ await trx.delete(userOrgs).where(
+ and(
+ eq(userOrgs.userId, userId!),
+ inArray(
+ userOrgs.orgId,
+ orgsToDelete.map((org) => org.orgId)
+ )
+ )
+ );
+ }
+
+ // Update roles for existing orgs where the role has changed
+ const orgsToUpdate = currentUserOrgs.filter((currentOrg) => {
+ const newOrg = userOrgInfo.find(
+ (newOrg) => newOrg.orgId === currentOrg.orgId
+ );
+ return newOrg && newOrg.roleId !== currentOrg.roleId;
+ });
+
+ if (orgsToUpdate.length > 0) {
+ for (const org of orgsToUpdate) {
+ const newRole = userOrgInfo.find(
+ (newOrg) => newOrg.orgId === org.orgId
+ );
+ if (newRole) {
+ await trx
+ .update(userOrgs)
+ .set({ roleId: newRole.roleId })
+ .where(
+ and(
+ eq(userOrgs.userId, userId!),
+ eq(userOrgs.orgId, org.orgId)
+ )
+ );
+ }
+ }
+ }
+
+ // Add new orgs that don't exist yet
+ const orgsToAdd = userOrgInfo.filter(
+ (newOrg) =>
+ !currentUserOrgs.some(
+ (currentOrg) => currentOrg.orgId === newOrg.orgId
+ )
+ );
+
+ if (orgsToAdd.length > 0) {
+ await trx.insert(userOrgs).values(
+ orgsToAdd.map((org) => ({
+ userId: userId!,
+ orgId: org.orgId,
+ roleId: org.roleId,
+ dateCreated: new Date().toISOString()
+ }))
+ );
+ }
});
+ const token = generateSessionToken();
+ const sess = await createSession(token, existingUserId!);
+ const isSecure = req.protocol === "https";
+ const cookie = serializeSessionCookie(
+ token,
+ isSecure,
+ new Date(sess.expiresAt)
+ );
+
+ res.appendHeader("Set-Cookie", cookie);
+
return response(res, {
data: {
redirectUrl: postAuthRedirectUrl
@@ -278,3 +464,13 @@ export async function validateOidcCallback(
);
}
}
+
+function hydrateOrgMapping(
+ orgMapping: string | null,
+ orgId: string
+): string | undefined {
+ if (!orgMapping) {
+ return undefined;
+ }
+ return orgMapping.split("{{orgId}}").join(orgId);
+}
diff --git a/server/routers/integration.ts b/server/routers/integration.ts
index 40ab9aa9..8fa5c25c 100644
--- a/server/routers/integration.ts
+++ b/server/routers/integration.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import * as site from "./site";
import * as org from "./org";
import * as resource from "./resource";
diff --git a/server/routers/license/activateLicense.ts b/server/routers/license/activateLicense.ts
index da2b76c4..3826277c 100644
--- a/server/routers/license/activateLicense.ts
+++ b/server/routers/license/activateLicense.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
diff --git a/server/routers/license/deleteLicenseKey.ts b/server/routers/license/deleteLicenseKey.ts
index bea7f9ad..6ae5ca24 100644
--- a/server/routers/license/deleteLicenseKey.ts
+++ b/server/routers/license/deleteLicenseKey.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
diff --git a/server/routers/license/getLicenseStatus.ts b/server/routers/license/getLicenseStatus.ts
index a4e4151a..e46b4caa 100644
--- a/server/routers/license/getLicenseStatus.ts
+++ b/server/routers/license/getLicenseStatus.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
diff --git a/server/routers/license/index.ts b/server/routers/license/index.ts
index 6c848c2a..486ca6b2 100644
--- a/server/routers/license/index.ts
+++ b/server/routers/license/index.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
export * from "./getLicenseStatus";
export * from "./activateLicense";
export * from "./listLicenseKeys";
diff --git a/server/routers/license/listLicenseKeys.ts b/server/routers/license/listLicenseKeys.ts
index 12a19564..915690df 100644
--- a/server/routers/license/listLicenseKeys.ts
+++ b/server/routers/license/listLicenseKeys.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
diff --git a/server/routers/license/recheckStatus.ts b/server/routers/license/recheckStatus.ts
index 5f0bd949..d2ab7939 100644
--- a/server/routers/license/recheckStatus.ts
+++ b/server/routers/license/recheckStatus.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { Request, Response, NextFunction } from "express";
import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors";
diff --git a/src/app/[orgId]/settings/access/users/[userId]/access-controls/page.tsx b/src/app/[orgId]/settings/access/users/[userId]/access-controls/page.tsx
index 002febc2..f95fb258 100644
--- a/src/app/[orgId]/settings/access/users/[userId]/access-controls/page.tsx
+++ b/src/app/[orgId]/settings/access/users/[userId]/access-controls/page.tsx
@@ -42,7 +42,7 @@ import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
const formSchema = z.object({
- email: z.string().email({ message: "Please enter a valid email" }),
+ username: z.string(),
roleId: z.string().min(1, { message: "Please select a role" })
});
@@ -59,7 +59,7 @@ export default function AccessControlsPage() {
const form = useForm>({
resolver: zodResolver(formSchema),
defaultValues: {
- email: user.email!,
+ username: user.username!,
roleId: user.roleId?.toString()
}
});
diff --git a/src/app/[orgId]/settings/api-keys/OrgApiKeysDataTable.tsx b/src/app/[orgId]/settings/api-keys/OrgApiKeysDataTable.tsx
index 69fe7176..c10a82dd 100644
--- a/src/app/[orgId]/settings/api-keys/OrgApiKeysDataTable.tsx
+++ b/src/app/[orgId]/settings/api-keys/OrgApiKeysDataTable.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { DataTable } from "@app/components/ui/data-table";
diff --git a/src/app/[orgId]/settings/api-keys/OrgApiKeysTable.tsx b/src/app/[orgId]/settings/api-keys/OrgApiKeysTable.tsx
index 89e47842..893f6d7e 100644
--- a/src/app/[orgId]/settings/api-keys/OrgApiKeysTable.tsx
+++ b/src/app/[orgId]/settings/api-keys/OrgApiKeysTable.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { ColumnDef } from "@tanstack/react-table";
diff --git a/src/app/[orgId]/settings/api-keys/[apiKeyId]/layout.tsx b/src/app/[orgId]/settings/api-keys/[apiKeyId]/layout.tsx
index a4c13c9a..4a7b319d 100644
--- a/src/app/[orgId]/settings/api-keys/[apiKeyId]/layout.tsx
+++ b/src/app/[orgId]/settings/api-keys/[apiKeyId]/layout.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { internal } from "@app/lib/api";
import { AxiosResponse } from "axios";
import { redirect } from "next/navigation";
diff --git a/src/app/[orgId]/settings/api-keys/[apiKeyId]/page.tsx b/src/app/[orgId]/settings/api-keys/[apiKeyId]/page.tsx
index 7df37cd6..e54f442d 100644
--- a/src/app/[orgId]/settings/api-keys/[apiKeyId]/page.tsx
+++ b/src/app/[orgId]/settings/api-keys/[apiKeyId]/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { redirect } from "next/navigation";
export default async function ApiKeysPage(props: {
diff --git a/src/app/[orgId]/settings/api-keys/[apiKeyId]/permissions/page.tsx b/src/app/[orgId]/settings/api-keys/[apiKeyId]/permissions/page.tsx
index d1e6f518..624d13a7 100644
--- a/src/app/[orgId]/settings/api-keys/[apiKeyId]/permissions/page.tsx
+++ b/src/app/[orgId]/settings/api-keys/[apiKeyId]/permissions/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import PermissionsSelectBox from "@app/components/PermissionsSelectBox";
diff --git a/src/app/[orgId]/settings/api-keys/create/page.tsx b/src/app/[orgId]/settings/api-keys/create/page.tsx
index 3ede2ac0..d3e7e346 100644
--- a/src/app/[orgId]/settings/api-keys/create/page.tsx
+++ b/src/app/[orgId]/settings/api-keys/create/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import {
diff --git a/src/app/[orgId]/settings/api-keys/page.tsx b/src/app/[orgId]/settings/api-keys/page.tsx
index ef1e3dd1..c6e48d20 100644
--- a/src/app/[orgId]/settings/api-keys/page.tsx
+++ b/src/app/[orgId]/settings/api-keys/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import { AxiosResponse } from "axios";
diff --git a/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx b/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx
index a9db3e79..ce6133d5 100644
--- a/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx
+++ b/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx
@@ -1,8 +1,6 @@
"use client";
-import {
- ColumnDef,
-} from "@tanstack/react-table";
+import { ColumnDef } from "@tanstack/react-table";
import { DataTable } from "@app/components/ui/data-table";
interface DataTableProps {
@@ -25,6 +23,10 @@ export function ResourcesDataTable({
searchColumn="name"
onAdd={createResource}
addButtonText="Add Resource"
+ defaultSort={{
+ id: "name",
+ desc: false
+ }}
/>
);
}
diff --git a/src/app/[orgId]/settings/sites/SitesDataTable.tsx b/src/app/[orgId]/settings/sites/SitesDataTable.tsx
index 08d97955..76beca6d 100644
--- a/src/app/[orgId]/settings/sites/SitesDataTable.tsx
+++ b/src/app/[orgId]/settings/sites/SitesDataTable.tsx
@@ -1,8 +1,6 @@
"use client";
-import {
- ColumnDef,
-} from "@tanstack/react-table";
+import { ColumnDef } from "@tanstack/react-table";
import { DataTable } from "@app/components/ui/data-table";
interface DataTableProps {
@@ -25,6 +23,10 @@ export function SitesDataTable({
searchColumn="name"
onAdd={createSite}
addButtonText="Add Site"
+ defaultSort={{
+ id: "name",
+ desc: false
+ }}
/>
);
}
diff --git a/src/app/admin/api-keys/ApiKeysDataTable.tsx b/src/app/admin/api-keys/ApiKeysDataTable.tsx
index f65949a4..b7e2ed00 100644
--- a/src/app/admin/api-keys/ApiKeysDataTable.tsx
+++ b/src/app/admin/api-keys/ApiKeysDataTable.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import {
diff --git a/src/app/admin/api-keys/ApiKeysTable.tsx b/src/app/admin/api-keys/ApiKeysTable.tsx
index c44d43f3..a89157b8 100644
--- a/src/app/admin/api-keys/ApiKeysTable.tsx
+++ b/src/app/admin/api-keys/ApiKeysTable.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { ColumnDef } from "@tanstack/react-table";
diff --git a/src/app/admin/api-keys/[apiKeyId]/layout.tsx b/src/app/admin/api-keys/[apiKeyId]/layout.tsx
index be3147ea..768ad30a 100644
--- a/src/app/admin/api-keys/[apiKeyId]/layout.tsx
+++ b/src/app/admin/api-keys/[apiKeyId]/layout.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { internal } from "@app/lib/api";
import { AxiosResponse } from "axios";
import { redirect } from "next/navigation";
diff --git a/src/app/admin/api-keys/[apiKeyId]/page.tsx b/src/app/admin/api-keys/[apiKeyId]/page.tsx
index b0e4c3e5..910d1b53 100644
--- a/src/app/admin/api-keys/[apiKeyId]/page.tsx
+++ b/src/app/admin/api-keys/[apiKeyId]/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { redirect } from "next/navigation";
export default async function ApiKeysPage(props: {
diff --git a/src/app/admin/api-keys/[apiKeyId]/permissions/page.tsx b/src/app/admin/api-keys/[apiKeyId]/permissions/page.tsx
index c468c139..70c2c55e 100644
--- a/src/app/admin/api-keys/[apiKeyId]/permissions/page.tsx
+++ b/src/app/admin/api-keys/[apiKeyId]/permissions/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import PermissionsSelectBox from "@app/components/PermissionsSelectBox";
diff --git a/src/app/admin/api-keys/create/page.tsx b/src/app/admin/api-keys/create/page.tsx
index c76b1859..c762fed8 100644
--- a/src/app/admin/api-keys/create/page.tsx
+++ b/src/app/admin/api-keys/create/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import {
diff --git a/src/app/admin/api-keys/page.tsx b/src/app/admin/api-keys/page.tsx
index b4a00806..077c9be1 100644
--- a/src/app/admin/api-keys/page.tsx
+++ b/src/app/admin/api-keys/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import { AxiosResponse } from "axios";
diff --git a/src/app/admin/idp/[idpId]/general/page.tsx b/src/app/admin/idp/[idpId]/general/page.tsx
index f7844c7c..857c7e48 100644
--- a/src/app/admin/idp/[idpId]/general/page.tsx
+++ b/src/app/admin/idp/[idpId]/general/page.tsx
@@ -232,7 +232,6 @@ export default function GeneralPage() {
defaultChecked={form.getValues(
"autoProvision"
)}
- disabled={!isUnlocked()}
onCheckedChange={(checked) => {
form.setValue(
"autoProvision",
@@ -240,14 +239,6 @@ export default function GeneralPage() {
);
}}
/>
- {!isUnlocked() && (
-
- Professional
-
- )}
When enabled, users will be
diff --git a/src/app/admin/idp/[idpId]/layout.tsx b/src/app/admin/idp/[idpId]/layout.tsx
index d244e13d..9913c8d6 100644
--- a/src/app/admin/idp/[idpId]/layout.tsx
+++ b/src/app/admin/idp/[idpId]/layout.tsx
@@ -43,8 +43,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
},
{
title: "Organization Policies",
- href: `/admin/idp/${params.idpId}/policies`,
- showProfessional: true
+ href: `/admin/idp/${params.idpId}/policies`
}
];
diff --git a/src/app/admin/idp/[idpId]/policies/PolicyDataTable.tsx b/src/app/admin/idp/[idpId]/policies/PolicyDataTable.tsx
index 222e98eb..2873b80a 100644
--- a/src/app/admin/idp/[idpId]/policies/PolicyDataTable.tsx
+++ b/src/app/admin/idp/[idpId]/policies/PolicyDataTable.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { ColumnDef } from "@tanstack/react-table";
diff --git a/src/app/admin/idp/[idpId]/policies/PolicyTable.tsx b/src/app/admin/idp/[idpId]/policies/PolicyTable.tsx
index df78c648..09ba309f 100644
--- a/src/app/admin/idp/[idpId]/policies/PolicyTable.tsx
+++ b/src/app/admin/idp/[idpId]/policies/PolicyTable.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { ColumnDef } from "@tanstack/react-table";
diff --git a/src/app/admin/idp/[idpId]/policies/page.tsx b/src/app/admin/idp/[idpId]/policies/page.tsx
index 9fb9b49b..ba108064 100644
--- a/src/app/admin/idp/[idpId]/policies/page.tsx
+++ b/src/app/admin/idp/[idpId]/policies/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { useEffect, useState } from "react";
@@ -377,9 +372,7 @@ export default function PoliciesPage() {
- JMESPath to extract role
- information from the ID
- token. The result of this
+ The result of this
expression must return the
role name as defined in the
organization as a string.
@@ -401,13 +394,10 @@ export default function PoliciesPage() {
- JMESPath to extract
- organization information
- from the ID token. This
- expression must return thr
- org ID or true for the user
- to be allowed to access the
- organization.
+ This expression must return
+ thr org ID or true for the
+ user to be allowed to access
+ the organization.
@@ -578,8 +568,6 @@ export default function PoliciesPage() {
- JMESPath to extract role
- information from the ID token.
The result of this expression
must return the role name as
defined in the organization as a
@@ -603,8 +591,6 @@ export default function PoliciesPage() {
- JMESPath to extract organization
- information from the ID token.
This expression must return the
org ID or true for the user to
be allowed to access the
diff --git a/src/app/admin/idp/create/page.tsx b/src/app/admin/idp/create/page.tsx
index 034cc69a..85ec0f74 100644
--- a/src/app/admin/idp/create/page.tsx
+++ b/src/app/admin/idp/create/page.tsx
@@ -192,7 +192,6 @@ export default function Page() {
defaultChecked={form.getValues(
"autoProvision"
)}
- disabled={!isUnlocked()}
onCheckedChange={(checked) => {
form.setValue(
"autoProvision",
@@ -200,14 +199,6 @@ export default function Page() {
);
}}
/>
- {!isUnlocked() && (
-
- Professional
-
- )}
When enabled, users will be
@@ -421,7 +412,7 @@ export default function Page() {
- The JMESPath to the user
+ The path to the user
identifier in the ID
token
@@ -442,7 +433,7 @@ export default function Page() {
- The JMESPath to the
+ The path to the
user's email in the ID
token
@@ -463,7 +454,7 @@ export default function Page() {
- The JMESPath to the
+ The path to the
user's name in the ID
token
diff --git a/src/app/admin/license/LicenseKeysDataTable.tsx b/src/app/admin/license/LicenseKeysDataTable.tsx
index 98ed814a..d07164f5 100644
--- a/src/app/admin/license/LicenseKeysDataTable.tsx
+++ b/src/app/admin/license/LicenseKeysDataTable.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { ColumnDef } from "@tanstack/react-table";
diff --git a/src/app/admin/license/components/SitePriceCalculator.tsx b/src/app/admin/license/components/SitePriceCalculator.tsx
index cf771b51..7f28b2c5 100644
--- a/src/app/admin/license/components/SitePriceCalculator.tsx
+++ b/src/app/admin/license/components/SitePriceCalculator.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { useState } from "react";
import { Button } from "@app/components/ui/button";
import { MinusCircle, PlusCircle } from "lucide-react";
@@ -107,35 +102,6 @@ export function SitePriceCalculator({
- {mode === "license" && (
-
-
- License fee:
-
-
- ${licenseFlatRate.toFixed(2)}
-
-
- )}
-
-
- Price per site:
-
-
- ${pricePerSite.toFixed(2)}
-
-
-
-
- Number of sites:
-
- {siteCount}
-
-
- Total:
- ${totalCost.toFixed(2)} / mo
-
-
For the most up-to-date pricing and discounts,
please visit the{" "}
@@ -157,7 +123,7 @@ export function SitePriceCalculator({
Cancel
- Continue to Payment
+ See Purchase Portal
diff --git a/src/app/admin/license/page.tsx b/src/app/admin/license/page.tsx
index a9678898..b86c18b3 100644
--- a/src/app/admin/license/page.tsx
+++ b/src/app/admin/license/page.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { useState, useEffect } from "react";
@@ -49,7 +44,7 @@ import {
} from "@app/components/Settings";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import { Badge } from "@app/components/ui/badge";
-import { Check, ShieldCheck, ShieldOff } from "lucide-react";
+import { Check, Heart, InfoIcon, ShieldCheck, ShieldOff } from "lucide-react";
import CopyTextBox from "@app/components/CopyTextBox";
import { Progress } from "@app/components/ui/progress";
import { MinusCircle, PlusCircle } from "lucide-react";
@@ -57,6 +52,8 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
import { SitePriceCalculator } from "./components/SitePriceCalculator";
import Link from "next/link";
import { Checkbox } from "@app/components/ui/checkbox";
+import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
+import { useSupporterStatusContext } from "@app/hooks/useSupporterStatusContext";
const formSchema = z.object({
licenseKey: z
@@ -95,6 +92,7 @@ export default function LicensePage() {
const [isActivatingLicense, setIsActivatingLicense] = useState(false);
const [isDeletingLicense, setIsDeletingLicense] = useState(false);
const [isRecheckingLicense, setIsRecheckingLicense] = useState(false);
+ const { supporterStatus } = useSupporterStatusContext();
const form = useForm>({
resolver: zodResolver(formSchema),
@@ -370,6 +368,18 @@ export default function LicensePage() {
description="View and manage license keys in the system"
/>
+
+
+
+ About Licensing
+
+
+ This is for business and enterprise users who are using
+ Pangolin in a commercial environment. If you are using
+ Pangolin for personal use, you can ignore this section.
+
+
+
@@ -387,18 +397,25 @@ export default function LicensePage() {
{licenseStatus?.tier ===
"PROFESSIONAL"
- ? "Professional License"
+ ? "Commercial License"
: licenseStatus?.tier ===
"ENTERPRISE"
- ? "Enterprise License"
+ ? "Commercial License"
: "Licensed"}
) : (
-
- Not Licensed
-
+ {supporterStatus?.visible ? (
+
+ Community Edition
+
+ ) : (
+
+
+ Community Edition
+
+ )}
)}
diff --git a/src/app/auth/layout.tsx b/src/app/auth/layout.tsx
index 7edc12d8..79f3294a 100644
--- a/src/app/auth/layout.tsx
+++ b/src/app/auth/layout.tsx
@@ -1,6 +1,11 @@
import ProfileIcon from "@app/components/ProfileIcon";
+import { Separator } from "@app/components/ui/separator";
+import { priv } from "@app/lib/api";
import { verifySession } from "@app/lib/auth/verifySession";
import UserProvider from "@app/providers/UserProvider";
+import { GetLicenseStatusResponse } from "@server/routers/license";
+import { AxiosResponse } from "axios";
+import { ExternalLink } from "lucide-react";
import { Metadata } from "next";
import { cache } from "react";
@@ -17,6 +22,14 @@ export default async function AuthLayout({ children }: AuthLayoutProps) {
const getUser = cache(verifySession);
const user = await getUser();
+ const licenseStatusRes = await cache(
+ async () =>
+ await priv.get>(
+ "/license/status"
+ )
+ )();
+ const licenseStatus = licenseStatusRes.data.data;
+
return (
{user && (
@@ -28,10 +41,49 @@ export default async function AuthLayout({ children }: AuthLayoutProps) {
)}
-
- {children}
-
+
{children}
+
+ {!(
+ licenseStatus.isHostLicensed && licenseStatus.isLicenseValid
+ ) && (
+
+ )}
);
}
diff --git a/src/app/components/LicenseViolation.tsx b/src/app/components/LicenseViolation.tsx
index 75d544d3..4dd6cbf6 100644
--- a/src/app/components/LicenseViolation.tsx
+++ b/src/app/components/LicenseViolation.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { Button } from "@app/components/ui/button";
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index e0089bc5..22b478be 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -12,6 +12,7 @@ import { IsSupporterKeyVisibleResponse } from "@server/routers/supporterKey";
import LicenseStatusProvider from "@app/providers/LicenseStatusProvider";
import { GetLicenseStatusResponse } from "@server/routers/license";
import LicenseViolation from "./components/LicenseViolation";
+import { cache } from "react";
export const metadata: Metadata = {
title: `Dashboard - Pangolin`,
@@ -40,10 +41,12 @@ export default async function RootLayout({
supporterData.visible = res.data.data.visible;
supporterData.tier = res.data.data.tier;
- const licenseStatusRes =
- await priv.get>(
- "/license/status"
- );
+ const licenseStatusRes = await cache(
+ async () =>
+ await priv.get>(
+ "/license/status"
+ )
+ )();
const licenseStatus = licenseStatusRes.data.data;
return (
diff --git a/src/app/navigation.tsx b/src/app/navigation.tsx
index b05bf30b..8ea3c080 100644
--- a/src/app/navigation.tsx
+++ b/src/app/navigation.tsx
@@ -68,8 +68,7 @@ export const orgNavItems: SidebarNavItem[] = [
{
title: "API Keys",
href: "/{orgId}/settings/api-keys",
- icon: ,
- showProfessional: true
+ icon:
},
{
title: "Settings",
@@ -87,8 +86,7 @@ export const adminNavItems: SidebarNavItem[] = [
{
title: "API Keys",
href: "/admin/api-keys",
- icon: ,
- showProfessional: true
+ icon:
},
{
title: "Identity Providers",
diff --git a/src/components/AuthFooter.tsx b/src/components/AuthFooter.tsx
new file mode 100644
index 00000000..a1c0795e
--- /dev/null
+++ b/src/components/AuthFooter.tsx
@@ -0,0 +1,3 @@
+"use client";
+
+export function AuthFooter() {}
diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx
index 12cb09d6..e0925525 100644
--- a/src/components/Layout.tsx
+++ b/src/components/Layout.tsx
@@ -22,6 +22,7 @@ import { Breadcrumbs } from "@app/components/Breadcrumbs";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useUserContext } from "@app/hooks/useUserContext";
+import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext";
interface LayoutProps {
children: React.ReactNode;
@@ -58,6 +59,7 @@ export function Layout({
const pathname = usePathname();
const isAdminPage = pathname?.startsWith("/admin");
const { user } = useUserContext();
+ const { isUnlocked } = useLicenseStatusContext();
return (
@@ -207,7 +209,9 @@ export function Layout({
rel="noopener noreferrer"
className="flex items-center justify-center gap-1"
>
- Open Source
+ {!isUnlocked()
+ ? "Community Edition"
+ : "Commercial Edition"}
diff --git a/src/components/PermissionsSelectBox.tsx b/src/components/PermissionsSelectBox.tsx
index a6f9addd..c0b9a4e4 100644
--- a/src/components/PermissionsSelectBox.tsx
+++ b/src/components/PermissionsSelectBox.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { CheckboxWithLabel } from "@app/components/ui/checkbox";
@@ -26,7 +21,6 @@ function getActionsCategories(root: boolean) {
"Update Organization": "updateOrg",
"Get Organization User": "getOrgUser",
"List Organization Domains": "listOrgDomains",
- "Check Org ID": "checkOrgId",
},
Site: {
diff --git a/src/components/ProfessionalContentOverlay.tsx b/src/components/ProfessionalContentOverlay.tsx
index cd484a2b..d35b09ba 100644
--- a/src/components/ProfessionalContentOverlay.tsx
+++ b/src/components/ProfessionalContentOverlay.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import { cn } from "@app/lib/cn";
diff --git a/src/components/SupporterStatus.tsx b/src/components/SupporterStatus.tsx
index 48abf7b3..bd092007 100644
--- a/src/components/SupporterStatus.tsx
+++ b/src/components/SupporterStatus.tsx
@@ -193,7 +193,7 @@ export default function SupporterStatus() {
contribution allows us to commit more time to
maintain and add new features to the application for
everyone. We will never use this to paywall
- features. This is separate from the Professional
+ features. This is separate from any Commercial
Edition.
diff --git a/src/components/ui/data-table.tsx b/src/components/ui/data-table.tsx
index b544b751..c9556052 100644
--- a/src/components/ui/data-table.tsx
+++ b/src/components/ui/data-table.tsx
@@ -31,7 +31,7 @@ import {
CardTitle
} from "@app/components/ui/card";
-interface DataTableProps {
+type DataTableProps = {
columns: ColumnDef[];
data: TData[];
title?: string;
@@ -39,7 +39,11 @@ interface DataTableProps {
onAdd?: () => void;
searchPlaceholder?: string;
searchColumn?: string;
-}
+ defaultSort?: {
+ id: string;
+ desc: boolean;
+ };
+};
export function DataTable({
columns,
@@ -48,9 +52,12 @@ export function DataTable({
addButtonText,
onAdd,
searchPlaceholder = "Search...",
- searchColumn = "name"
+ searchColumn = "name",
+ defaultSort
}: DataTableProps) {
- const [sorting, setSorting] = useState([]);
+ const [sorting, setSorting] = useState(
+ defaultSort ? [defaultSort] : []
+ );
const [columnFilters, setColumnFilters] = useState([]);
const [globalFilter, setGlobalFilter] = useState([]);
diff --git a/src/contexts/apiKeyContext.ts b/src/contexts/apiKeyContext.ts
index dd6c9b83..58b091fd 100644
--- a/src/contexts/apiKeyContext.ts
+++ b/src/contexts/apiKeyContext.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { GetApiKeyResponse } from "@server/routers/apiKeys";
import { createContext } from "react";
diff --git a/src/contexts/licenseStatusContext.ts b/src/contexts/licenseStatusContext.ts
index eca63573..ad58959b 100644
--- a/src/contexts/licenseStatusContext.ts
+++ b/src/contexts/licenseStatusContext.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import { LicenseStatus } from "@server/license/license";
import { createContext } from "react";
diff --git a/src/hooks/useApikeyContext.ts b/src/hooks/useApikeyContext.ts
index 3ebcbddc..6c9a8297 100644
--- a/src/hooks/useApikeyContext.ts
+++ b/src/hooks/useApikeyContext.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import ApiKeyContext from "@app/contexts/apiKeyContext";
import { useContext } from "react";
diff --git a/src/hooks/useLicenseStatusContext.ts b/src/hooks/useLicenseStatusContext.ts
index b1da3434..bc4a776d 100644
--- a/src/hooks/useLicenseStatusContext.ts
+++ b/src/hooks/useLicenseStatusContext.ts
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
import LicenseStatusContext from "@app/contexts/licenseStatusContext";
import { useContext } from "react";
diff --git a/src/providers/ApiKeyProvider.tsx b/src/providers/ApiKeyProvider.tsx
index 13061da3..43a2a9b6 100644
--- a/src/providers/ApiKeyProvider.tsx
+++ b/src/providers/ApiKeyProvider.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import ApiKeyContext from "@app/contexts/apiKeyContext";
diff --git a/src/providers/LicenseStatusProvider.tsx b/src/providers/LicenseStatusProvider.tsx
index c3fe9684..1f8d99c8 100644
--- a/src/providers/LicenseStatusProvider.tsx
+++ b/src/providers/LicenseStatusProvider.tsx
@@ -1,8 +1,3 @@
-// This file is licensed under the Fossorial Commercial License.
-// Unauthorized use, copying, modification, or distribution is strictly prohibited.
-//
-// Copyright (c) 2025 Fossorial LLC. All rights reserved.
-
"use client";
import LicenseStatusContext from "@app/contexts/licenseStatusContext";