WIP
This commit is contained in:
		| @@ -54,17 +54,11 @@ func (a *API) ensurePassword() error { | ||||
| 	log.Printf("Setting password: %s", pwd) | ||||
|  | ||||
| 	hashed, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	conf := &Config{ | ||||
| 		ConfigID:   1, | ||||
| 		VPNNetwork: []byte{10, 1, 1, 0}, | ||||
| 		Password:   hashed, | ||||
| 	} | ||||
|  | ||||
| 	conf := &Config{ConfigID: 1, Password: hashed} | ||||
| 	return db.Config_Insert(a.db, conf) | ||||
| } | ||||
|  | ||||
| @@ -80,10 +74,6 @@ func (a *API) Config_Update(conf *Config) error { | ||||
| 	return db.Config_Update(a.db, conf) | ||||
| } | ||||
|  | ||||
| func (a *API) Config_UpdatePassword(pwdHash []byte) error { | ||||
| 	return db.Config_UpdatePassword(a.db, pwdHash) | ||||
| } | ||||
|  | ||||
| func (a *API) Session_Delete(sessionID string) error { | ||||
| 	return db.Session_Delete(a.db, sessionID) | ||||
| } | ||||
| @@ -137,6 +127,24 @@ func (a *API) Session_SignIn(s *Session, pwd string) error { | ||||
| 	return db.Session_SetSignedIn(a.db, s.SessionID) | ||||
| } | ||||
|  | ||||
| func (a *API) Network_Create(n *Network) error { | ||||
| 	n.NetworkID = idgen.NextID(0) | ||||
| 	return db.Network_Insert(a.db, n) | ||||
| } | ||||
|  | ||||
| func (a *API) Network_Delete(n *Network) error { | ||||
| 	return db.Network_Delete(a.db, n.NetworkID) | ||||
| } | ||||
|  | ||||
| func (a *API) Network_Get(id int64) (*Network, error) { | ||||
| 	return db.Network_Get(a.db, id) | ||||
| } | ||||
|  | ||||
| func (a *API) Network_List() ([]*Network, error) { | ||||
| 	const query = db.Network_SelectQuery + ` ORDER BY Name ASC` | ||||
| 	return db.Network_List(a.db, query) | ||||
| } | ||||
|  | ||||
| func (a *API) Peer_CreateNew(p *Peer) error { | ||||
| 	p.Version = idgen.NextID(0) | ||||
| 	p.PubKey = []byte{} | ||||
| @@ -146,7 +154,7 @@ func (a *API) Peer_CreateNew(p *Peer) error { | ||||
| 	return db.Peer_Insert(a.db, p) | ||||
| } | ||||
|  | ||||
| func (a *API) Peer_Init(peer *Peer, args m.PeerInitArgs) (*m.PeerConfig, error) { | ||||
| func (a *API) Peer_Init(peer *Peer, args m.PeerInitArgs) error { | ||||
| 	a.lock.Lock() | ||||
| 	defer a.lock.Unlock() | ||||
|  | ||||
| @@ -154,19 +162,7 @@ func (a *API) Peer_Init(peer *Peer, args m.PeerInitArgs) (*m.PeerConfig, error) | ||||
| 	peer.PubKey = args.EncPubKey | ||||
| 	peer.PubSignKey = args.PubSignKey | ||||
|  | ||||
| 	if err := db.Peer_UpdateFull(a.db, peer); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	conf := a.Config_Get() | ||||
|  | ||||
| 	return &m.PeerConfig{ | ||||
| 		PeerIP:   peer.PeerIP, | ||||
| 		Network:  conf.VPNNetwork, | ||||
| 		PublicIP: peer.PublicIP, | ||||
| 		Port:     peer.Port, | ||||
| 		Relay:    peer.Relay, | ||||
| 	}, nil | ||||
| 	return db.Peer_UpdateFull(a.db, peer) | ||||
| } | ||||
|  | ||||
| func (a *API) Peer_Update(p *Peer) error { | ||||
| @@ -177,16 +173,16 @@ func (a *API) Peer_Update(p *Peer) error { | ||||
| 	return db.Peer_Update(a.db, p) | ||||
| } | ||||
|  | ||||
| func (a *API) Peer_Delete(ip byte) error { | ||||
| 	return db.Peer_Delete(a.db, ip) | ||||
| func (a *API) Peer_Delete(networkID int64, peerIP byte) error { | ||||
| 	return db.Peer_Delete(a.db, networkID, peerIP) | ||||
| } | ||||
|  | ||||
| func (a *API) Peer_List() ([]*Peer, error) { | ||||
| 	return db.Peer_ListAll(a.db) | ||||
| func (a *API) Peer_List(networkID int64) ([]*Peer, error) { | ||||
| 	return db.Peer_ListAll(a.db, networkID) | ||||
| } | ||||
|  | ||||
| func (a *API) Peer_Get(ip byte) (*Peer, error) { | ||||
| 	return db.Peer_Get(a.db, ip) | ||||
| func (a *API) Peer_Get(networkID int64, ip byte) (*Peer, error) { | ||||
| 	return db.Peer_Get(a.db, networkID, ip) | ||||
| } | ||||
|  | ||||
| func (a *API) Peer_GetByAPIKey(key string) (*Peer, error) { | ||||
|   | ||||
| @@ -16,13 +16,11 @@ type TX interface { | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| type Config struct { | ||||
| 	ConfigID   int64 | ||||
| 	HubAddress string | ||||
| 	VPNNetwork []byte | ||||
| 	Password   []byte | ||||
| 	ConfigID int64 | ||||
| 	Password []byte | ||||
| } | ||||
|  | ||||
| const Config_SelectQuery = "SELECT ConfigID,HubAddress,VPNNetwork,Password FROM config" | ||||
| const Config_SelectQuery = "SELECT ConfigID,Password FROM config" | ||||
|  | ||||
| func Config_Insert( | ||||
| 	tx TX, | ||||
| @@ -33,7 +31,7 @@ func Config_Insert( | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = tx.Exec("INSERT INTO config(ConfigID,HubAddress,VPNNetwork,Password) VALUES(?,?,?,?)", row.ConfigID, row.HubAddress, row.VPNNetwork, row.Password) | ||||
| 	_, err = tx.Exec("INSERT INTO config(ConfigID,Password) VALUES(?,?)", row.ConfigID, row.Password) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| @@ -46,7 +44,7 @@ func Config_Update( | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE config SET HubAddress=?,VPNNetwork=? WHERE ConfigID=?", row.HubAddress, row.VPNNetwork, row.ConfigID) | ||||
| 	result, err := tx.Exec("UPDATE config SET Password=? WHERE ConfigID=?", row.Password, row.ConfigID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -74,7 +72,7 @@ func Config_UpdateFull( | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE config SET HubAddress=?,VPNNetwork=?,Password=? WHERE ConfigID=?", row.HubAddress, row.VPNNetwork, row.Password, row.ConfigID) | ||||
| 	result, err := tx.Exec("UPDATE config SET Password=? WHERE ConfigID=?", row.Password, row.ConfigID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -124,8 +122,8 @@ func Config_Get( | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Config{} | ||||
| 	r := tx.QueryRow("SELECT ConfigID,HubAddress,VPNNetwork,Password FROM config WHERE ConfigID=?", ConfigID) | ||||
| 	err = r.Scan(&row.ConfigID, &row.HubAddress, &row.VPNNetwork, &row.Password) | ||||
| 	r := tx.QueryRow("SELECT ConfigID,Password FROM config WHERE ConfigID=?", ConfigID) | ||||
| 	err = r.Scan(&row.ConfigID, &row.Password) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -139,7 +137,7 @@ func Config_GetWhere( | ||||
| ) { | ||||
| 	row = &Config{} | ||||
| 	r := tx.QueryRow(query, args...) | ||||
| 	err = r.Scan(&row.ConfigID, &row.HubAddress, &row.VPNNetwork, &row.Password) | ||||
| 	err = r.Scan(&row.ConfigID, &row.Password) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -159,7 +157,7 @@ func Config_Iterate( | ||||
| 		defer rows.Close() | ||||
| 		for rows.Next() { | ||||
| 			row := &Config{} | ||||
| 			err := rows.Scan(&row.ConfigID, &row.HubAddress, &row.VPNNetwork, &row.Password) | ||||
| 			err := rows.Scan(&row.ConfigID, &row.Password) | ||||
| 			if !yield(row, err) { | ||||
| 				return | ||||
| 			} | ||||
| @@ -302,11 +300,156 @@ func Session_List( | ||||
| 	return l, nil | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Table: networks | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| type Network struct { | ||||
| 	NetworkID int64 | ||||
| 	Name      string | ||||
| 	Network   []byte | ||||
| } | ||||
|  | ||||
| const Network_SelectQuery = "SELECT NetworkID,Name,Network FROM networks" | ||||
|  | ||||
| func Network_Insert( | ||||
| 	tx TX, | ||||
| 	row *Network, | ||||
| ) (err error) { | ||||
| 	Network_Sanitize(row) | ||||
| 	if err = Network_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = tx.Exec("INSERT INTO networks(NetworkID,Name,Network) VALUES(?,?,?)", row.NetworkID, row.Name, row.Network) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Network_UpdateFull( | ||||
| 	tx TX, | ||||
| 	row *Network, | ||||
| ) (err error) { | ||||
| 	Network_Sanitize(row) | ||||
| 	if err = Network_Validate(row); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE networks SET Name=?,Network=? WHERE NetworkID=?", row.Name, row.Network, row.NetworkID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows updated") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Network_Delete( | ||||
| 	tx TX, | ||||
| 	NetworkID int64, | ||||
| ) (err error) { | ||||
| 	result, err := tx.Exec("DELETE FROM networks WHERE NetworkID=?", NetworkID) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	n, err := result.RowsAffected() | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	switch n { | ||||
| 	case 0: | ||||
| 		return sql.ErrNoRows | ||||
| 	case 1: | ||||
| 		return nil | ||||
| 	default: | ||||
| 		panic("multiple rows deleted") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Network_Get( | ||||
| 	tx TX, | ||||
| 	NetworkID int64, | ||||
| ) ( | ||||
| 	row *Network, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Network{} | ||||
| 	r := tx.QueryRow("SELECT NetworkID,Name,Network FROM networks WHERE NetworkID=?", NetworkID) | ||||
| 	err = r.Scan(&row.NetworkID, &row.Name, &row.Network) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Network_GetWhere( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	row *Network, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Network{} | ||||
| 	r := tx.QueryRow(query, args...) | ||||
| 	err = r.Scan(&row.NetworkID, &row.Name, &row.Network) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func Network_Iterate( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) iter.Seq2[*Network, error] { | ||||
| 	rows, err := tx.Query(query, args...) | ||||
| 	if err != nil { | ||||
| 		return func(yield func(*Network, error) bool) { | ||||
| 			yield(nil, err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return func(yield func(*Network, error) bool) { | ||||
| 		defer rows.Close() | ||||
| 		for rows.Next() { | ||||
| 			row := &Network{} | ||||
| 			err := rows.Scan(&row.NetworkID, &row.Name, &row.Network) | ||||
| 			if !yield(row, err) { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Network_List( | ||||
| 	tx TX, | ||||
| 	query string, | ||||
| 	args ...any, | ||||
| ) ( | ||||
| 	l []*Network, | ||||
| 	err error, | ||||
| ) { | ||||
| 	for row, err := range Network_Iterate(tx, query, args...) { | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		l = append(l, row) | ||||
| 	} | ||||
| 	return l, nil | ||||
| } | ||||
|  | ||||
| // ---------------------------------------------------------------------------- | ||||
| // Table: peers | ||||
| // ---------------------------------------------------------------------------- | ||||
|  | ||||
| type Peer struct { | ||||
| 	NetworkID  int64 | ||||
| 	PeerIP     byte | ||||
| 	Version    int64 | ||||
| 	APIKey     string | ||||
| @@ -318,7 +461,7 @@ type Peer struct { | ||||
| 	PubSignKey []byte | ||||
| } | ||||
|  | ||||
| const Peer_SelectQuery = "SELECT PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey FROM peers" | ||||
| const Peer_SelectQuery = "SELECT NetworkID,PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey FROM peers" | ||||
|  | ||||
| func Peer_Insert( | ||||
| 	tx TX, | ||||
| @@ -329,7 +472,7 @@ func Peer_Insert( | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	_, err = tx.Exec("INSERT INTO peers(PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey) VALUES(?,?,?,?,?,?,?,?,?)", row.PeerIP, row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey, row.PubSignKey) | ||||
| 	_, err = tx.Exec("INSERT INTO peers(NetworkID,PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey) VALUES(?,?,?,?,?,?,?,?,?,?)", row.NetworkID, row.PeerIP, row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey, row.PubSignKey) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| @@ -342,7 +485,7 @@ func Peer_Update( | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE peers SET Version=?,Name=?,PublicIP=?,Port=?,Relay=? WHERE PeerIP=?", row.Version, row.Name, row.PublicIP, row.Port, row.Relay, row.PeerIP) | ||||
| 	result, err := tx.Exec("UPDATE peers SET Version=?,Name=?,PublicIP=?,Port=?,Relay=? WHERE NetworkID=? AND PeerIP=?", row.Version, row.Name, row.PublicIP, row.Port, row.Relay, row.NetworkID, row.PeerIP) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -370,7 +513,7 @@ func Peer_UpdateFull( | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	result, err := tx.Exec("UPDATE peers SET Version=?,APIKey=?,Name=?,PublicIP=?,Port=?,Relay=?,PubKey=?,PubSignKey=? WHERE PeerIP=?", row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey, row.PubSignKey, row.PeerIP) | ||||
| 	result, err := tx.Exec("UPDATE peers SET Version=?,APIKey=?,Name=?,PublicIP=?,Port=?,Relay=?,PubKey=?,PubSignKey=? WHERE NetworkID=? AND PeerIP=?", row.Version, row.APIKey, row.Name, row.PublicIP, row.Port, row.Relay, row.PubKey, row.PubSignKey, row.NetworkID, row.PeerIP) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -391,9 +534,10 @@ func Peer_UpdateFull( | ||||
|  | ||||
| func Peer_Delete( | ||||
| 	tx TX, | ||||
| 	NetworkID int64, | ||||
| 	PeerIP byte, | ||||
| ) (err error) { | ||||
| 	result, err := tx.Exec("DELETE FROM peers WHERE PeerIP=?", PeerIP) | ||||
| 	result, err := tx.Exec("DELETE FROM peers WHERE NetworkID=? AND PeerIP=?", NetworkID, PeerIP) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -414,14 +558,15 @@ func Peer_Delete( | ||||
|  | ||||
| func Peer_Get( | ||||
| 	tx TX, | ||||
| 	NetworkID int64, | ||||
| 	PeerIP byte, | ||||
| ) ( | ||||
| 	row *Peer, | ||||
| 	err error, | ||||
| ) { | ||||
| 	row = &Peer{} | ||||
| 	r := tx.QueryRow("SELECT PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey FROM peers WHERE PeerIP=?", PeerIP) | ||||
| 	err = r.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey) | ||||
| 	r := tx.QueryRow("SELECT NetworkID,PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey FROM peers WHERE NetworkID=? AND PeerIP=?", NetworkID, PeerIP) | ||||
| 	err = r.Scan(&row.NetworkID, &row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -435,7 +580,7 @@ func Peer_GetWhere( | ||||
| ) { | ||||
| 	row = &Peer{} | ||||
| 	r := tx.QueryRow(query, args...) | ||||
| 	err = r.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey) | ||||
| 	err = r.Scan(&row.NetworkID, &row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -455,7 +600,7 @@ func Peer_Iterate( | ||||
| 		defer rows.Close() | ||||
| 		for rows.Next() { | ||||
| 			row := &Peer{} | ||||
| 			err := rows.Scan(&row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey) | ||||
| 			err := rows.Scan(&row.NetworkID, &row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey) | ||||
| 			if !yield(row, err) { | ||||
| 				return | ||||
| 			} | ||||
|   | ||||
| @@ -3,35 +3,21 @@ package db | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"net/netip" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	ErrInvalidIP   = errors.New("invalid IP") | ||||
| 	ErrInvalidPort = errors.New("invalid port") | ||||
| 	ErrInvalidIP       = errors.New("invalid IP") | ||||
| 	ErrNonPrivateIP    = errors.New("non-private IP") | ||||
| 	ErrInvalidPort     = errors.New("invalid port") | ||||
| 	ErrInvalidNetName  = errors.New("invalid network name") | ||||
| 	ErrInvalidPeerName = errors.New("invalid peer name") | ||||
| ) | ||||
|  | ||||
| func Config_Sanitize(c *Config) { | ||||
| 	if u, err := url.Parse(c.HubAddress); err == nil { | ||||
| 		c.HubAddress = u.String() | ||||
| 	} | ||||
|  | ||||
| 	if addr, ok := netip.AddrFromSlice(c.VPNNetwork); ok { | ||||
| 		c.VPNNetwork = addr.AsSlice() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Config_Validate(c *Config) error { | ||||
| 	if _, err := url.Parse(c.HubAddress); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	addr, ok := netip.AddrFromSlice(c.VPNNetwork) | ||||
| 	if !ok || !addr.Is4() || addr.As4()[3] != 0 || addr.As4()[0] == 0 { | ||||
| 		return ErrInvalidIP | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -42,6 +28,42 @@ func Session_Validate(s *Session) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func Network_Sanitize(n *Network) { | ||||
| 	n.Name = strings.TrimSpace(n.Name) | ||||
|  | ||||
| 	if addr, ok := netip.AddrFromSlice(n.Network); ok { | ||||
| 		n.Network = addr.AsSlice() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Network_Validate(c *Network) error { | ||||
| 	// 16 bytes is linux limit for network interface names. | ||||
| 	if len(c.Name) == 0 || len(c.Name) > 16 { | ||||
| 		return ErrInvalidNetName | ||||
| 	} | ||||
|  | ||||
| 	for _, c := range c.Name { | ||||
| 		if c >= 'a' && c <= 'z' { | ||||
| 			continue | ||||
| 		} | ||||
| 		if c >= '0' && c <= '9' { | ||||
| 			continue | ||||
| 		} | ||||
| 		return ErrInvalidNetName | ||||
| 	} | ||||
|  | ||||
| 	addr, ok := netip.AddrFromSlice(c.Network) | ||||
| 	if !ok || !addr.Is4() || addr.As4()[3] != 0 || addr.As4()[0] == 0 { | ||||
| 		return ErrInvalidIP | ||||
| 	} | ||||
|  | ||||
| 	if !addr.IsPrivate() { | ||||
| 		return ErrNonPrivateIP | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func Peer_Sanitize(p *Peer) { | ||||
| 	p.Name = strings.TrimSpace(p.Name) | ||||
| 	if len(p.PublicIP) != 0 { | ||||
| @@ -65,5 +87,20 @@ func Peer_Validate(p *Peer) error { | ||||
| 	if p.Port == 0 { | ||||
| 		return ErrInvalidPort | ||||
| 	} | ||||
|  | ||||
| 	for _, c := range p.Name { | ||||
| 		if c >= 'a' && c <= 'z' { | ||||
| 			continue | ||||
| 		} | ||||
| 		if c >= '0' && c <= '9' { | ||||
| 			continue | ||||
| 		} | ||||
| 		if c == '.' || c == '-' || c == '_' { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		return ErrInvalidPeerName | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| TABLE config OF Config ( | ||||
|   ConfigID    int64  PK, | ||||
|   HubAddress  string, | ||||
|   VPNNetwork  []byte, | ||||
|   Password    []byte NoUpdate | ||||
|   Password    []byte | ||||
| ); | ||||
|  | ||||
| TABLE sessions OF Session NoUpdate ( | ||||
| @@ -13,7 +11,14 @@ TABLE sessions OF Session NoUpdate ( | ||||
|   LastSeenAt int64 | ||||
| ); | ||||
|  | ||||
| TABLE networks OF Network ( | ||||
|   NetworkID int64 PK, | ||||
|   Name      string NoUpdate, | ||||
|   Network   []byte NoUpdate | ||||
| ); | ||||
|  | ||||
| TABLE peers OF Peer ( | ||||
|   NetworkID  int64 PK, | ||||
|   PeerIP     byte PK, | ||||
|   Version    int64, | ||||
|   APIKey     string NoUpdate, | ||||
|   | ||||
| @@ -26,16 +26,9 @@ func Session_DeleteBefore( | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Config_UpdatePassword( | ||||
| 	tx TX, | ||||
| 	pwdHash []byte, | ||||
| ) (err error) { | ||||
| 	_, err = tx.Exec("UPDATE config SET Password=? WHERE ConfigID=1", pwdHash) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func Peer_ListAll(tx TX) ([]*Peer, error) { | ||||
| 	return Peer_List(tx, Peer_SelectQuery) | ||||
| func Peer_ListAll(tx TX, networkID int64) ([]*Peer, error) { | ||||
| 	const query = Peer_SelectQuery + ` WHERE NetworkID=? ORDER BY PeerIP ASC` | ||||
| 	return Peer_List(tx, query, networkID) | ||||
| } | ||||
|  | ||||
| func Peer_GetByAPIKey(tx TX, apiKey string) (*Peer, error) { | ||||
| @@ -45,7 +38,8 @@ func Peer_GetByAPIKey(tx TX, apiKey string) (*Peer, error) { | ||||
| 		apiKey) | ||||
| } | ||||
|  | ||||
| func Peer_Exists(tx TX, ip byte) (exists bool, err error) { | ||||
| 	err = tx.QueryRow(`SELECT EXISTS(SELECT 1 FROM peers WHERE PeerIP=?)`, ip).Scan(&exists) | ||||
| func Peer_Exists(tx TX, networkID int64, ip byte) (exists bool, err error) { | ||||
| 	const query = `SELECT EXISTS(SELECT 1 FROM peers WHERE NetworkID=? AND PeerIP=?)` | ||||
| 	err = tx.QueryRow(query, networkID, ip).Scan(&exists) | ||||
| 	return | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| CREATE TABLE config ( | ||||
|   ConfigID    INTEGER NOT NULL PRIMARY KEY, -- Always 1. | ||||
|   HubAddress  TEXT    NOT NULL, -- https://for.example.com | ||||
|   VPNNetwork  BLOB    NOT NULL, -- Network (/24), example 10.51.50.0 | ||||
|   Password    BLOB    NOT NULL  -- bcrypt password for web interface | ||||
| ) WITHOUT ROWID; | ||||
|  | ||||
| @@ -15,13 +13,22 @@ CREATE TABLE sessions ( | ||||
|  | ||||
| CREATE INDEX sessions_last_seen_index ON sessions(LastSeenAt); | ||||
|  | ||||
| CREATE TABLE networks ( | ||||
|   NetworkID   INTEGER NOT NULL PRIMARY KEY, | ||||
|   Name        TEXT    NOT NULL UNIQUE, -- Network/interface name. | ||||
|   Network     BLOB    NOT NULL UNIQUE  -- Network (/24), example 10.51.50.0 | ||||
| ) WITHOUT ROWID; | ||||
|  | ||||
| CREATE TABLE peers ( | ||||
|   PeerIP     INTEGER NOT NULL PRIMARY KEY, -- Final byte. | ||||
|   Version    INTEGER NOT NULL, | ||||
|   APIKey     TEXT    NOT NULL UNIQUE, | ||||
|   NetworkID  INTEGER NOT NULL, | ||||
|   PeerIP     INTEGER NOT NULL,             -- Final byte of IP. | ||||
|   Version    INTEGER NOT NULL,             -- Changes when updated. | ||||
|   APIKey     TEXT    NOT NULL UNIQUE,      -- Peer's secret API key. | ||||
|   Name       TEXT    NOT NULL UNIQUE,      -- For humans. | ||||
|   PublicIP   BLOB    NOT NULL, | ||||
|   Port       INTEGER NOT NULL, | ||||
|   Relay      INTEGER NOT NULL DEFAULT 0,   -- Boolean if peer will forward packets. Must also have public address. | ||||
|   PubKey     BLOB    NOT NULL | ||||
|   PubKey     BLOB    NOT NULL, | ||||
|   PubSignKey BLOB    NOT NULL, | ||||
|   PRIMARY KEY(NetworkID, PeerIP) | ||||
| ) WITHOUT ROWID; | ||||
|   | ||||
| @@ -1 +0,0 @@ | ||||
| ALTER TABLE peers ADD COLUMN PubSignKey BLOB NOT NULL DEFAULT ''; | ||||
| @@ -4,4 +4,5 @@ import "vppn/hub/api/db" | ||||
|  | ||||
| type Config = db.Config | ||||
| type Session = db.Session | ||||
| type Network = db.Network | ||||
| type Peer = db.Peer | ||||
|   | ||||
		Reference in New Issue
	
	Block a user