From ab4c105e757201136af0462dfe5738c505cc0293 Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 19 Oct 2026 16:55:10 -0400 Subject: [PATCH] Make rekey not private and in integration api --- messages/en-US.json | 1 + server/lib/backupFileName.ts | 11 ---- server/openApi.ts | 3 +- server/private/routers/external.ts | 31 --------- server/private/routers/re-key/index.ts | 16 ----- .../resource/createResourceMtlsCertificate.ts | 13 ++++ .../resource/deleteResourceMtlsCertificate.ts | 13 ++++ .../resource/listResourceMtlsCertificates.ts | 13 ++++ server/routers/external.ts | 25 +++++++ server/routers/integration.ts | 28 ++++++++ server/routers/re-key/index.ts | 3 + .../routers/re-key/reGenerateClientSecret.ts | 49 ++++++++++---- .../re-key/reGenerateExitNodeSecret.ts | 66 ++++++++++++++----- .../routers/re-key/reGenerateSiteSecret.ts | 49 ++++++++++---- .../[remoteExitNodeId]/credentials/page.tsx | 15 ----- .../machine/[niceId]/credentials/page.tsx | 15 ----- .../sites/[niceId]/credentials/page.tsx | 32 +-------- src/components/PermissionsSelectBox.tsx | 3 +- 18 files changed, 221 insertions(+), 165 deletions(-) delete mode 100644 server/private/routers/re-key/index.ts create mode 100644 server/routers/re-key/index.ts rename server/{private => }/routers/re-key/reGenerateClientSecret.ts (80%) rename server/{private => }/routers/re-key/reGenerateExitNodeSecret.ts (68%) rename server/{private => }/routers/re-key/reGenerateSiteSecret.ts (86%) diff --git a/messages/en-US.json b/messages/en-US.json index 760a42a24..a6aa0060f 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1504,6 +1504,7 @@ "actionDeleteSite": "Delete Site", "actionGetSite": "Get Site", "actionListSites": "List Sites", + "actionReGenerateSecret": "Regenerate Credentials", "actionCreateAiProvider": "Create AI Provider", "actionDeleteAiProvider": "Delete AI Provider", "actionGetAiProvider": "Get AI Provider", diff --git a/server/lib/backupFileName.ts b/server/lib/backupFileName.ts index 9d2c1bd62..69b08dc8b 100644 --- a/server/lib/backupFileName.ts +++ b/server/lib/backupFileName.ts @@ -1,14 +1,3 @@ -/** - * Builds the timestamp segment of a database backup file name. - * - * `Date#getMonth` is zero-indexed, so building this inline produced names like - * `db_2026-8-12_...` for a backup taken on 12 September 2026. Every field is - * also zero-padded, which keeps the names unambiguous and makes them sort - * lexicographically in the order they were taken. - * - * @param date The moment the backup is being taken. Defaults to now. - * @returns A timestamp of the form `YYYY-MM-DD_HH-MM-SS`. - */ export function formatBackupTimestamp(date: Date = new Date()): string { const pad = (value: number): string => String(value).padStart(2, "0"); diff --git a/server/openApi.ts b/server/openApi.ts index 94e2079d0..3c77ed979 100644 --- a/server/openApi.ts +++ b/server/openApi.ts @@ -34,7 +34,8 @@ export enum OpenAPITags { AiBudget = "AI Budget", VirtualApiKey = "Virtual API Key", Redirect = "Redirect", - Label = "Label" + Label = "Label", + RemoteExitNode = "Remote Exit Node" } // Order here controls the order tags are displayed in Swagger UI diff --git a/server/private/routers/external.ts b/server/private/routers/external.ts index 720183a36..6dcf0e3be 100644 --- a/server/private/routers/external.ts +++ b/server/private/routers/external.ts @@ -26,7 +26,6 @@ import { exportAiSessionLogs } from "@server/routers/auditLogs"; import * as misc from "#private/routers/misc"; -import * as reKey from "#private/routers/re-key"; import * as approval from "#private/routers/approvals"; import * as user from "#private/routers/user"; import * as client from "#private/routers/client"; @@ -617,36 +616,6 @@ authenticated.get( exportAiSessionLogs ); -authenticated.post( - "/re-key/:clientId/regenerate-client-secret", - verifyClientAccess, // this is first to set the org id - verifyValidLicense, - verifyValidSubscription(tierMatrix.rotateCredentials), - verifyLimits, - verifyUserHasAction(ActionsEnum.reGenerateSecret), - reKey.reGenerateClientSecret -); - -authenticated.post( - "/re-key/:siteId/regenerate-site-secret", - verifySiteAccess, // this is first to set the org id - verifyValidLicense, - verifyValidSubscription(tierMatrix.rotateCredentials), - verifyLimits, - verifyUserHasAction(ActionsEnum.reGenerateSecret), - reKey.reGenerateSiteSecret -); - -authenticated.put( - "/re-key/:orgId/regenerate-remote-exit-node-secret", - verifyValidLicense, - verifyValidSubscription(tierMatrix.rotateCredentials), - verifyOrgAccess, - verifyLimits, - verifyUserHasAction(ActionsEnum.reGenerateSecret), - reKey.reGenerateExitNodeSecret -); - authenticated.post( "/user/:userId/add-role/:roleId", verifyRoleAccess, diff --git a/server/private/routers/re-key/index.ts b/server/private/routers/re-key/index.ts deleted file mode 100644 index 922a021fd..000000000 --- a/server/private/routers/re-key/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - -export * from "./reGenerateClientSecret"; -export * from "./reGenerateSiteSecret"; -export * from "./reGenerateExitNodeSecret"; diff --git a/server/private/routers/resource/createResourceMtlsCertificate.ts b/server/private/routers/resource/createResourceMtlsCertificate.ts index 5ad04b55d..d42293441 100644 --- a/server/private/routers/resource/createResourceMtlsCertificate.ts +++ b/server/private/routers/resource/createResourceMtlsCertificate.ts @@ -1,3 +1,16 @@ +/* + * This file is part of a proprietary work. + * + * Copyright (c) 2025-2026 Fossorial, Inc. + * All rights reserved. + * + * This file is licensed under the Fossorial Commercial License. + * You may not use this file except in compliance with the License. + * Unauthorized use, copying, modification, or distribution is strictly prohibited. + * + * This file is not licensed under the AGPLv3. + */ + import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db, resourceMtlsCertificates, resources } from "@server/db"; diff --git a/server/private/routers/resource/deleteResourceMtlsCertificate.ts b/server/private/routers/resource/deleteResourceMtlsCertificate.ts index f9ee3c2f6..c74f0eb1f 100644 --- a/server/private/routers/resource/deleteResourceMtlsCertificate.ts +++ b/server/private/routers/resource/deleteResourceMtlsCertificate.ts @@ -1,3 +1,16 @@ +/* + * This file is part of a proprietary work. + * + * Copyright (c) 2025-2026 Fossorial, Inc. + * All rights reserved. + * + * This file is licensed under the Fossorial Commercial License. + * You may not use this file except in compliance with the License. + * Unauthorized use, copying, modification, or distribution is strictly prohibited. + * + * This file is not licensed under the AGPLv3. + */ + import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db, resourceMtlsCertificates, resources } from "@server/db"; diff --git a/server/private/routers/resource/listResourceMtlsCertificates.ts b/server/private/routers/resource/listResourceMtlsCertificates.ts index 142d225b7..aa6ab8b24 100644 --- a/server/private/routers/resource/listResourceMtlsCertificates.ts +++ b/server/private/routers/resource/listResourceMtlsCertificates.ts @@ -1,3 +1,16 @@ +/* + * This file is part of a proprietary work. + * + * Copyright (c) 2025-2026 Fossorial, Inc. + * All rights reserved. + * + * This file is licensed under the Fossorial Commercial License. + * You may not use this file except in compliance with the License. + * Unauthorized use, copying, modification, or distribution is strictly prohibited. + * + * This file is not licensed under the AGPLv3. + */ + import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db, resourceMtlsCertificates, resources } from "@server/db"; diff --git a/server/routers/external.ts b/server/routers/external.ts index d5faba7cd..71691a336 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -22,6 +22,7 @@ import * as newt from "./newt"; import * as olm from "./olm"; import * as ssh from "./ssh"; import * as serverInfo from "./serverInfo"; +import * as reKey from "./re-key"; import HttpCode from "@server/types/HttpCode"; import { verifyAccessTokenAccess, @@ -1972,6 +1973,30 @@ authenticated.post( certificates.restartCertificate ); +authenticated.post( + "/re-key/:clientId/regenerate-client-secret", + verifyClientAccess, // this is first to set the org id + verifyLimits, + verifyUserHasAction(ActionsEnum.reGenerateSecret), + reKey.reGenerateClientSecret +); + +authenticated.post( + "/re-key/:siteId/regenerate-site-secret", + verifySiteAccess, // this is first to set the org id + verifyLimits, + verifyUserHasAction(ActionsEnum.reGenerateSecret), + reKey.reGenerateSiteSecret +); + +authenticated.put( + "/re-key/:orgId/regenerate-remote-exit-node-secret", + verifyOrgAccess, + verifyLimits, + verifyUserHasAction(ActionsEnum.reGenerateSecret), + reKey.reGenerateExitNodeSecret +); + // Auth routes export const authRouter = Router(); unauthenticated.use("/auth", authRouter); diff --git a/server/routers/integration.ts b/server/routers/integration.ts index 20b6d9c78..dac082434 100644 --- a/server/routers/integration.ts +++ b/server/routers/integration.ts @@ -18,6 +18,7 @@ import * as aiBudget from "./aiBudget"; import * as virtualApiKey from "./virtualApiKey"; import * as redirect from "./redirect"; import * as labels from "./labels"; +import * as reKey from "./re-key"; import { verifyApiKey, verifyApiKeyOrgAccess, @@ -149,6 +150,24 @@ authenticated.post( site.updateSite ); +authenticated.post( + "/re-key/:siteId/regenerate-site-secret", + verifyApiKeySiteAccess, + verifyLimits, + verifyApiKeyHasAction(ActionsEnum.reGenerateSecret), + logActionAudit(ActionsEnum.reGenerateSecret), + reKey.reGenerateSiteSecret +); + +authenticated.put( + "/re-key/:orgId/regenerate-remote-exit-node-secret", + verifyApiKeyOrgAccess, + verifyLimits, + verifyApiKeyHasAction(ActionsEnum.reGenerateSecret), + logActionAudit(ActionsEnum.reGenerateSecret), + reKey.reGenerateExitNodeSecret +); + authenticated.post( "/org/:orgId/reset-bandwidth", verifyApiKeyOrgAccess, @@ -1497,6 +1516,15 @@ authenticated.post( client.updateClient ); +authenticated.post( + "/re-key/:clientId/regenerate-client-secret", + verifyApiKeyClientAccess, + verifyLimits, + verifyApiKeyHasAction(ActionsEnum.reGenerateSecret), + logActionAudit(ActionsEnum.reGenerateSecret), + reKey.reGenerateClientSecret +); + authenticated.put( "/org/:orgId/blueprint", verifyApiKeyOrgAccess, diff --git a/server/routers/re-key/index.ts b/server/routers/re-key/index.ts new file mode 100644 index 000000000..beb38a92e --- /dev/null +++ b/server/routers/re-key/index.ts @@ -0,0 +1,3 @@ +export * from "./reGenerateClientSecret"; +export * from "./reGenerateSiteSecret"; +export * from "./reGenerateExitNodeSecret"; diff --git a/server/private/routers/re-key/reGenerateClientSecret.ts b/server/routers/re-key/reGenerateClientSecret.ts similarity index 80% rename from server/private/routers/re-key/reGenerateClientSecret.ts rename to server/routers/re-key/reGenerateClientSecret.ts index c0c160f7e..53217de24 100644 --- a/server/private/routers/re-key/reGenerateClientSecret.ts +++ b/server/routers/re-key/reGenerateClientSecret.ts @@ -1,16 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db, Olm, olms } from "@server/db"; @@ -23,7 +10,7 @@ import { eq, and } from "drizzle-orm"; import { fromError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; import { hashPassword } from "@server/auth/password"; -import { disconnectClient, sendToClient } from "#private/routers/ws"; +import { disconnectClient, sendToClient } from "#dynamic/routers/ws"; import { OlmErrorCodes, sendOlmError } from "@server/routers/olm/error"; import { sendTerminateClient } from "@server/routers/client/terminate"; @@ -39,6 +26,40 @@ const reGenerateSecretBodySchema = z.strictObject({ export type ReGenerateSecretBody = z.infer; +registry.registerPath({ + method: "post", + path: "/re-key/{clientId}/regenerate-client-secret", + description: + "Regenerate the secret for a machine client's olm. Optionally disconnects the olm so it must reconnect with the new secret.", + tags: [OpenAPITags.Client], + request: { + params: reGenerateSecretParamsSchema, + body: { + content: { + "application/json": { + schema: reGenerateSecretBodySchema + } + } + } + }, + responses: { + 200: { + description: "Successful response", + content: { + "application/json": { + schema: z.object({ + data: z.object({ olmId: z.string() }), + success: z.boolean(), + error: z.boolean(), + message: z.string(), + status: z.number() + }) + } + } + } + } +}); + export async function reGenerateClientSecret( req: Request, res: Response, diff --git a/server/private/routers/re-key/reGenerateExitNodeSecret.ts b/server/routers/re-key/reGenerateExitNodeSecret.ts similarity index 68% rename from server/private/routers/re-key/reGenerateExitNodeSecret.ts rename to server/routers/re-key/reGenerateExitNodeSecret.ts index df5f57048..80bcb166d 100644 --- a/server/private/routers/re-key/reGenerateExitNodeSecret.ts +++ b/server/routers/re-key/reGenerateExitNodeSecret.ts @@ -1,16 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - import { NextFunction, Request, Response } from "express"; import { db, @@ -30,7 +17,7 @@ import { hashPassword } from "@server/auth/password"; import logger from "@server/logger"; import { and, eq } from "drizzle-orm"; import { OpenAPITags, registry } from "@server/openApi"; -import { disconnectClient, sendToClient } from "#private/routers/ws"; +import { disconnectClient, sendToClient } from "#dynamic/routers/ws"; export const paramsSchema = z.object({ orgId: z.string() @@ -42,6 +29,40 @@ const bodySchema = z.strictObject({ disconnect: z.boolean().optional().default(true) }); +registry.registerPath({ + method: "put", + path: "/re-key/{orgId}/regenerate-remote-exit-node-secret", + description: + "Regenerate the secret for a remote exit node. Optionally disconnects the node so it must reconnect with the new secret.", + tags: [OpenAPITags.RemoteExitNode], + request: { + params: paramsSchema, + body: { + content: { + "application/json": { + schema: bodySchema + } + } + } + }, + responses: { + 200: { + description: "Successful response", + content: { + "application/json": { + schema: z.object({ + data: z.null(), + success: z.boolean(), + error: z.boolean(), + message: z.string(), + status: z.number() + }) + } + } + } + } +}); + export async function reGenerateExitNodeSecret( req: Request, res: Response, @@ -68,12 +89,25 @@ export async function reGenerateExitNodeSecret( ); } + const { orgId } = parsedParams.data; const { remoteExitNodeId, secret, disconnect } = parsedBody.data; + // Only allow re-keying a node that belongs to this org (a node can be + // shared across several orgs; any of them may re-key it) const [existingRemoteExitNode] = await db - .select() + .select({ remoteExitNodeId: remoteExitNodes.remoteExitNodeId }) .from(remoteExitNodes) - .where(eq(remoteExitNodes.remoteExitNodeId, remoteExitNodeId)); + .innerJoin( + exitNodeOrgs, + eq(exitNodeOrgs.exitNodeId, remoteExitNodes.exitNodeId) + ) + .where( + and( + eq(remoteExitNodes.remoteExitNodeId, remoteExitNodeId), + eq(exitNodeOrgs.orgId, orgId) + ) + ) + .limit(1); if (!existingRemoteExitNode) { return next( diff --git a/server/private/routers/re-key/reGenerateSiteSecret.ts b/server/routers/re-key/reGenerateSiteSecret.ts similarity index 86% rename from server/private/routers/re-key/reGenerateSiteSecret.ts rename to server/routers/re-key/reGenerateSiteSecret.ts index 2bb29b202..3afbe58a3 100644 --- a/server/private/routers/re-key/reGenerateSiteSecret.ts +++ b/server/routers/re-key/reGenerateSiteSecret.ts @@ -1,16 +1,3 @@ -/* - * This file is part of a proprietary work. - * - * Copyright (c) 2025-2026 Fossorial, Inc. - * All rights reserved. - * - * This file is licensed under the Fossorial Commercial License. - * You may not use this file except in compliance with the License. - * Unauthorized use, copying, modification, or distribution is strictly prohibited. - * - * This file is not licensed under the AGPLv3. - */ - import { Request, Response, NextFunction } from "express"; import { z } from "zod"; import { db, Newt, newts, sites } from "@server/db"; @@ -24,7 +11,7 @@ import { OpenAPITags, registry } from "@server/openApi"; import { hashPassword } from "@server/auth/password"; import { addPeer, deletePeer } from "@server/routers/gerbil/peers"; import { getAllowedIps } from "@server/routers/target/helpers"; -import { disconnectClient, sendToClient } from "#private/routers/ws"; +import { disconnectClient, sendToClient } from "#dynamic/routers/ws"; const updateSiteParamsSchema = z.strictObject({ siteId: z.coerce.number().int().positive() @@ -37,6 +24,40 @@ const updateSiteBodySchema = z.strictObject({ disconnect: z.boolean().optional().default(true) }); +registry.registerPath({ + method: "post", + path: "/re-key/{siteId}/regenerate-site-secret", + description: + "Regenerate the credentials for a site. For newt sites a new secret is required; for wireguard sites a new public key is required.", + tags: [OpenAPITags.Site], + request: { + params: updateSiteParamsSchema, + body: { + content: { + "application/json": { + schema: updateSiteBodySchema + } + } + } + }, + responses: { + 200: { + description: "Successful response", + content: { + "application/json": { + schema: z.object({ + data: z.object({ newtId: z.string().optional() }), + success: z.boolean(), + error: z.boolean(), + message: z.string(), + status: z.number() + }) + } + } + } + } +}); + export async function reGenerateSiteSecret( req: Request, res: Response, diff --git a/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx b/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx index 2f24b15cf..24efde738 100644 --- a/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx +++ b/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/credentials/page.tsx @@ -32,9 +32,6 @@ import { import CopyToClipboard from "@app/components/CopyToClipboard"; import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert"; import { InfoIcon } from "lucide-react"; -import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; -import { usePaidStatus } from "@app/hooks/usePaidStatus"; -import { tierMatrix } from "@server/lib/billing/tierMatrix"; export default function CredentialsPage() { const { env } = useEnvContext(); @@ -44,8 +41,6 @@ export default function CredentialsPage() { const t = useTranslations(); const { remoteExitNode } = useRemoteExitNodeContext(); - const { isPaidUser } = usePaidStatus(); - const [modalOpen, setModalOpen] = useState(false); const [credentials, setCredentials] = useState(null); @@ -129,10 +124,6 @@ export default function CredentialsPage() { - - @@ -196,9 +187,6 @@ export default function CredentialsPage() { setShouldDisconnect(false); setModalOpen(true); }} - disabled={ - !isPaidUser(tierMatrix.rotateCredentials) - } > {t("regenerateCredentialsButton")} @@ -207,9 +195,6 @@ export default function CredentialsPage() { setShouldDisconnect(true); setModalOpen(true); }} - disabled={ - !isPaidUser(tierMatrix.rotateCredentials) - } > {t("remoteExitNodeRegenerateAndDisconnect")} diff --git a/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx b/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx index 634994b25..c575a53b2 100644 --- a/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx +++ b/src/app/[orgId]/settings/clients/machine/[niceId]/credentials/page.tsx @@ -28,10 +28,7 @@ import { import CopyToClipboard from "@app/components/CopyToClipboard"; import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert"; import { InfoIcon } from "lucide-react"; -import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; import { OlmInstallCommands } from "@app/components/olm-install-commands"; -import { usePaidStatus } from "@app/hooks/usePaidStatus"; -import { tierMatrix } from "@server/lib/billing/tierMatrix"; export default function CredentialsPage() { const { env } = useEnvContext(); @@ -53,8 +50,6 @@ export default function CredentialsPage() { const [showCredentialsAlert, setShowCredentialsAlert] = useState(false); const [shouldDisconnect, setShouldDisconnect] = useState(true); - const { isPaidUser } = usePaidStatus(); - const handleConfirmRegenerate = async () => { try { const res = await api.get(`/org/${orgId}/pick-client-defaults`); @@ -119,10 +114,6 @@ export default function CredentialsPage() { - - @@ -182,9 +173,6 @@ export default function CredentialsPage() { setShouldDisconnect(false); setModalOpen(true); }} - disabled={ - !isPaidUser(tierMatrix.rotateCredentials) - } > {t("regenerateCredentialsButton")} @@ -193,9 +181,6 @@ export default function CredentialsPage() { setShouldDisconnect(true); setModalOpen(true); }} - disabled={ - !isPaidUser(tierMatrix.rotateCredentials) - } > {t("clientRegenerateAndDisconnect")} diff --git a/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx b/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx index 88ab47bb0..72bea2ccf 100644 --- a/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx +++ b/src/app/[orgId]/settings/sites/[niceId]/credentials/page.tsx @@ -35,10 +35,7 @@ import { generateObfuscatedWireGuardConfig } from "@app/lib/wireguard"; import { QRCodeCanvas } from "qrcode.react"; -import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; import { NewtSiteInstallCommands } from "@app/components/newt-install-commands"; -import { usePaidStatus } from "@app/hooks/usePaidStatus"; -import { tierMatrix } from "@server/lib/billing/tierMatrix"; import type { AxiosResponse } from "axios"; import { useQuery } from "@tanstack/react-query"; import { productUpdatesQueries } from "@app/lib/queries"; @@ -67,8 +64,6 @@ export default function CredentialsPage() { const [loadingDefaults, setLoadingDefaults] = useState(false); const [shouldDisconnect, setShouldDisconnect] = useState(true); - const { isPaidUser } = usePaidStatus(); - const { data: latestVersions } = useQuery( productUpdatesQueries.latestVersion(true) ); @@ -206,10 +201,6 @@ export default function CredentialsPage() { - - @@ -280,11 +271,6 @@ export default function CredentialsPage() { setShouldDisconnect(false); setModalOpen(true); }} - disabled={ - !isPaidUser( - tierMatrix.rotateCredentials - ) - } > {t("regenerateCredentialsButton")} @@ -293,11 +279,6 @@ export default function CredentialsPage() { setShouldDisconnect(true); setModalOpen(true); }} - disabled={ - !isPaidUser( - tierMatrix.rotateCredentials - ) - } > {t("siteRegenerateAndDisconnect")} @@ -324,10 +305,6 @@ export default function CredentialsPage() { - - {!loadingDefaults && ( <> @@ -393,14 +370,7 @@ export default function CredentialsPage() { {!env.flags.disableEnterpriseFeatures && ( - diff --git a/src/components/PermissionsSelectBox.tsx b/src/components/PermissionsSelectBox.tsx index a6bb26ec5..19b39eab9 100644 --- a/src/components/PermissionsSelectBox.tsx +++ b/src/components/PermissionsSelectBox.tsx @@ -36,7 +36,8 @@ function getActionsCategories(root: boolean) { [t("createOrgUser")]: "createOrgUser", [t("actionApplyBlueprint")]: "applyBlueprint", [t("actionListBlueprints")]: "listBlueprints", - [t("actionGetBlueprint")]: "getBlueprint" + [t("actionGetBlueprint")]: "getBlueprint", + [t("actionReGenerateSecret")]: "reGenerateSecret" }, Domain: {