feat(licenses): enhance license validation process

- Updated the validateLicense function to accept server IP for improved validation.
- Modified user API to utilize the new validateLicense signature.
- Added useEffect in EnablePaidFeatures component to set license key based on user data.
- Improved error handling and user feedback during license validation.
This commit is contained in:
Mauricio Siu
2025-03-23 04:55:16 -06:00
parent fb0272a64d
commit b7874f053f
4 changed files with 38 additions and 8 deletions

View File

@@ -12,7 +12,7 @@ import { api } from "@/utils/api";
import { SetupMonitoring } from "./servers/setup-monitoring"; import { SetupMonitoring } from "./servers/setup-monitoring";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { useState } from "react"; import { useState, useEffect } from "react";
export const EnablePaidFeatures = () => { export const EnablePaidFeatures = () => {
const { data, refetch } = api.user.get.useQuery(); const { data, refetch } = api.user.get.useQuery();
@@ -21,14 +21,25 @@ export const EnablePaidFeatures = () => {
const { mutateAsync: update } = api.user.update.useMutation(); const { mutateAsync: update } = api.user.update.useMutation();
const [licenseKey, setLicenseKey] = useState(""); const [licenseKey, setLicenseKey] = useState("");
useEffect(() => {
if (data?.user?.enablePaidFeatures) {
setLicenseKey(data.user.licenseKey || "");
}
}, [data?.user?.enablePaidFeatures]);
const handleValidateLicense = async () => { const handleValidateLicense = async () => {
if (!licenseKey) {
toast.error("Please enter a license key");
return;
}
await validateLicense({ await validateLicense({
licenseKey, licenseKey,
}) })
.then(() => { .then(() => {
toast.success("License validated successfully"); toast.success("License validated successfully");
}) })
.catch(() => { .catch((e) => {
console.error(e);
toast.error("Error validating license"); toast.error("Error validating license");
}); });
}; };

View File

@@ -140,14 +140,18 @@ export const userRouter = createTRPCRouter({
} }
return await updateUser(ctx.user.id, input); return await updateUser(ctx.user.id, input);
}), }),
validateLicense: protectedProcedure validateLicense: adminProcedure
.input( .input(
z.object({ z.object({
licenseKey: z.string(), licenseKey: z.string(),
}), }),
) )
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const isValid = await validateLicense(input.licenseKey); const owner = await findUserById(ctx.user.ownerId);
const isValid = await validateLicense(
input.licenseKey,
owner?.serverIp || "",
);
if (!isValid) { if (!isValid) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
@@ -363,7 +367,7 @@ export const userRouter = createTRPCRouter({
const user = await findUserById(ctx.user.id); const user = await findUserById(ctx.user.id);
if (!validateLicense(user?.licenseKey || "")) { if (!validateLicense(user?.licenseKey || "", user?.serverIp || "")) {
throw new TRPCError({ throw new TRPCError({
code: "UNAUTHORIZED", code: "UNAUTHORIZED",
message: "Invalid license key", message: "Invalid license key",

View File

@@ -1,8 +1,21 @@
export const validateLicense = async (licenseKey: string): Promise<boolean> => { const licensesUrl = process.env.LICENSES_URL || "http://localhost:4002";
const response = await fetch(`${process.env.SERVER_URL}/validate-license`, {
export const validateLicense = async (
licenseKey: string,
serverIp: string,
): Promise<boolean> => {
const response = await fetch(`${licensesUrl}/api/validate`, {
method: "POST", method: "POST",
body: JSON.stringify({ licenseKey }), headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ licenseKey, serverIp }),
}); });
const data = await response.json();
if (!response.ok && data.error?.issues) {
console.log("Validation errors:", data.error.issues);
}
return response.ok; return response.ok;
}; };

View File

@@ -56,6 +56,8 @@ router.get("/health", async (c) => {
router.post("/validate", zValidator("json", validateSchema), async (c) => { router.post("/validate", zValidator("json", validateSchema), async (c) => {
const { licenseKey, serverIp } = c.req.valid("json"); const { licenseKey, serverIp } = c.req.valid("json");
console.log("Validating license", licenseKey, serverIp);
try { try {
const result = await validateLicense(licenseKey, serverIp); const result = await validateLicense(licenseKey, serverIp);
return c.json(result); return c.json(result);