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/newt b/newt
new file mode 100755
index 00000000..3805c736
Binary files /dev/null and b/newt differ
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 935522ed..fe51af39 100644
--- a/server/lib/config.ts
+++ b/server/lib/config.ts
@@ -216,7 +216,8 @@ const configSchema = z.object({
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()
+ allow_local_sites: z.boolean().optional(),
+ enable_integration_api: z.boolean().optional()
})
.optional()
});
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
For the most up-to-date pricing and discounts,
please visit the{" "}
@@ -157,7 +123,7 @@ export function SitePriceCalculator({
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