dsfx/shared/dnet/addr.go

98 lines
2.1 KiB
Go

package dnet
import (
"crypto/ecdsa"
"encoding/base64"
"errors"
"fmt"
"net"
"strings"
"koti.casa/numenor-labs/dsfx/shared/dcrypto"
)
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
publicKey *ecdsa.PublicKey
}
// NewAddr creates a new Addr.
func NewAddr(ip net.IP, port int, publicKey *ecdsa.PublicKey) *Addr {
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
}
publicKey, err := dcrypto.ImportPublicSigningKey(publicKeyBytes)
if err != nil {
return nil, ErrInvalidFormat
}
network := "dsfx"
return &Addr{network, ip, port, publicKey}, nil
}
// Network implements net.Addr.
func (a *Addr) Network() string {
return a.network
}
// String implements net.Addr.
func (a *Addr) String() string {
exported, _ := dcrypto.ExportPublicSigningKey(a.publicKey)
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.
func (a *Addr) PublicKey() *ecdsa.PublicKey {
return a.publicKey
}