194 lines
4.9 KiB
Go
194 lines
4.9 KiB
Go
package ironlicensing
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Transport struct {
|
|
baseURL string
|
|
publicKey string
|
|
productSlug string
|
|
debug bool
|
|
httpClient *http.Client
|
|
machineID string
|
|
}
|
|
|
|
func NewTransport(baseURL, publicKey, productSlug string, timeout time.Duration, debug bool) *Transport {
|
|
t := &Transport{
|
|
baseURL: baseURL,
|
|
publicKey: publicKey,
|
|
productSlug: productSlug,
|
|
debug: debug,
|
|
httpClient: &http.Client{Timeout: timeout},
|
|
}
|
|
t.machineID = t.getMachineID()
|
|
return t
|
|
}
|
|
|
|
func (t *Transport) log(msg string) {
|
|
if t.debug {
|
|
fmt.Printf("[IronLicensing] %s\n", msg)
|
|
}
|
|
}
|
|
|
|
func (t *Transport) getMachineID() string {
|
|
homeDir, _ := os.UserHomeDir()
|
|
idPath := filepath.Join(homeDir, ".ironlicensing", "machine_id")
|
|
if data, err := os.ReadFile(idPath); err == nil {
|
|
return string(data)
|
|
}
|
|
id := uuid.New().String()
|
|
os.MkdirAll(filepath.Dir(idPath), 0755)
|
|
os.WriteFile(idPath, []byte(id), 0644)
|
|
return id
|
|
}
|
|
|
|
func (t *Transport) request(ctx context.Context, method, path string, body any) (*http.Response, error) {
|
|
var reqBody io.Reader
|
|
if body != nil {
|
|
data, _ := json.Marshal(body)
|
|
reqBody = bytes.NewReader(data)
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, method, t.baseURL+path, reqBody)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("X-Public-Key", t.publicKey)
|
|
req.Header.Set("X-Product-Slug", t.productSlug)
|
|
return t.httpClient.Do(req)
|
|
}
|
|
|
|
func (t *Transport) Validate(ctx context.Context, licenseKey string) LicenseResult {
|
|
t.log(fmt.Sprintf("Validating: %s...", licenseKey[:min(10, len(licenseKey))]))
|
|
resp, err := t.request(ctx, "POST", "/api/v1/validate", map[string]string{
|
|
"licenseKey": licenseKey,
|
|
"machineId": t.machineID,
|
|
})
|
|
if err != nil {
|
|
return LicenseResult{Valid: false, Error: err.Error()}
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
if resp.StatusCode == 200 {
|
|
var result LicenseResult
|
|
json.Unmarshal(body, &result)
|
|
return result
|
|
}
|
|
var errResp struct{ Error string }
|
|
json.Unmarshal(body, &errResp)
|
|
return LicenseResult{Valid: false, Error: errResp.Error}
|
|
}
|
|
|
|
func (t *Transport) Activate(ctx context.Context, licenseKey, machineName string) LicenseResult {
|
|
t.log(fmt.Sprintf("Activating: %s...", licenseKey[:min(10, len(licenseKey))]))
|
|
if machineName == "" {
|
|
machineName, _ = os.Hostname()
|
|
}
|
|
resp, err := t.request(ctx, "POST", "/api/v1/activate", map[string]string{
|
|
"licenseKey": licenseKey,
|
|
"machineId": t.machineID,
|
|
"machineName": machineName,
|
|
"platform": runtime.GOOS,
|
|
})
|
|
if err != nil {
|
|
return LicenseResult{Valid: false, Error: err.Error()}
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
if resp.StatusCode == 200 {
|
|
var result LicenseResult
|
|
json.Unmarshal(body, &result)
|
|
return result
|
|
}
|
|
var errResp struct{ Error string }
|
|
json.Unmarshal(body, &errResp)
|
|
return LicenseResult{Valid: false, Error: errResp.Error}
|
|
}
|
|
|
|
func (t *Transport) Deactivate(ctx context.Context, licenseKey string) bool {
|
|
resp, err := t.request(ctx, "POST", "/api/v1/deactivate", map[string]string{
|
|
"licenseKey": licenseKey,
|
|
"machineId": t.machineID,
|
|
})
|
|
if err != nil {
|
|
return false
|
|
}
|
|
defer resp.Body.Close()
|
|
return resp.StatusCode == 200
|
|
}
|
|
|
|
func (t *Transport) StartTrial(ctx context.Context, email string) LicenseResult {
|
|
t.log(fmt.Sprintf("Starting trial for: %s", email))
|
|
resp, err := t.request(ctx, "POST", "/api/v1/trial", map[string]string{
|
|
"email": email,
|
|
"machineId": t.machineID,
|
|
})
|
|
if err != nil {
|
|
return LicenseResult{Valid: false, Error: err.Error()}
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
if resp.StatusCode == 200 {
|
|
var result LicenseResult
|
|
json.Unmarshal(body, &result)
|
|
return result
|
|
}
|
|
var errResp struct{ Error string }
|
|
json.Unmarshal(body, &errResp)
|
|
return LicenseResult{Valid: false, Error: errResp.Error}
|
|
}
|
|
|
|
func (t *Transport) GetTiers(ctx context.Context) []ProductTier {
|
|
resp, err := t.request(ctx, "GET", "/api/v1/tiers", nil)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode == 200 {
|
|
var result struct{ Tiers []ProductTier }
|
|
json.NewDecoder(resp.Body).Decode(&result)
|
|
return result.Tiers
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *Transport) StartCheckout(ctx context.Context, tierID, email string) CheckoutResult {
|
|
resp, err := t.request(ctx, "POST", "/api/v1/checkout", map[string]string{
|
|
"tierId": tierID,
|
|
"email": email,
|
|
})
|
|
if err != nil {
|
|
return CheckoutResult{Success: false, Error: err.Error()}
|
|
}
|
|
defer resp.Body.Close()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
if resp.StatusCode == 200 {
|
|
var result CheckoutResult
|
|
json.Unmarshal(body, &result)
|
|
result.Success = true
|
|
return result
|
|
}
|
|
var errResp struct{ Error string }
|
|
json.Unmarshal(body, &errResp)
|
|
return CheckoutResult{Success: false, Error: errResp.Error}
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|