This commit is contained in:
jdl
2026-06-04 16:00:21 +02:00
parent 5ae075647d
commit 8b2c9709fc
22 changed files with 217 additions and 317 deletions

View File

@@ -21,6 +21,8 @@ var migrations embed.FS
type API struct {
db *sql.DB
lock sync.Mutex
sessionsMu sync.Mutex
sessions map[string]*Session
}
func New(dbPath string) (*API, error) {
@@ -35,6 +37,7 @@ func New(dbPath string) (*API, error) {
a := &API{
db: sqlDB,
sessions: make(map[string]*Session),
}
return a, a.ensurePassword()
@@ -75,47 +78,41 @@ func (a *API) Config_Update(conf *Config) error {
}
func (a *API) Session_Delete(sessionID string) error {
return db.Session_Delete(a.db, sessionID)
a.sessionsMu.Lock()
defer a.sessionsMu.Unlock()
delete(a.sessions, sessionID)
return nil
}
func (a *API) Session_Get(sessionID string) (*Session, error) {
if sessionID == "" {
return a.session_CreatePub()
}
a.sessionsMu.Lock()
defer a.sessionsMu.Unlock()
session, err := db.Session_Get(a.db, sessionID)
if err != nil {
return a.session_CreatePub()
if sessionID != "" {
s, ok := a.sessions[sessionID]
if ok {
if timeSince(s.LastSeenAt) <= 86400*21 {
if timeSince(s.LastSeenAt) > 86400*7 {
s.LastSeenAt = time.Now().Unix()
}
if timeSince(session.LastSeenAt) > 86400*21 {
return a.session_CreatePub()
return s, nil
}
if timeSince(session.LastSeenAt) > 86400*7 {
session.LastSeenAt = time.Now().Unix()
if err := db.Session_UpdateLastSeenAt(a.db, session.SessionID); err != nil {
log.Printf("Failed to update session: %v", err)
delete(a.sessions, sessionID)
}
}
return session, nil
return a.session_Create(), nil
}
func (a *API) session_CreatePub() (*Session, error) {
// caller must hold sessionsMu
func (a *API) session_Create() *Session {
s := &Session{
SessionID: idgen.NewToken(),
CSRF: idgen.NewToken(),
SignedIn: false,
CreatedAt: time.Now().Unix(),
LastSeenAt: time.Now().Unix(),
}
err := db.Session_Insert(a.db, s)
return s, err
}
func (a *API) Session_DeleteBefore(timestamp int64) error {
return db.Session_DeleteBefore(a.db, timestamp)
a.sessions[s.SessionID] = s
return s
}
func (a *API) Session_SignIn(s *Session, pwd string) error {
@@ -123,8 +120,10 @@ func (a *API) Session_SignIn(s *Session, pwd string) error {
if err := bcrypt.CompareHashAndPassword(conf.Password, []byte(pwd)); err != nil {
return ErrNotAuthorized
}
return db.Session_SetSignedIn(a.db, s.SessionID)
a.sessionsMu.Lock()
s.SignedIn = true
a.sessionsMu.Unlock()
return nil
}
func (a *API) Network_Create(n *Network) error {
@@ -147,8 +146,7 @@ func (a *API) Network_List() ([]*Network, error) {
func (a *API) Peer_CreateNew(p *Peer) error {
p.Version = idgen.NextID(0)
p.PubKey = []byte{}
p.PubSignKey = []byte{}
p.WGPubKey = []byte{}
p.APIKey = idgen.NewToken()
return db.Peer_Insert(a.db, p)
@@ -159,8 +157,7 @@ func (a *API) Peer_Init(peer *Peer, args m.PeerInitArgs) error {
defer a.lock.Unlock()
peer.Version = idgen.NextID(0)
peer.PubKey = args.EncPubKey
peer.PubSignKey = args.PubSignKey
peer.WGPubKey = args.WGPubKey
return db.Peer_UpdateFull(a.db, peer)
}

View File

@@ -123,7 +123,9 @@ func Config_Get(
) {
row = &Config{}
r := tx.QueryRow("SELECT ConfigID,Password FROM config WHERE ConfigID=?", ConfigID)
err = r.Scan(&row.ConfigID, &row.Password)
if err = r.Scan(&row.ConfigID, &row.Password); err != nil {
row = nil
}
return
}
@@ -137,7 +139,9 @@ func Config_GetWhere(
) {
row = &Config{}
r := tx.QueryRow(query, args...)
err = r.Scan(&row.ConfigID, &row.Password)
if err = r.Scan(&row.ConfigID, &row.Password); err != nil {
row = nil
}
return
}
@@ -182,124 +186,6 @@ func Config_List(
return l, nil
}
// ----------------------------------------------------------------------------
// Table: sessions
// ----------------------------------------------------------------------------
type Session struct {
SessionID string
CSRF string
SignedIn bool
CreatedAt int64
LastSeenAt int64
}
const Session_SelectQuery = "SELECT SessionID,CSRF,SignedIn,CreatedAt,LastSeenAt FROM sessions"
func Session_Insert(
tx TX,
row *Session,
) (err error) {
Session_Sanitize(row)
if err = Session_Validate(row); err != nil {
return err
}
_, err = tx.Exec("INSERT INTO sessions(SessionID,CSRF,SignedIn,CreatedAt,LastSeenAt) VALUES(?,?,?,?,?)", row.SessionID, row.CSRF, row.SignedIn, row.CreatedAt, row.LastSeenAt)
return err
}
func Session_Delete(
tx TX,
SessionID string,
) (err error) {
result, err := tx.Exec("DELETE FROM sessions WHERE SessionID=?", SessionID)
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 Session_Get(
tx TX,
SessionID string,
) (
row *Session,
err error,
) {
row = &Session{}
r := tx.QueryRow("SELECT SessionID,CSRF,SignedIn,CreatedAt,LastSeenAt FROM sessions WHERE SessionID=?", SessionID)
err = r.Scan(&row.SessionID, &row.CSRF, &row.SignedIn, &row.CreatedAt, &row.LastSeenAt)
return
}
func Session_GetWhere(
tx TX,
query string,
args ...any,
) (
row *Session,
err error,
) {
row = &Session{}
r := tx.QueryRow(query, args...)
err = r.Scan(&row.SessionID, &row.CSRF, &row.SignedIn, &row.CreatedAt, &row.LastSeenAt)
return
}
func Session_Iterate(
tx TX,
query string,
args ...any,
) iter.Seq2[*Session, error] {
rows, err := tx.Query(query, args...)
if err != nil {
return func(yield func(*Session, error) bool) {
yield(nil, err)
}
}
return func(yield func(*Session, error) bool) {
defer rows.Close()
for rows.Next() {
row := &Session{}
err := rows.Scan(&row.SessionID, &row.CSRF, &row.SignedIn, &row.CreatedAt, &row.LastSeenAt)
if !yield(row, err) {
return
}
}
}
}
func Session_List(
tx TX,
query string,
args ...any,
) (
l []*Session,
err error,
) {
for row, err := range Session_Iterate(tx, query, args...) {
if err != nil {
return nil, err
}
l = append(l, row)
}
return l, nil
}
// ----------------------------------------------------------------------------
// Table: networks
// ----------------------------------------------------------------------------
@@ -385,7 +271,9 @@ func Network_Get(
) {
row = &Network{}
r := tx.QueryRow("SELECT NetworkID,Name,Network FROM networks WHERE NetworkID=?", NetworkID)
err = r.Scan(&row.NetworkID, &row.Name, &row.Network)
if err = r.Scan(&row.NetworkID, &row.Name, &row.Network); err != nil {
row = nil
}
return
}
@@ -399,7 +287,9 @@ func Network_GetWhere(
) {
row = &Network{}
r := tx.QueryRow(query, args...)
err = r.Scan(&row.NetworkID, &row.Name, &row.Network)
if err = r.Scan(&row.NetworkID, &row.Name, &row.Network); err != nil {
row = nil
}
return
}
@@ -454,14 +344,15 @@ type Peer struct {
Version int64
APIKey string
Name string
PublicIP []byte
Port uint16
PublicIP1 []byte
Port1 uint16
PublicIP2 []byte
Port2 uint16
Relay bool
PubKey []byte
PubSignKey []byte
WGPubKey []byte
}
const Peer_SelectQuery = "SELECT NetworkID,PeerIP,Version,APIKey,Name,PublicIP,Port,Relay,PubKey,PubSignKey FROM peers"
const Peer_SelectQuery = "SELECT NetworkID,PeerIP,Version,APIKey,Name,PublicIP1,Port1,PublicIP2,Port2,Relay,WGPubKey FROM peers"
func Peer_Insert(
tx TX,
@@ -472,7 +363,7 @@ func Peer_Insert(
return err
}
_, 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)
_, err = tx.Exec("INSERT INTO peers(NetworkID,PeerIP,Version,APIKey,Name,PublicIP1,Port1,PublicIP2,Port2,Relay,WGPubKey) VALUES(?,?,?,?,?,?,?,?,?,?,?)", row.NetworkID, row.PeerIP, row.Version, row.APIKey, row.Name, row.PublicIP1, row.Port1, row.PublicIP2, row.Port2, row.Relay, row.WGPubKey)
return err
}
@@ -485,7 +376,7 @@ func Peer_Update(
return err
}
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)
result, err := tx.Exec("UPDATE peers SET Version=?,Name=?,PublicIP1=?,Port1=?,PublicIP2=?,Port2=?,Relay=? WHERE NetworkID=? AND PeerIP=?", row.Version, row.Name, row.PublicIP1, row.Port1, row.PublicIP2, row.Port2, row.Relay, row.NetworkID, row.PeerIP)
if err != nil {
return err
}
@@ -513,7 +404,7 @@ func Peer_UpdateFull(
return err
}
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)
result, err := tx.Exec("UPDATE peers SET Version=?,APIKey=?,Name=?,PublicIP1=?,Port1=?,PublicIP2=?,Port2=?,Relay=?,WGPubKey=? WHERE NetworkID=? AND PeerIP=?", row.Version, row.APIKey, row.Name, row.PublicIP1, row.Port1, row.PublicIP2, row.Port2, row.Relay, row.WGPubKey, row.NetworkID, row.PeerIP)
if err != nil {
return err
}
@@ -565,8 +456,10 @@ func Peer_Get(
err error,
) {
row = &Peer{}
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)
r := tx.QueryRow("SELECT NetworkID,PeerIP,Version,APIKey,Name,PublicIP1,Port1,PublicIP2,Port2,Relay,WGPubKey FROM peers WHERE NetworkID=? AND PeerIP=?", NetworkID, PeerIP)
if err = r.Scan(&row.NetworkID, &row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP1, &row.Port1, &row.PublicIP2, &row.Port2, &row.Relay, &row.WGPubKey); err != nil {
row = nil
}
return
}
@@ -580,7 +473,9 @@ func Peer_GetWhere(
) {
row = &Peer{}
r := tx.QueryRow(query, args...)
err = r.Scan(&row.NetworkID, &row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP, &row.Port, &row.Relay, &row.PubKey, &row.PubSignKey)
if err = r.Scan(&row.NetworkID, &row.PeerIP, &row.Version, &row.APIKey, &row.Name, &row.PublicIP1, &row.Port1, &row.PublicIP2, &row.Port2, &row.Relay, &row.WGPubKey); err != nil {
row = nil
}
return
}
@@ -600,7 +495,7 @@ func Peer_Iterate(
defer rows.Close()
for rows.Next() {
row := &Peer{}
err := rows.Scan(&row.NetworkID, &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.PublicIP1, &row.Port1, &row.PublicIP2, &row.Port2, &row.Relay, &row.WGPubKey)
if !yield(row, err) {
return
}

View File

@@ -21,13 +21,6 @@ func Config_Validate(c *Config) error {
return nil
}
func Session_Sanitize(s *Session) {
}
func Session_Validate(s *Session) error {
return nil
}
func Network_Sanitize(n *Network) {
n.Name = strings.TrimSpace(n.Name)
@@ -66,25 +59,39 @@ func Network_Validate(c *Network) error {
func Peer_Sanitize(p *Peer) {
p.Name = strings.TrimSpace(p.Name)
if len(p.PublicIP) != 0 {
addr, ok := netip.AddrFromSlice(p.PublicIP)
if ok && addr.Is4() {
p.PublicIP = addr.AsSlice()
if len(p.PublicIP1) != 0 {
if addr, ok := netip.AddrFromSlice(p.PublicIP1); ok {
p.PublicIP1 = addr.AsSlice()
}
}
if p.Port == 0 {
p.Port = 456
if len(p.PublicIP2) != 0 {
if addr, ok := netip.AddrFromSlice(p.PublicIP2); ok {
p.PublicIP2 = addr.AsSlice()
}
}
if p.Port1 == 0 {
p.Port1 = 456
}
if len(p.PublicIP2) != 0 && p.Port2 == 0 {
p.Port2 = 456
}
}
func Peer_Validate(p *Peer) error {
if len(p.PublicIP) > 0 {
_, ok := netip.AddrFromSlice(p.PublicIP)
if !ok {
if len(p.PublicIP1) > 0 {
if _, ok := netip.AddrFromSlice(p.PublicIP1); !ok {
return ErrInvalidIP
}
}
if p.Port == 0 {
if len(p.PublicIP2) > 0 {
if _, ok := netip.AddrFromSlice(p.PublicIP2); !ok {
return ErrInvalidIP
}
if p.Port2 == 0 {
return ErrInvalidPort
}
}
if p.Port1 == 0 {
return ErrInvalidPort
}
@@ -98,7 +105,6 @@ func Peer_Validate(p *Peer) error {
if c == '.' || c == '-' || c == '_' {
continue
}
return ErrInvalidPeerName
}

View File

@@ -3,14 +3,6 @@ TABLE config OF Config (
Password []byte
);
TABLE sessions OF Session NoUpdate (
SessionID string PK,
CSRF string,
SignedIn bool,
CreatedAt int64,
LastSeenAt int64
);
TABLE networks OF Network (
NetworkID int64 PK,
Name string NoUpdate,
@@ -23,9 +15,10 @@ TABLE peers OF Peer (
Version int64,
APIKey string NoUpdate,
Name string,
PublicIP []byte,
Port uint16,
PublicIP1 []byte,
Port1 uint16,
PublicIP2 []byte,
Port2 uint16,
Relay bool,
PubKey []byte NoUpdate,
PubSignKey []byte NoUpdate
WGPubKey []byte NoUpdate
);

View File

@@ -1,31 +1,5 @@
package db
import "time"
func Session_UpdateLastSeenAt(
tx TX,
id string,
) (err error) {
_, err = tx.Exec("UPDATE sessions SET LastSeenAt=? WHERE SessionID=?", time.Now().Unix(), id)
return err
}
func Session_SetSignedIn(
tx TX,
id string,
) (err error) {
_, err = tx.Exec("UPDATE sessions SET SignedIn=1 WHERE SessionID=?", id)
return err
}
func Session_DeleteBefore(
tx TX,
timestamp int64,
) (err error) {
_, err = tx.Exec("DELETE FROM sessions WHERE LastSeenAt<?", timestamp)
return err
}
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)

View File

@@ -3,16 +3,6 @@ CREATE TABLE config (
Password BLOB NOT NULL -- bcrypt password for web interface
) WITHOUT ROWID;
CREATE TABLE sessions (
SessionID TEXT NOT NULL PRIMARY KEY,
CSRF TEXT NOT NULL,
SignedIn INTEGER NOT NULL,
CreatedAt INTEGER NOT NULL,
LastSeenAt INTEGER NOT NULL
) WITHOUT ROWID;
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.
@@ -25,10 +15,11 @@ CREATE TABLE peers (
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,
PubSignKey BLOB NOT NULL,
PublicIP1 BLOB NOT NULL,
Port1 INTEGER NOT NULL,
PublicIP2 BLOB NOT NULL,
Port2 INTEGER NOT NULL,
Relay INTEGER NOT NULL DEFAULT 0, -- Boolean if peer will forward packets.
WGPubKey BLOB NOT NULL,
PRIMARY KEY(NetworkID, PeerIP)
) WITHOUT ROWID;

View File

@@ -3,6 +3,12 @@ package api
import "vppn/hub/api/db"
type Config = db.Config
type Session = db.Session
type Network = db.Network
type Peer = db.Peer
type Session struct {
SessionID string
SignedIn bool
CreatedAt int64
LastSeenAt int64
}

View File

@@ -2,6 +2,7 @@ package hub
import (
"embed"
"encoding/base64"
"html/template"
"net/http"
"path/filepath"
@@ -47,6 +48,19 @@ func NewApp(conf Config) (*App, error) {
return app, nil
}
func (app *App) Handler() http.Handler {
cop := http.NewCrossOriginProtection()
return cop.Handler(app.mux)
}
var templateFuncs = template.FuncMap{
"ipToString": ipBytesTostring,
"wgKeyString": wgKeyString,
}
func wgKeyString(key []byte) string {
if len(key) == 0 {
return "not set"
}
return base64.StdEncoding.EncodeToString(key)
}

View File

@@ -26,11 +26,6 @@ func (app *App) handlePub(pattern string, fn handlerFunc) {
if r.Method == http.MethodPost {
r.ParseMultipartForm(64 * 1024)
if r.FormValue("CSRF") != s.CSRF {
log.Printf("%s != %s", r.FormValue("CSRF"), s.CSRF)
http.Error(w, "CSRF mismatch", http.StatusBadRequest)
return
}
} else {
r.ParseForm()
}

View File

@@ -142,22 +142,27 @@ func (a *App) _adminPeerCreate(s *api.Session, w http.ResponseWriter, r *http.Re
}
func (a *App) _adminPeerCreateSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error {
var ipStr string
var ip1Str, ip2Str string
p := &api.Peer{}
err := webutil.NewFormScanner(r.Form).
Scan("NetworkID", &p.NetworkID).
Scan("IP", &p.PeerIP).
Scan("Name", &p.Name).
Scan("PublicIP", &ipStr).
Scan("Port", &p.Port).
Scan("PublicIP1", &ip1Str).
Scan("Port1", &p.Port1).
Scan("PublicIP2", &ip2Str).
Scan("Port2", &p.Port2).
Scan("Relay", &p.Relay).
Error()
if err != nil {
return err
}
if p.PublicIP, err = stringToIP(ipStr); err != nil {
if p.PublicIP1, err = stringToIP(ip1Str); err != nil {
return err
}
if p.PublicIP2, err = stringToIP(ip2Str); err != nil {
return err
}
@@ -199,19 +204,24 @@ func (a *App) _adminPeerEditSubmit(s *api.Session, w http.ResponseWriter, r *htt
return err
}
var ipStr string
var ip1Str, ip2Str string
err = webutil.NewFormScanner(r.Form).
Scan("Name", &peer.Name).
Scan("PublicIP", &ipStr).
Scan("Port", &peer.Port).
Scan("PublicIP1", &ip1Str).
Scan("Port1", &peer.Port1).
Scan("PublicIP2", &ip2Str).
Scan("Port2", &peer.Port2).
Scan("Relay", &peer.Relay).
Error()
if err != nil {
return err
}
if peer.PublicIP, err = stringToIP(ipStr); err != nil {
if peer.PublicIP1, err = stringToIP(ip1Str); err != nil {
return err
}
if peer.PublicIP2, err = stringToIP(ip2Str); err != nil {
return err
}
@@ -295,6 +305,11 @@ func (a *App) _adminPasswordSubmit(s *api.Session, w http.ResponseWriter, r *htt
}
func (a *App) _peerInit(peer *api.Peer, w http.ResponseWriter, r *http.Request) error {
if len(peer.WGPubKey) != 0 {
http.Error(w, "Already initialized", http.StatusConflict)
return nil
}
args := m.PeerInitArgs{}
if err := json.NewDecoder(r.Body).Decode(&args); err != nil {
return err
@@ -338,16 +353,17 @@ func (a *App) peersArray(networkID int64) (peers [256]*m.Peer, err error) {
}
for _, p := range l {
if len(p.PubKey) != 0 {
if len(p.WGPubKey) != 0 {
peers[p.PeerIP] = &m.Peer{
PeerIP: p.PeerIP,
Version: p.Version,
Name: p.Name,
PublicIP: p.PublicIP,
Port: p.Port,
PublicIP1: p.PublicIP1,
Port1: p.Port1,
PublicIP2: p.PublicIP2,
Port2: p.Port2,
Relay: p.Relay,
PubKey: p.PubKey,
PubSignKey: p.PubSignKey,
WGPubKey: p.WGPubKey,
}
}
}

View File

@@ -31,7 +31,7 @@ func Main() {
srv := &http.Server{
Addr: conf.ListenAddr,
Handler: app.mux,
Handler: app.Handler(),
}
log.Fatal(webutil.ListenAndServe(srv))

View File

@@ -2,7 +2,6 @@
<h2>Create Network</h2>
<form method="POST">
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
<p>
<label>Name</label><br>
<input type="text" name="Name">

View File

@@ -2,7 +2,6 @@
<h2>Change Password</h2>
<form method="POST">
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
<p>
<label>Current Password</label><br>
<input type="password" name="CurrentPassword">

View File

@@ -2,7 +2,6 @@
<h2>Sign Out</h2>
<form method="POST">
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
<p>
<button type="submit">Sign Out</button>
<a href="/">Cancel</a>

View File

@@ -5,7 +5,6 @@
<p>You must first delete all peers.</p>
{{- else -}}
<form method="POST">
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
<input type="hidden" name="NetworkID" value="{{.Network.NetworkID}}">
<p>
<button type="submit">Delete</button>

View File

@@ -22,8 +22,10 @@
<tr>
<th>PeerIP</th>
<th>Name</th>
<th>Public IP</th>
<th>Port</th>
<th>Public IP 1</th>
<th>Port 1</th>
<th>Public IP 2</th>
<th>Port 2</th>
<th>Relay</th>
</tr>
</thead>
@@ -36,8 +38,10 @@
</a>
</td>
<td>{{.Name}}</td>
<td>{{ipToString .PublicIP}}</td>
<td>{{.Port}}</td>
<td>{{ipToString .PublicIP1}}</td>
<td>{{.Port1}}</td>
<td>{{ipToString .PublicIP2}}</td>
<td>{{.Port2}}</td>
<td>{{if .Relay}}T{{else}}F{{end}}</td>
</tr>
</tbody>

View File

@@ -2,7 +2,6 @@
<h3>New Peer</h3>
<form method="POST">
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
<input type="hidden" name="NetworkID" value="{{.Network.NetworkID}}">
<p>
<label>IP</label><br>
@@ -13,12 +12,20 @@
<input type="text" name="Name">
</p>
<p>
<label>Public IP</label><br>
<input type="text" name="PublicIP">
<label>Public IP 1</label><br>
<input type="text" name="PublicIP1">
</p>
<p>
<label>Port</label><br>
<input type="number" name="Port" value="456">
<label>Port 1</label><br>
<input type="number" name="Port1" value="456">
</p>
<p>
<label>Public IP 2 (optional)</label><br>
<input type="text" name="PublicIP2">
</p>
<p>
<label>Port 2</label><br>
<input type="number" name="Port2" value="0">
</p>
<p>
<label>

View File

@@ -3,7 +3,6 @@
{{with .Peer -}}
<form method="POST">
<input type="hidden" name="CSRF" value="{{$.Session.CSRF}}">
<input type="hidden" name="NetworkID" value="{{.NetworkID}}">
<input type="hidden" name="NetworkID" value="{{.PeerIP}}">
<p>

View File

@@ -3,7 +3,6 @@
{{with .Peer -}}
<form method="POST">
<input type="hidden" name="CSRF" value="{{$.Session.CSRF}}">
<p>
<label>Peer IP</label><br>
<input type="text" value="{{.PeerIP}}" disabled>
@@ -13,12 +12,20 @@
<input type="text" name="Name" value="{{.Name}}">
</p>
<p>
<label>Public IP</label><br>
<input type="text" name="PublicIP" value="{{ipToString .PublicIP}}">
<label>Public IP 1</label><br>
<input type="text" name="PublicIP1" value="{{ipToString .PublicIP1}}">
</p>
<p>
<label>Port</label><br>
<input type="number" name="Port" value="{{.Port}}">
<label>Port 1</label><br>
<input type="number" name="Port1" value="{{.Port1}}">
</p>
<p>
<label>Public IP 2 (optional)</label><br>
<input type="text" name="PublicIP2" value="{{ipToString .PublicIP2}}">
</p>
<p>
<label>Port 2</label><br>
<input type="number" name="Port2" value="{{.Port2}}">
</p>
<p>
<label>

View File

@@ -8,10 +8,12 @@
{{with .Peer -}}
<table class="def-list">
<tr><td>Peer IP</td><td>{{.PeerIP}}</td></tr>
<tr><td>Public IP</td><td>{{ipToString .PublicIP}}</td></tr>
<tr><td>Port</td><td>{{.Port}}</td></tr>
<tr><td>Public IP 1</td><td>{{ipToString .PublicIP1}}</td></tr>
<tr><td>Port 1</td><td>{{.Port1}}</td></tr>
<tr><td>Public IP 2</td><td>{{ipToString .PublicIP2}}</td></tr>
<tr><td>Port 2</td><td>{{.Port2}}</td></tr>
<tr><td>Relay</td><td>{{if .Relay}}T{{else}}F{{end}}</td></tr>
</td></tr>
<tr><td>WG Public Key</td><td>{{wgKeyString .WGPubKey}}</td></tr>
</table>
<details>
@@ -19,7 +21,6 @@
<p>{{.APIKey}}</p>
</details>
{{- end}}
{{- end}}

View File

@@ -2,7 +2,6 @@
<h2>Sign In</h2>
<form method="POST">
<input type="hidden" name="CSRF" value="{{.Session.CSRF}}">
<p>
<label>Password</label><br>
<input type="password" name="Password">

View File

@@ -2,8 +2,7 @@
package m
type PeerInitArgs struct {
EncPubKey []byte
PubSignKey []byte
WGPubKey []byte
}
type PeerInitResp struct {
@@ -16,11 +15,12 @@ type Peer struct {
PeerIP byte
Version int64
Name string
PublicIP []byte
Port uint16
PublicIP1 []byte
Port1 uint16
PublicIP2 []byte
Port2 uint16
Relay bool
PubKey []byte
PubSignKey []byte
WGPubKey []byte
}
type NetworkState struct {