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() }