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(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({ 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";