mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-01 00:26:38 +08:00
187 lines
4.8 KiB
Go
187 lines
4.8 KiB
Go
package license
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type KeygenClient struct {
|
|
AccountID string
|
|
Token string
|
|
HTTPClient *http.Client
|
|
}
|
|
|
|
func NewKeygenClient(accountID, token string) *KeygenClient {
|
|
return &KeygenClient{
|
|
AccountID: accountID,
|
|
Token: token,
|
|
HTTPClient: &http.Client{Timeout: 10 * time.Second},
|
|
}
|
|
}
|
|
|
|
type ValidateResponse struct {
|
|
Meta struct {
|
|
Valid bool `json:"valid"`
|
|
Code string `json:"code"`
|
|
} `json:"meta"`
|
|
Data struct {
|
|
ID string `json:"id"`
|
|
Attributes struct {
|
|
Expiry string `json:"expiry"`
|
|
} `json:"attributes"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
type ActivateMachineRequest struct {
|
|
Data struct {
|
|
Type string `json:"type"`
|
|
Attributes struct {
|
|
Fingerprint string `json:"fingerprint"`
|
|
} `json:"attributes"`
|
|
Relationships struct {
|
|
License struct {
|
|
Data struct {
|
|
Type string `json:"type"`
|
|
ID string `json:"id"`
|
|
} `json:"data"`
|
|
} `json:"license"`
|
|
} `json:"relationships"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
func (c *KeygenClient) ValidateKeyWithFingerprint(key string, fingerprint string) (*ValidateResponse, error) {
|
|
url := fmt.Sprintf("https://api.keygen.sh/v1/accounts/%s/licenses/actions/validate-key", c.AccountID)
|
|
|
|
meta := map[string]interface{}{
|
|
"key": key,
|
|
}
|
|
|
|
if fingerprint != "" {
|
|
meta["scope"] = map[string]interface{}{
|
|
"fingerprint": fingerprint,
|
|
}
|
|
}
|
|
|
|
reqBody := map[string]interface{}{
|
|
"meta": meta,
|
|
}
|
|
|
|
bodyBytes, _ := json.Marshal(reqBody)
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(bodyBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Accept", "application/json")
|
|
if c.Token != "" {
|
|
if !strings.HasPrefix(c.Token, "Bearer ") && !strings.HasPrefix(c.Token, "License ") {
|
|
req.Header.Set("Authorization", "License "+c.Token)
|
|
} else {
|
|
req.Header.Set("Authorization", c.Token)
|
|
}
|
|
}
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("keygen api error: status %d", resp.StatusCode)
|
|
}
|
|
|
|
var valResp ValidateResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&valResp); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &valResp, nil
|
|
}
|
|
|
|
func (c *KeygenClient) ValidateKey(key string) (*ValidateResponse, error) {
|
|
url := fmt.Sprintf("https://api.keygen.sh/v1/accounts/%s/licenses/actions/validate-key", c.AccountID)
|
|
|
|
reqBody := map[string]interface{}{
|
|
"meta": map[string]string{
|
|
"key": key,
|
|
},
|
|
}
|
|
bodyBytes, _ := json.Marshal(reqBody)
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(bodyBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Accept", "application/json")
|
|
if c.Token != "" {
|
|
if !strings.HasPrefix(c.Token, "Bearer ") && !strings.HasPrefix(c.Token, "License ") {
|
|
req.Header.Set("Authorization", "License "+c.Token)
|
|
} else {
|
|
req.Header.Set("Authorization", c.Token)
|
|
}
|
|
}
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("keygen api error: status %d", resp.StatusCode)
|
|
}
|
|
|
|
var valResp ValidateResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&valResp); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &valResp, nil
|
|
}
|
|
|
|
func (c *KeygenClient) ActivateMachine(licenseID, fingerprint string) error {
|
|
url := fmt.Sprintf("https://api.keygen.sh/v1/accounts/%s/machines", c.AccountID)
|
|
|
|
var reqBody ActivateMachineRequest
|
|
reqBody.Data.Type = "machines"
|
|
reqBody.Data.Attributes.Fingerprint = fingerprint
|
|
reqBody.Data.Relationships.License.Data.Type = "licenses"
|
|
reqBody.Data.Relationships.License.Data.ID = licenseID
|
|
|
|
bodyBytes, _ := json.Marshal(reqBody)
|
|
|
|
req, _ := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(bodyBytes))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Accept", "application/json")
|
|
if c.Token != "" {
|
|
if !strings.HasPrefix(c.Token, "Bearer ") && !strings.HasPrefix(c.Token, "License ") {
|
|
req.Header.Set("Authorization", "License "+c.Token)
|
|
} else {
|
|
req.Header.Set("Authorization", c.Token)
|
|
}
|
|
}
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusOK {
|
|
return nil
|
|
}
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
if resp.StatusCode == http.StatusConflict || resp.StatusCode == http.StatusUnprocessableEntity {
|
|
if strings.Contains(string(body), "FINGERPRINT_TAKEN") || strings.Contains(string(body), "MACHINE_LIMIT_EXCEEDED") {
|
|
// Machine already registered to this license or limit reached because it's already us.
|
|
// The subsequent ValidateKey check will determine if the existing machine is actually us.
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("failed to activate machine: status %d, response: %s", resp.StatusCode, string(body))
|
|
} |