package license import ( "encoding/base64" "encoding/json" "license-server/storage" "time" "github.com/gofiber/fiber/v2" ) func GenerateLicenseHandler(db storage.Database) fiber.Handler { return func(c *fiber.Ctx) error { var req LicenseRequest if err := c.BodyParser(&req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } if req.MachineID == "" || req.Expiry == "" { return fiber.NewError(fiber.StatusBadRequest, "Missing required fields") } payloadBytes, err := json.Marshal(req) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Failed to encode payload") } signature, err := SignPayload(payloadBytes) if err != nil { return fiber.NewError(fiber.StatusInternalServerError, "Signing failed") } licenseFile := LicenseFile{ Payload: base64.StdEncoding.EncodeToString(payloadBytes), Signature: signature, } return c.JSON(licenseFile) } } func ActivateLicenseHandler(db storage.Database) fiber.Handler { return func(c *fiber.Ctx) error { var lf LicenseFile if err := c.BodyParser(&lf); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid license format") } payloadBytes, err := base64.StdEncoding.DecodeString(lf.Payload) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid base64 payload") } if !VerifySignature(GetPublicKey(), payloadBytes, lf.Signature) { return fiber.NewError(fiber.StatusUnauthorized, "Invalid license signature") } var req LicenseRequest if err := json.Unmarshal(payloadBytes, &req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Malformed payload") } if req.MachineID == "" { return fiber.NewError(fiber.StatusBadRequest, "Missing machine ID") } if db.HasActivated(req.MachineID) { return fiber.NewError(fiber.StatusForbidden, "This machine is already activated") } expiry, err := time.Parse("2006-01-02", req.Expiry) if err != nil || time.Now().After(expiry) { return fiber.NewError(fiber.StatusForbidden, "License is invalid or expired") } // 绑定激活记录 db.SaveActivation(req.MachineID, lf.Payload+"."+lf.Signature) return c.JSON(fiber.Map{"status": "success", "message": "License activated successfully"}) } } func ValidateLicenseHandler(db storage.Database) fiber.Handler { return func(c *fiber.Ctx) error { var lf LicenseFile if err := c.BodyParser(&lf); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid license format") } payloadBytes, err := base64.StdEncoding.DecodeString(lf.Payload) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid base64 payload") } // 1. 校验签名 if !VerifySignature(GetPublicKey(), payloadBytes, lf.Signature) { return fiber.NewError(fiber.StatusUnauthorized, "Invalid license signature") } // 2. 解析 payload var req LicenseRequest if err := json.Unmarshal(payloadBytes, &req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Malformed payload") } // 3. 验证是否过期 expiry, err := time.Parse("2006-01-02", req.Expiry) if err != nil || time.Now().After(expiry) { return fiber.NewError(fiber.StatusForbidden, "License expired") } // ✅ 4. 关键补充:校验调用者的 MachineID 与 license 中一致 // 从请求 Header 或 Body 读取实际设备 ID(假设从 Header 传) clientMachineID := c.Get("X-Machine-ID") if clientMachineID == "" { return fiber.NewError(fiber.StatusBadRequest, "Missing machine ID in header") } if clientMachineID != req.MachineID { return fiber.NewError(fiber.StatusForbidden, "Machine ID mismatch") } return c.JSON(fiber.Map{ "valid": true, "features": req.Features, // "machine": req.MachineID, "expiry": req.Expiry, }) } }