2025-03-09 15:52:33 -04:00
|
|
|
package network
|
2025-03-08 15:07:27 -05:00
|
|
|
|
|
|
|
import (
|
2025-03-10 10:29:54 -04:00
|
|
|
"crypto/ed25519"
|
2025-03-08 15:07:27 -05:00
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"strings"
|
|
|
|
|
2025-03-25 13:14:27 -04:00
|
|
|
"numenor-labs.us/dsfx/internal/lib/crypto/identity"
|
2025-03-08 15:07:27 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrInvalidFormat = errors.New("address must be in the format 'dsfx://<ip>:<port>#<publicKey>'")
|
|
|
|
)
|
|
|
|
|
|
|
|
// Addr is a wrapper around net.Addr that adds a public key to the address. This
|
|
|
|
// means that all connections between two nodes can be verified by their public
|
|
|
|
// keys.
|
|
|
|
type Addr struct {
|
|
|
|
network string
|
|
|
|
ip net.IP
|
|
|
|
port int
|
2025-03-10 10:29:54 -04:00
|
|
|
publicKey ed25519.PublicKey
|
2025-03-08 15:07:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewAddr creates a new Addr.
|
2025-03-10 10:29:54 -04:00
|
|
|
func NewAddr(ip net.IP, port int, publicKey ed25519.PublicKey) *Addr {
|
2025-03-08 15:07:27 -05:00
|
|
|
network := "dsfx"
|
|
|
|
return &Addr{network, ip, port, publicKey}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ParseAddr(addrRaw string) (*Addr, error) {
|
|
|
|
addrWoNet := strings.ReplaceAll(addrRaw, "dsfx://", "")
|
|
|
|
parts := strings.Split(addrWoNet, "#")
|
|
|
|
if len(parts) != 2 {
|
|
|
|
return nil, ErrInvalidFormat
|
|
|
|
}
|
|
|
|
|
|
|
|
addr := parts[0]
|
|
|
|
publicKeyBase64 := parts[1]
|
|
|
|
|
|
|
|
parts = strings.Split(addr, ":")
|
|
|
|
if len(parts) != 2 {
|
|
|
|
return nil, ErrInvalidFormat
|
|
|
|
}
|
|
|
|
ip := net.ParseIP(parts[0])
|
|
|
|
if ip == nil {
|
|
|
|
return nil, ErrInvalidFormat
|
|
|
|
}
|
|
|
|
|
|
|
|
port, err := net.LookupPort("tcp", parts[1])
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrInvalidFormat
|
|
|
|
}
|
|
|
|
|
|
|
|
publicKeyBytes, err := base64.StdEncoding.DecodeString(publicKeyBase64)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrInvalidFormat
|
|
|
|
}
|
|
|
|
|
2025-03-09 17:09:21 -04:00
|
|
|
publicKey, err := identity.ImportPublicKey(publicKeyBytes)
|
2025-03-08 15:07:27 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, ErrInvalidFormat
|
|
|
|
}
|
|
|
|
|
|
|
|
network := "dsfx"
|
|
|
|
return &Addr{network, ip, port, publicKey}, nil
|
|
|
|
}
|
|
|
|
|
2025-03-09 12:33:27 -04:00
|
|
|
// FromTCPAddr creates a new Addr from a net.TCPAddr.
|
2025-03-10 10:29:54 -04:00
|
|
|
func FromTCPAddr(addr *net.TCPAddr, publicKey ed25519.PublicKey) *Addr {
|
2025-03-09 12:33:27 -04:00
|
|
|
return &Addr{
|
|
|
|
network: "dsfx",
|
|
|
|
ip: addr.IP,
|
|
|
|
port: addr.Port,
|
|
|
|
publicKey: publicKey,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-08 15:07:27 -05:00
|
|
|
// Network implements net.Addr.
|
|
|
|
func (a *Addr) Network() string {
|
|
|
|
return a.network
|
|
|
|
}
|
|
|
|
|
|
|
|
// String implements net.Addr.
|
|
|
|
func (a *Addr) String() string {
|
2025-03-09 17:09:21 -04:00
|
|
|
exported, _ := identity.ExportPublicKey(a.publicKey)
|
2025-03-08 15:07:27 -05:00
|
|
|
exportedBase64 := base64.StdEncoding.EncodeToString(exported)
|
|
|
|
return fmt.Sprintf("%s://%s:%d#%s", a.network, a.ip, a.port, exportedBase64)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IP returns the IP address of the Addr.
|
|
|
|
func (a *Addr) IP() net.IP {
|
|
|
|
return a.ip
|
|
|
|
}
|
|
|
|
|
|
|
|
// Port returns the port of the Addr.
|
|
|
|
func (a *Addr) Port() int {
|
|
|
|
return a.port
|
|
|
|
}
|
|
|
|
|
|
|
|
// PublicKey returns the public key of the Addr.
|
2025-03-10 10:29:54 -04:00
|
|
|
func (a *Addr) PublicKey() ed25519.PublicKey {
|
2025-03-08 15:07:27 -05:00
|
|
|
return a.publicKey
|
|
|
|
}
|
2025-03-09 12:33:27 -04:00
|
|
|
|
|
|
|
// TCPAddr returns a net.TCPAddr for the Addr.
|
|
|
|
func (a *Addr) TCPAddr() *net.TCPAddr {
|
|
|
|
return &net.TCPAddr{
|
|
|
|
IP: a.ip,
|
|
|
|
Port: a.port,
|
|
|
|
}
|
|
|
|
}
|