remove enable_clients flag from config

This commit is contained in:
miloschwartz
2025-12-03 15:02:39 -05:00
parent e1edbe6067
commit 357f297a3e
18 changed files with 138 additions and 232 deletions

View File

@@ -25,4 +25,3 @@ flags:
disable_user_create_org: true disable_user_create_org: true
allow_raw_resources: true allow_raw_resources: true
enable_integration_api: true enable_integration_api: true
enable_clients: true

View File

@@ -85,10 +85,6 @@ export class Config {
? "true" ? "true"
: "false"; : "false";
process.env.FLAGS_ENABLE_CLIENTS = parsedConfig.flags?.enable_clients
? "true"
: "false";
process.env.PRODUCT_UPDATES_NOTIFICATION_ENABLED = parsedConfig.app process.env.PRODUCT_UPDATES_NOTIFICATION_ENABLED = parsedConfig.app
.notifications.product_updates .notifications.product_updates
? "true" ? "true"

View File

@@ -325,8 +325,7 @@ export const configSchema = z
enable_integration_api: z.boolean().optional(), enable_integration_api: z.boolean().optional(),
disable_local_sites: z.boolean().optional(), disable_local_sites: z.boolean().optional(),
disable_basic_wireguard_sites: z.boolean().optional(), disable_basic_wireguard_sites: z.boolean().optional(),
disable_config_managed_domains: z.boolean().optional(), disable_config_managed_domains: z.boolean().optional()
enable_clients: z.boolean().optional().default(true)
}) })
.optional(), .optional(),
dns: z dns: z

View File

@@ -25,7 +25,6 @@ export * from "./integration";
export * from "./verifyUserHasAction"; export * from "./verifyUserHasAction";
export * from "./verifyApiKeyAccess"; export * from "./verifyApiKeyAccess";
export * from "./verifyDomainAccess"; export * from "./verifyDomainAccess";
export * from "./verifyClientsEnabled";
export * from "./verifyUserIsOrgOwner"; export * from "./verifyUserIsOrgOwner";
export * from "./verifySiteResourceAccess"; export * from "./verifySiteResourceAccess";
export * from "./logActionAudit"; export * from "./logActionAudit";

View File

@@ -1,29 +0,0 @@
import { Request, Response, NextFunction } from "express";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
import config from "@server/lib/config";
export async function verifyClientsEnabled(
req: Request,
res: Response,
next: NextFunction
) {
try {
if (!config.getRawConfig().flags?.enable_clients) {
return next(
createHttpError(
HttpCode.NOT_IMPLEMENTED,
"Clients are not enabled on this server."
)
);
}
return next();
} catch (error) {
return next(
createHttpError(
HttpCode.INTERNAL_SERVER_ERROR,
"Failed to check if clients are enabled"
)
);
}
}

View File

@@ -31,7 +31,6 @@ import {
verifyUserIsServerAdmin, verifyUserIsServerAdmin,
verifySiteAccess, verifySiteAccess,
verifyClientAccess, verifyClientAccess,
verifyClientsEnabled,
} from "@server/middlewares"; } from "@server/middlewares";
import { ActionsEnum } from "@server/auth/actions"; import { ActionsEnum } from "@server/auth/actions";
import { import {
@@ -410,7 +409,6 @@ authenticated.get(
authenticated.post( authenticated.post(
"/re-key/:clientId/regenerate-client-secret", "/re-key/:clientId/regenerate-client-secret",
verifyClientsEnabled,
verifyClientAccess, verifyClientAccess,
verifyUserHasAction(ActionsEnum.reGenerateSecret), verifyUserHasAction(ActionsEnum.reGenerateSecret),
reKey.reGenerateClientSecret reKey.reGenerateClientSecret

View File

@@ -37,7 +37,6 @@ import {
verifyClientAccess, verifyClientAccess,
verifyApiKeyAccess, verifyApiKeyAccess,
verifyDomainAccess, verifyDomainAccess,
verifyClientsEnabled,
verifyUserHasAction, verifyUserHasAction,
verifyUserIsOrgOwner, verifyUserIsOrgOwner,
verifySiteResourceAccess, verifySiteResourceAccess,
@@ -131,7 +130,6 @@ authenticated.get(
authenticated.get( authenticated.get(
"/org/:orgId/pick-client-defaults", "/org/:orgId/pick-client-defaults",
verifyClientsEnabled,
verifyOrgAccess, verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createClient), verifyUserHasAction(ActionsEnum.createClient),
client.pickClientDefaults client.pickClientDefaults
@@ -139,7 +137,6 @@ authenticated.get(
authenticated.get( authenticated.get(
"/org/:orgId/clients", "/org/:orgId/clients",
verifyClientsEnabled,
verifyOrgAccess, verifyOrgAccess,
verifyUserHasAction(ActionsEnum.listClients), verifyUserHasAction(ActionsEnum.listClients),
client.listClients client.listClients
@@ -147,7 +144,6 @@ authenticated.get(
authenticated.get( authenticated.get(
"/client/:clientId", "/client/:clientId",
verifyClientsEnabled,
verifyClientAccess, verifyClientAccess,
verifyUserHasAction(ActionsEnum.getClient), verifyUserHasAction(ActionsEnum.getClient),
client.getClient client.getClient
@@ -155,7 +151,6 @@ authenticated.get(
authenticated.put( authenticated.put(
"/org/:orgId/client", "/org/:orgId/client",
verifyClientsEnabled,
verifyOrgAccess, verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createClient), verifyUserHasAction(ActionsEnum.createClient),
logActionAudit(ActionsEnum.createClient), logActionAudit(ActionsEnum.createClient),
@@ -165,7 +160,6 @@ authenticated.put(
// TODO: Separate into a deleteUserClient (for user clients) and deleteClient (for machine clients) // TODO: Separate into a deleteUserClient (for user clients) and deleteClient (for machine clients)
authenticated.delete( authenticated.delete(
"/client/:clientId", "/client/:clientId",
verifyClientsEnabled,
verifyClientAccess, verifyClientAccess,
verifyUserHasAction(ActionsEnum.deleteClient), verifyUserHasAction(ActionsEnum.deleteClient),
logActionAudit(ActionsEnum.deleteClient), logActionAudit(ActionsEnum.deleteClient),
@@ -174,7 +168,6 @@ authenticated.delete(
authenticated.post( authenticated.post(
"/client/:clientId", "/client/:clientId",
verifyClientsEnabled,
verifyClientAccess, // this will check if the user has access to the client verifyClientAccess, // this will check if the user has access to the client
verifyUserHasAction(ActionsEnum.updateClient), // this will check if the user has permission to update the client verifyUserHasAction(ActionsEnum.updateClient), // this will check if the user has permission to update the client
logActionAudit(ActionsEnum.updateClient), logActionAudit(ActionsEnum.updateClient),

View File

@@ -24,7 +24,6 @@ import {
verifyApiKeyAccessTokenAccess, verifyApiKeyAccessTokenAccess,
verifyApiKeyIsRoot, verifyApiKeyIsRoot,
verifyApiKeyClientAccess, verifyApiKeyClientAccess,
verifyClientsEnabled,
verifyApiKeySiteResourceAccess, verifyApiKeySiteResourceAccess,
verifyApiKeySetResourceClients verifyApiKeySetResourceClients
} from "@server/middlewares"; } from "@server/middlewares";
@@ -796,7 +795,6 @@ authenticated.get(
authenticated.get( authenticated.get(
"/org/:orgId/pick-client-defaults", "/org/:orgId/pick-client-defaults",
verifyClientsEnabled,
verifyApiKeyOrgAccess, verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createClient), verifyApiKeyHasAction(ActionsEnum.createClient),
client.pickClientDefaults client.pickClientDefaults
@@ -804,7 +802,6 @@ authenticated.get(
authenticated.get( authenticated.get(
"/org/:orgId/clients", "/org/:orgId/clients",
verifyClientsEnabled,
verifyApiKeyOrgAccess, verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.listClients), verifyApiKeyHasAction(ActionsEnum.listClients),
client.listClients client.listClients
@@ -812,7 +809,6 @@ authenticated.get(
authenticated.get( authenticated.get(
"/client/:clientId", "/client/:clientId",
verifyClientsEnabled,
verifyApiKeyClientAccess, verifyApiKeyClientAccess,
verifyApiKeyHasAction(ActionsEnum.getClient), verifyApiKeyHasAction(ActionsEnum.getClient),
client.getClient client.getClient
@@ -820,7 +816,6 @@ authenticated.get(
authenticated.put( authenticated.put(
"/org/:orgId/client", "/org/:orgId/client",
verifyClientsEnabled,
verifyApiKeyOrgAccess, verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createClient), verifyApiKeyHasAction(ActionsEnum.createClient),
logActionAudit(ActionsEnum.createClient), logActionAudit(ActionsEnum.createClient),
@@ -839,7 +834,6 @@ authenticated.put(
authenticated.delete( authenticated.delete(
"/client/:clientId", "/client/:clientId",
verifyClientsEnabled,
verifyApiKeyClientAccess, verifyApiKeyClientAccess,
verifyApiKeyHasAction(ActionsEnum.deleteClient), verifyApiKeyHasAction(ActionsEnum.deleteClient),
logActionAudit(ActionsEnum.deleteClient), logActionAudit(ActionsEnum.deleteClient),
@@ -848,7 +842,6 @@ authenticated.delete(
authenticated.post( authenticated.post(
"/client/:clientId", "/client/:clientId",
verifyClientsEnabled,
verifyApiKeyClientAccess, verifyApiKeyClientAccess,
verifyApiKeyHasAction(ActionsEnum.updateClient), verifyApiKeyHasAction(ActionsEnum.updateClient),
logActionAudit(ActionsEnum.updateClient), logActionAudit(ActionsEnum.updateClient),

View File

@@ -13,9 +13,5 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
const { children } = props; const { children } = props;
const env = pullEnv(); const env = pullEnv();
if (!env.flags.enableClients) {
redirect(`/${params.orgId}/settings`);
}
return children; return children;
} }

View File

@@ -342,29 +342,25 @@ export default function GeneralPage() {
</FormItem> </FormItem>
)} )}
/> />
{env.flags.enableClients && ( <FormField
<FormField control={form.control}
control={form.control} name="subnet"
name="subnet" render={({ field }) => (
render={({ field }) => ( <FormItem>
<FormItem> <FormLabel>{t("subnet")}</FormLabel>
<FormLabel> <FormControl>
{t("subnet")} <Input
</FormLabel> {...field}
<FormControl> disabled={true}
<Input />
{...field} </FormControl>
disabled={true} <FormMessage />
/> <FormDescription>
</FormControl> {t("subnetDescription")}
<FormMessage /> </FormDescription>
<FormDescription> </FormItem>
{t("subnetDescription")} )}
</FormDescription> />
</FormItem>
)}
/>
)}
</SettingsSectionForm> </SettingsSectionForm>
</SettingsSectionBody> </SettingsSectionBody>
</SettingsSection> </SettingsSection>
@@ -600,7 +596,7 @@ export default function GeneralPage() {
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
<SettingsSectionForm> <SettingsSectionForm>
<SecurityFeaturesAlert /> <SecurityFeaturesAlert />
<FormField <FormField
control={form.control} control={form.control}
name="requireTwoFactor" name="requireTwoFactor"

View File

@@ -82,7 +82,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
<Layout <Layout
orgId={params.orgId} orgId={params.orgId}
orgs={orgs} orgs={orgs}
navItems={orgNavSections(env.flags.enableClients)} navItems={orgNavSections()}
> >
{children} {children}
</Layout> </Layout>

View File

@@ -708,51 +708,50 @@ WantedBy=default.target`
</FormItem> </FormItem>
)} )}
/> />
{env.flags.enableClients && {form.watch("method") ===
form.watch("method") === "newt" && (
"newt" && ( <FormField
<FormField control={form.control}
control={form.control} name="clientAddress"
name="clientAddress" render={({ field }) => (
render={({ field }) => ( <FormItem>
<FormItem> <FormLabel>
<FormLabel> {t(
{t( "siteAddress"
"siteAddress" )}
)} </FormLabel>
</FormLabel> <FormControl>
<FormControl> <Input
<Input autoComplete="off"
autoComplete="off" value={
value={ clientAddress
clientAddress }
} onChange={(
onChange={( e
) => {
setClientAddress(
e e
) => { .target
setClientAddress( .value
e );
.target field.onChange(
.value e
); .target
field.onChange( .value
e );
.target }}
.value />
); </FormControl>
}} <FormMessage />
/> <FormDescription>
</FormControl> {t(
<FormMessage /> "siteAddressDescription"
<FormDescription> )}
{t( </FormDescription>
"siteAddressDescription" </FormItem>
)} )}
</FormDescription> />
</FormItem> )}
)}
/>
)}
</form> </form>
</Form> </Form>
</SettingsSectionForm> </SettingsSectionForm>

View File

@@ -38,9 +38,7 @@ export const orgLangingNavItems: SidebarNavItem[] = [
} }
]; ];
export const orgNavSections = ( export const orgNavSections = (): SidebarNavSection[] => [
enableClients: boolean = true
): SidebarNavSection[] => [
{ {
heading: "General", heading: "General",
items: [ items: [
@@ -58,42 +56,30 @@ export const orgNavSections = (
href: "/{orgId}/settings/resources/proxy", href: "/{orgId}/settings/resources/proxy",
icon: <Globe className="size-4 flex-none" /> icon: <Globe className="size-4 flex-none" />
}, },
...(enableClients {
? [ title: "sidebarClientResources",
{ href: "/{orgId}/settings/resources/client",
title: "sidebarClientResources", icon: <GlobeLock className="size-4 flex-none" />
href: "/{orgId}/settings/resources/client", }
icon: ( ]
<GlobeLock className="size-4 flex-none" /> },
) {
} title: "sidebarClients",
] icon: <MonitorUp className="size-4 flex-none" />,
: []) isBeta: true,
items: [
{
href: "/{orgId}/settings/clients/user",
title: "sidebarUserDevices",
icon: <Laptop className="size-4 flex-none" />
},
{
href: "/{orgId}/settings/clients/machine",
title: "sidebarMachineClients",
icon: <Server className="size-4 flex-none" />
}
] ]
}, },
...(enableClients
? [
{
title: "sidebarClients",
icon: <MonitorUp className="size-4 flex-none" />,
isBeta: true,
items: [
{
href: "/{orgId}/settings/clients/user",
title: "sidebarUserDevices",
icon: (
<Laptop className="size-4 flex-none" />
)
},
{
href: "/{orgId}/settings/clients/machine",
title: "sidebarMachineClients",
icon: <Server className="size-4 flex-none" />
}
]
}
]
: []),
...(build == "saas" ...(build == "saas"
? [ ? [
{ {

View File

@@ -296,31 +296,27 @@ export default function StepperForm() {
)} )}
/> />
{env.flags.enableClients && ( <FormField
<FormField control={orgForm.control}
control={orgForm.control} name="subnet"
name="subnet" render={({ field }) => (
render={({ field }) => ( <FormItem>
<FormItem> <FormLabel>Subnet</FormLabel>
<FormLabel> <FormControl>
Subnet <Input
</FormLabel> type="text"
<FormControl> {...field}
<Input />
type="text" </FormControl>
{...field} <FormMessage />
/> <FormDescription>
</FormControl> The subnet for this
<FormMessage /> organization's internal
<FormDescription> network.
The subnet for this </FormDescription>
organization's internal </FormItem>
network. )}
</FormDescription> />
</FormItem>
)}
/>
)}
{orgIdTaken && !orgCreated ? ( {orgIdTaken && !orgCreated ? (
<Alert variant="destructive"> <Alert variant="destructive">

View File

@@ -35,7 +35,7 @@ export default function SiteInfoCard({ }: SiteInfoCardProps) {
return ( return (
<Alert> <Alert>
<AlertDescription> <AlertDescription>
<InfoSections cols={env.flags.enableClients ? 4 : 3}> <InfoSections cols={4}>
<InfoSection> <InfoSection>
<InfoSectionTitle> <InfoSectionTitle>
{t("identifier")} {t("identifier")}
@@ -75,7 +75,7 @@ export default function SiteInfoCard({ }: SiteInfoCardProps) {
</InfoSectionContent> </InfoSectionContent>
</InfoSection> </InfoSection>
{env.flags.enableClients && site.type == "newt" && ( {site.type == "newt" && (
<InfoSection> <InfoSection>
<InfoSectionTitle>Address</InfoSectionTitle> <InfoSectionTitle>Address</InfoSectionTitle>
<InfoSectionContent> <InfoSectionContent>

View File

@@ -306,42 +306,32 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
); );
} }
}, },
...(env.flags.enableClients {
? [ accessorKey: "address",
{ header: ({ column }: { column: Column<SiteRow, unknown> }) => {
accessorKey: "address", return (
header: ({ <Button
column variant="ghost"
}: { onClick={() =>
column: Column<SiteRow, unknown>; column.toggleSorting(column.getIsSorted() === "asc")
}) => { }
return ( >
<Button Address
variant="ghost" <ArrowUpDown className="ml-2 h-4 w-4" />
onClick={() => </Button>
column.toggleSorting( );
column.getIsSorted() === "asc" },
) cell: ({ row }: { row: any }) => {
} const originalRow = row.original;
> return originalRow.address ? (
Address <div className="flex items-center space-x-2">
<ArrowUpDown className="ml-2 h-4 w-4" /> <span>{originalRow.address}</span>
</Button> </div>
); ) : (
}, "-"
cell: ({ row }: { row: any }) => { );
const originalRow = row.original; }
return originalRow.address ? ( },
<div className="flex items-center space-x-2">
<span>{originalRow.address}</span>
</div>
) : (
"-"
);
}
}
]
: []),
{ {
id: "actions", id: "actions",
enableHiding: false, enableHiding: false,
@@ -403,9 +393,7 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) {
}} }}
dialog={ dialog={
<div className=""> <div className="">
<p> <p>{t("siteQuestionRemove")}</p>
{t("siteQuestionRemove")}
</p>
<p>{t("siteMessageRemove")}</p> <p>{t("siteMessageRemove")}</p>
</div> </div>
} }

View File

@@ -55,8 +55,6 @@ export function pullEnv(): Env {
process.env.FLAGS_DISABLE_BASIC_WIREGUARD_SITES === "true" process.env.FLAGS_DISABLE_BASIC_WIREGUARD_SITES === "true"
? true ? true
: false, : false,
enableClients:
process.env.FLAGS_ENABLE_CLIENTS === "true" ? true : false,
hideSupporterKey: hideSupporterKey:
process.env.HIDE_SUPPORTER_KEY === "true" ? true : false, process.env.HIDE_SUPPORTER_KEY === "true" ? true : false,
usePangolinDns: usePangolinDns:

View File

@@ -30,7 +30,6 @@ export type Env = {
allowRawResources: boolean; allowRawResources: boolean;
disableLocalSites: boolean; disableLocalSites: boolean;
disableBasicWireguardSites: boolean; disableBasicWireguardSites: boolean;
enableClients: boolean;
hideSupporterKey: boolean; hideSupporterKey: boolean;
usePangolinDns: boolean; usePangolinDns: boolean;
}; };