license-server/license/service.go

130 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
})
}
}