Files
zeromesh/sdk/sdk.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()
}