Skip to content

Commit f5fa39b

Browse files
committed
refactor(dokploy): restrict license key access to owners only and enhance validation
- Updated the license key settings to ensure only users with the "owner" role can access certain functionalities. - Modified the license key activation input validation to require a non-empty string. - Improved error handling for network issues when validating license keys, providing clearer feedback to users. - Adjusted the dashboard settings to redirect non-owner users appropriately.
1 parent 0a3a90c commit f5fa39b

File tree

5 files changed

+53
-6
lines changed

5 files changed

+53
-6
lines changed

apps/dokploy/components/layouts/side.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,7 @@ const MENU: Menu = {
404404
url: "/dashboard/settings/license",
405405
icon: Key,
406406
// Only enabled for admins in non-cloud environments
407-
isEnabled: ({ auth }) =>
408-
!!(auth?.role === "owner" || auth?.role === "admin"),
407+
isEnabled: ({ auth }) => !!(auth?.role === "owner"),
409408
},
410409
{
411410
isSingle: true,

apps/dokploy/components/proprietary/license-keys/license-key.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@ export function LicenseKeySettings() {
166166
{!haveValidLicenseKey && (
167167
<Button
168168
variant="secondary"
169-
disabled={isSaving || isValidating || isDeactivating}
169+
disabled={
170+
isSaving ||
171+
isValidating ||
172+
isDeactivating ||
173+
!licenseKey.trim()
174+
}
170175
isLoading={isActivating}
171176
onClick={async () => {
172177
try {

apps/dokploy/pages/dashboard/settings/license.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IS_CLOUD, validateRequest } from "@dokploy/server";
1+
import { validateRequest } from "@dokploy/server";
22
import { createServerSideHelpers } from "@trpc/react-query/server";
33
import type { GetServerSidePropsContext } from "next";
44
import type { ReactElement } from "react";
@@ -45,7 +45,7 @@ export async function getServerSideProps(
4545
},
4646
};
4747
}
48-
if (user.role === "member") {
48+
if (user.role !== "owner") {
4949
return {
5050
redirect: {
5151
permanent: true,

apps/dokploy/server/api/routers/proprietary/license-key.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212

1313
export const licenseKeyRouter = createTRPCRouter({
1414
activate: adminProcedure
15-
.input(z.object({ licenseKey: z.string() }))
15+
.input(z.object({ licenseKey: z.string().min(1) }))
1616
.mutation(async ({ input, ctx }) => {
1717
try {
1818
const currentUserId = ctx.user.id;
@@ -74,6 +74,13 @@ export const licenseKeyRouter = createTRPCRouter({
7474
});
7575
}
7676

77+
if (ctx.user.role !== "owner") {
78+
throw new TRPCError({
79+
code: "FORBIDDEN",
80+
message: "You are not authorized to validate a license key",
81+
});
82+
}
83+
7784
if (!currentUser.licenseKey) {
7885
throw new TRPCError({
7986
code: "BAD_REQUEST",
@@ -164,6 +171,13 @@ export const licenseKeyRouter = createTRPCRouter({
164171
});
165172
}
166173

174+
if (ctx.user.role !== "owner") {
175+
throw new TRPCError({
176+
code: "FORBIDDEN",
177+
message: "You are not authorized to get enterprise settings",
178+
});
179+
}
180+
167181
return {
168182
enableEnterpriseFeatures: !!currentUser.enableEnterpriseFeatures,
169183
licenseKey: currentUser.licenseKey ?? "",
@@ -200,6 +214,13 @@ export const licenseKeyRouter = createTRPCRouter({
200214
});
201215
}
202216

217+
if (ctx.user.role !== "owner") {
218+
throw new TRPCError({
219+
code: "FORBIDDEN",
220+
message: "You are not authorized to update enterprise settings",
221+
});
222+
}
223+
203224
await db
204225
.update(user)
205226
.set({

apps/dokploy/server/utils/enterprise.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import { getPublicIpWithFallback, LICENSE_KEY_URL } from "@dokploy/server";
22

3+
const LICENSE_SERVER_UNREACHABLE =
4+
"Could not reach the license server. Check your connection or try again later.";
5+
6+
function isNetworkError(error: unknown): boolean {
7+
if (error instanceof Error) {
8+
if (error.message === "fetch failed") return true;
9+
const cause = (error as Error & { cause?: { code?: string } }).cause;
10+
const code = cause?.code;
11+
return code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "ETIMEDOUT";
12+
}
13+
return false;
14+
}
15+
316
export const validateLicenseKey = async (licenseKey: string) => {
417
try {
518
const ip = await getPublicIpWithFallback();
@@ -22,6 +35,9 @@ export const validateLicenseKey = async (licenseKey: string) => {
2235
console.error(
2336
error instanceof Error ? error.message : "Failed to validate license key",
2437
);
38+
if (isNetworkError(error)) {
39+
throw new Error(LICENSE_SERVER_UNREACHABLE);
40+
}
2541
throw error;
2642
}
2743
};
@@ -48,6 +64,9 @@ export const activateLicenseKey = async (licenseKey: string) => {
4864
console.error(
4965
error instanceof Error ? error.message : "Failed to activate license key",
5066
);
67+
if (isNetworkError(error)) {
68+
throw new Error(LICENSE_SERVER_UNREACHABLE);
69+
}
5170
throw error;
5271
}
5372
};
@@ -76,6 +95,9 @@ export const deactivateLicenseKey = async (licenseKey: string) => {
7695
? error.message
7796
: "Failed to deactivate license key",
7897
);
98+
if (isNetworkError(error)) {
99+
throw new Error(LICENSE_SERVER_UNREACHABLE);
100+
}
79101
throw error;
80102
}
81103
};

0 commit comments

Comments
 (0)