LibreAuth SDK Docs
Nut.exe
Go 144 lines · 3,029 bytes
package libreauth

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"time"
)

type Client struct {
	Name      string
	OwnerID   string
	Version   string
	BaseURL   string
	SessionID string
	EncKey    string
	Hash      string
	client    *http.Client
}

func New(name, ownerID, version, baseURL string) *Client {
	return &Client{
		Name:    name,
		OwnerID: ownerID,
		Version: version,
		BaseURL: strings.TrimRight(baseURL, "/") + "/",
		client:  &http.Client{Timeout: 30 * time.Second},
	}
}

func (c *Client) Init() (map[string]interface{}, error) {
	if c.EncKey == "" {
		c.EncKey = randHex(18)
		if len(c.EncKey) > 35 {
			c.EncKey = c.EncKey[:35]
		}
	}
	body := url.Values{
		"type":    {"init"},
		"name":    {c.Name},
		"ownerid": {c.OwnerID},
		"ver":     {c.Version},
		"enckey":  {c.EncKey},
	}
	if c.Hash != "" {
		body.Set("hash", c.Hash)
	}
	res, err := c.post(body)
	if err != nil {
		return nil, err
	}
	if ok, _ := res["success"].(bool); !ok {
		return nil, fmt.Errorf("%v", res["message"])
	}
	if sid, ok := res["sessionid"].(string); ok {
		c.SessionID = sid
	}
	return res, nil
}

func (c *Client) Login(user, pass, hwid string) (map[string]interface{}, error) {
	return c.auth(url.Values{
		"type":     {"login"},
		"username": {user},
		"pass":     {pass},
		"hwid":     {hwid},
	})
}

func (c *Client) License(key, hwid string) (map[string]interface{}, error) {
	return c.auth(url.Values{
		"type": {"license"},
		"key":  {key},
		"hwid": {hwid},
	})
}

func (c *Client) Register(user, pass, key, hwid string) (map[string]interface{}, error) {
	return c.auth(url.Values{
		"type":     {"register"},
		"username": {user},
		"pass":     {pass},
		"key":      {key},
		"hwid":     {hwid},
	})
}

func (c *Client) auth(extra url.Values) (map[string]interface{}, error) {
	res, err := c.post(extra)
	if err != nil {
		return nil, err
	}
	if ok, _ := res["success"].(bool); !ok {
		return nil, fmt.Errorf("%v", res["message"])
	}
	if info, ok := res["info"].(map[string]interface{}); ok {
		return info, nil
	}
	return res, nil
}

func (c *Client) post(extra url.Values) (map[string]interface{}, error) {
	extra.Set("name", c.Name)
	extra.Set("ownerid", c.OwnerID)
	if c.SessionID != "" {
		extra.Set("sessionid", c.SessionID)
	}
	req, err := http.NewRequest(http.MethodPost, c.BaseURL, strings.NewReader(extra.Encode()))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode == 429 {
		return nil, fmt.Errorf("rate limited")
	}
	raw, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	var out map[string]interface{}
	if err := json.Unmarshal(raw, &out); err != nil {
		return nil, err
	}
	return out, nil
}

func randHex(n int) string {
	const hex = "0123456789abcdef"
	b := make([]byte, n)
	for i := range b {
		b[i] = hex[time.Now().UnixNano()%16]
		time.Sleep(time.Nanosecond)
	}
	return string(b)
}