mirror of
https://git.numenor-labs.us/dsfx.git
synced 2025-04-29 16:20:34 +00:00
98 lines
2.1 KiB
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
|
||
|
}
|