215 lines
4.7 KiB
Go
215 lines
4.7 KiB
Go
package sdk
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
type Config struct {
|
|
ControllerURL string
|
|
Token string
|
|
PSK string
|
|
NetworkID uint32
|
|
ListenPort int
|
|
TapName string
|
|
TapMTU int
|
|
IdentityPath string
|
|
HTTPTimeout time.Duration
|
|
}
|
|
|
|
func DefaultConfig() Config {
|
|
return Config{
|
|
ControllerURL: "http://127.0.0.1:10001",
|
|
ListenPort: 0,
|
|
TapName: "zeromesh0",
|
|
TapMTU: 2800,
|
|
IdentityPath: "./data/agent.identity",
|
|
HTTPTimeout: 30 * time.Second,
|
|
}
|
|
}
|
|
|
|
type Client struct {
|
|
cfg Config
|
|
httpc *http.Client
|
|
identity *Identity
|
|
}
|
|
|
|
func New(cfg Config) *Client {
|
|
if cfg.HTTPTimeout == 0 {
|
|
cfg.HTTPTimeout = 30 * time.Second
|
|
}
|
|
if cfg.TapName == "" {
|
|
cfg.TapName = "zeromesh0"
|
|
}
|
|
if cfg.TapMTU == 0 {
|
|
cfg.TapMTU = 2800
|
|
}
|
|
if cfg.IdentityPath == "" {
|
|
cfg.IdentityPath = "./data/agent.identity"
|
|
}
|
|
return &Client{
|
|
cfg: cfg,
|
|
httpc: &http.Client{
|
|
Timeout: cfg.HTTPTimeout,
|
|
Transport: &http.Transport{
|
|
MaxIdleConns: 10,
|
|
IdleConnTimeout: 60 * time.Second,
|
|
DisableCompression: false,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (c *Client) Config() Config { return c.cfg }
|
|
func (c *Client) HTTPClient() *http.Client { return c.httpc }
|
|
func (c *Client) Identity() *Identity { return c.identity }
|
|
func (c *Client) SetToken(tok string) { c.cfg.Token = tok }
|
|
func (c *Client) Token() string { return c.cfg.Token }
|
|
|
|
type Address [5]byte
|
|
|
|
func (a Address) String() string { return hex.EncodeToString(a[:]) }
|
|
|
|
func AddressFromPublicKey(pub []byte) Address {
|
|
var a Address
|
|
h := hashBytes(pub)
|
|
copy(a[:], h[:5])
|
|
return a
|
|
}
|
|
|
|
type Identity struct {
|
|
PublicKey ed25519.PublicKey
|
|
PrivateKey ed25519.PrivateKey
|
|
Address Address
|
|
}
|
|
|
|
func GenerateIdentity() *Identity {
|
|
pub, priv, err := ed25519.GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return &Identity{
|
|
PublicKey: pub,
|
|
PrivateKey: priv,
|
|
Address: AddressFromPublicKey(pub),
|
|
}
|
|
}
|
|
|
|
func (id *Identity) PublicKeyHex() string { return hex.EncodeToString(id.PublicKey) }
|
|
func (id *Identity) PrivateKeyHex() string { return hex.EncodeToString(id.PrivateKey) }
|
|
|
|
func hashBytes(data []byte) []byte {
|
|
h := make([]byte, 32)
|
|
for i, b := range data {
|
|
h[i%32] ^= b
|
|
}
|
|
for round := 0; round < 3; round++ {
|
|
for i := 0; i < 32; i++ {
|
|
h[i] = h[i] ^ h[(i+1)%32] ^ h[(i+7)%32]
|
|
h[i] = (h[i] << 3) | (h[i] >> 5)
|
|
}
|
|
}
|
|
return h
|
|
}
|
|
|
|
type AuthResponse struct {
|
|
Token string `json:"token"`
|
|
User *User `json:"user"`
|
|
}
|
|
|
|
type User struct {
|
|
ID uint `json:"id"`
|
|
Username string `json:"username"`
|
|
Role string `json:"role"`
|
|
QuotaNetworks int `json:"quota_networks"`
|
|
QuotaNodes int `json:"quota_nodes"`
|
|
}
|
|
|
|
type Network struct {
|
|
ID uint `json:"id"`
|
|
NetworkID uint32 `json:"network_id"`
|
|
UserID uint `json:"user_id"`
|
|
Name string `json:"name"`
|
|
IPRange string `json:"ip_range"`
|
|
MTU int `json:"mtu"`
|
|
Private bool `json:"private"`
|
|
Members []NetworkMember `json:"members,omitempty"`
|
|
}
|
|
|
|
type NetworkMember struct {
|
|
ID uint `json:"id"`
|
|
NetworkID uint32 `json:"network_id"`
|
|
NodeID string `json:"node_id"`
|
|
IPAddress string `json:"ip_address"`
|
|
Authorized bool `json:"authorized"`
|
|
Label string `json:"label"`
|
|
}
|
|
|
|
type Node struct {
|
|
ID uint `json:"id"`
|
|
UserID uint `json:"user_id"`
|
|
NodeID string `json:"node_id"`
|
|
PublicKey string `json:"public_key"`
|
|
Name string `json:"name"`
|
|
IPAddress string `json:"ip_address"`
|
|
Port int `json:"port"`
|
|
Online bool `json:"online"`
|
|
LastSeen *string `json:"last_seen"`
|
|
Version string `json:"version"`
|
|
}
|
|
|
|
type DashboardStats struct {
|
|
AuthorizedMembers int `json:"authorized_members"`
|
|
NodesTotal int `json:"nodes_total"`
|
|
NodesOnline int `json:"nodes_online"`
|
|
NetworksCount int `json:"networks_count"`
|
|
}
|
|
|
|
type NetworkListResponse struct {
|
|
Networks []Network `json:"networks"`
|
|
}
|
|
|
|
type NodeListResponse struct {
|
|
Nodes []Node `json:"nodes"`
|
|
}
|
|
|
|
type MembersResponse struct {
|
|
Members []NetworkMember `json:"members"`
|
|
}
|
|
|
|
type ProfileResponse struct {
|
|
User User `json:"user"`
|
|
UsedNetworks int `json:"used_networks"`
|
|
UsedNodes int `json:"used_nodes"`
|
|
}
|
|
|
|
func (a Address) MarshalText() ([]byte, error) {
|
|
return []byte(a.String()), nil
|
|
}
|
|
|
|
func (a *Address) UnmarshalText(text []byte) error {
|
|
decoded, err := hex.DecodeString(string(text))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(decoded) != 5 {
|
|
return err
|
|
}
|
|
copy(a[:], decoded)
|
|
return nil
|
|
}
|
|
|
|
func GetPreferredIP() string {
|
|
conn, err := net.Dial("udp", "8.8.8.8:80")
|
|
if err != nil {
|
|
return "0.0.0.0"
|
|
}
|
|
defer conn.Close()
|
|
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
|
return localAddr.IP.String()
|
|
}
|