package hub import ( "encoding/json" "errors" "log" "net/http" "net/netip" "strings" "vppn/hub/api" "vppn/m" "git.crumpington.com/lib/go/webutil" "golang.org/x/crypto/bcrypt" ) func (a *App) _root(s *api.Session, w http.ResponseWriter, r *http.Request) error { if s.SignedIn { return a.redirect(w, r, "/admin/network/list/") } else { return a.redirect(w, r, "/sign-in/") } } func (a *App) _signin(s *api.Session, w http.ResponseWriter, r *http.Request) error { return a.render("/sign-in.html", w, struct{ Session *api.Session }{s}) } func (a *App) _signinSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var pwd string err := webutil.NewFormScanner(r.Form). Scan("Password", &pwd). Error() if err != nil { return err } if err := a.api.Session_SignIn(s, pwd); err != nil { return err } return a.redirect(w, r, "/") } func (a *App) _adminSignOut(s *api.Session, w http.ResponseWriter, r *http.Request) error { return a.render("/admin-sign-out.html", w, struct{ Session *api.Session }{s}) } func (a *App) _adminSignOutSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { if err := a.api.Session_Delete(s.SessionID); err != nil { log.Printf("Failed to delete session cookie %s: %v", s.SessionID, err) } a.deleteCookie(w, SESSION_ID_COOKIE_NAME) return a.redirect(w, r, "/") } func (a *App) _adminNetworkList(s *api.Session, w http.ResponseWriter, r *http.Request) error { l, err := a.api.Network_List() if err != nil { return err } return a.render("/admin-network-list.html", w, struct { Session *api.Session Networks []*api.Network }{s, l}) } func (a *App) _adminNetworkCreate(s *api.Session, w http.ResponseWriter, r *http.Request) error { return a.render("/admin-network-create.html", w, struct{ Session *api.Session }{s}) } func (a *App) _adminNetworkCreateSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { n := &api.Network{} var netStr string err := webutil.NewFormScanner(r.Form). Scan("Name", &n.Name). Scan("Network", &netStr). Error() if err != nil { return err } n.Network, err = stringToIP(netStr) if err != nil { return err } if err := a.api.Network_Create(n); err != nil { return err } return a.redirect(w, r, "/admin/network/view/?NetworkID=%d", n.NetworkID) } func (a *App) _adminNetworkView(s *api.Session, w http.ResponseWriter, r *http.Request) error { n, peers, err := a.formGetNetworkPeers(r.Form) if err != nil { return err } return a.render("/network/network-view.html", w, struct { Session *api.Session Network *api.Network Peers []*api.Peer }{s, n, peers}) } func (a *App) _adminNetworkDelete(s *api.Session, w http.ResponseWriter, r *http.Request) error { n, peers, err := a.formGetNetworkPeers(r.Form) if err != nil { return err } return a.render("/network/network-delete.html", w, struct { Session *api.Session Network *api.Network Peers []*api.Peer }{s, n, peers}) } func (a *App) _adminNetworkDeleteSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { n, err := a.formGetNetwork(r.Form) if err != nil { return err } if err = a.api.Network_Delete(n); err != nil { return err } return a.redirect(w, r, "/admin/network/list/") } func (a *App) _adminPeerCreate(s *api.Session, w http.ResponseWriter, r *http.Request) error { n, err := a.formGetNetwork(r.Form) if err != nil { return err } return a.render("/network/peer-create.html", w, struct { Session *api.Session Network *api.Network }{s, n}) } func (a *App) _adminPeerCreateSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var ipStr 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("Relay", &p.Relay). Error() if err != nil { return err } if p.PublicIP, err = stringToIP(ipStr); err != nil { return err } if err := a.api.Peer_CreateNew(p); err != nil { return err } return a.redirect(w, r, "/admin/peer/view/?NetworkID=%d&PeerIP=%d", p.NetworkID, p.PeerIP) } func (a *App) _adminPeerView(s *api.Session, w http.ResponseWriter, r *http.Request) error { net, peer, err := a.formGetPeer(r.Form) if err != nil { return err } return a.render("/network/peer-view.html", w, struct { Session *api.Session Network *api.Network Peer *api.Peer }{s, net, peer}) } func (a *App) _adminPeerEdit(s *api.Session, w http.ResponseWriter, r *http.Request) error { net, peer, err := a.formGetPeer(r.Form) if err != nil { return err } return a.render("/network/peer-edit.html", w, struct { Session *api.Session Network *api.Network Peer *api.Peer }{s, net, peer}) } func (a *App) _adminPeerEditSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { _, peer, err := a.formGetPeer(r.Form) if err != nil { return err } var ipStr string err = webutil.NewFormScanner(r.Form). Scan("Name", &peer.Name). Scan("PublicIP", &ipStr). Scan("Port", &peer.Port). Scan("Relay", &peer.Relay). Error() if err != nil { return err } if peer.PublicIP, err = stringToIP(ipStr); err != nil { return err } if err = a.api.Peer_Update(peer); err != nil { return err } return a.redirect(w, r, "/admin/peer/view/?NetworkID=%d&PeerIP=%d", peer.NetworkID, peer.PeerIP) } func (a *App) _adminPeerDelete(s *api.Session, w http.ResponseWriter, r *http.Request) error { n, peer, err := a.formGetPeer(r.Form) if err != nil { return err } return a.render("/network/peer-delete.html", w, struct { Session *api.Session Network *api.Network Peer *api.Peer }{s, n, peer}) } func (a *App) _adminPeerDeleteSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { n, peer, err := a.formGetPeer(r.Form) if err != nil { return err } if err := a.api.Peer_Delete(n.NetworkID, peer.PeerIP); err != nil { return err } return a.redirect(w, r, "/admin/network/view/?NetworkID=%d", n.NetworkID) } func (a *App) _adminNetworkHosts(s *api.Session, w http.ResponseWriter, r *http.Request) error { n, peers, err := a.formGetNetworkPeers(r.Form) if err != nil { return err } b := strings.Builder{} for _, peer := range peers { ip := n.Network ip[3] = peer.PeerIP b.WriteString(netip.AddrFrom4([4]byte(ip)).String()) b.WriteString(" ") b.WriteString(peer.Name) b.WriteString("\n") } w.Write([]byte(b.String())) return nil } func (a *App) _adminPasswordEdit(s *api.Session, w http.ResponseWriter, r *http.Request) error { return a.render("/admin-password-edit.html", w, struct{ Session *api.Session }{s}) } func (a *App) _adminPasswordSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var ( conf = a.api.Config_Get() curPwd string newPwd string newPwd2 string ) err := webutil.NewFormScanner(r.Form). Scan("CurrentPassword", &curPwd). Scan("NewPassword", &newPwd). Scan("NewPassword2", &newPwd2). Error() if err != nil { return err } if len(newPwd) < 8 { return errors.New("password is too short") } if newPwd != newPwd2 { return errors.New("passwords don't match") } err = bcrypt.CompareHashAndPassword(conf.Password, []byte(curPwd)) if err != nil { return err } hash, err := bcrypt.GenerateFromPassword([]byte(newPwd), bcrypt.DefaultCost) if err != nil { return err } conf.Password = hash if err := a.api.Config_Update(conf); err != nil { return err } return a.redirect(w, r, "/admin/config/") } func (a *App) _peerInit(peer *api.Peer, w http.ResponseWriter, r *http.Request) error { args := m.PeerInitArgs{} if err := json.NewDecoder(r.Body).Decode(&args); err != nil { return err } net, err := a.api.Network_Get(peer.NetworkID) if err != nil { return err } if err := a.api.Peer_Init(peer, args); err != nil { return err } resp := m.PeerInitResp{ PeerIP: peer.PeerIP, Network: net.Network, } resp.NetworkState.Peers, err = a.peersArray(net.NetworkID) if err != nil { return err } return a.sendJSON(w, resp) } func (a *App) _peerFetchState(peer *api.Peer, w http.ResponseWriter, r *http.Request) error { peers, err := a.peersArray(peer.NetworkID) if err != nil { return err } return a.sendJSON(w, m.NetworkState{Peers: peers}) } func (a *App) peersArray(networkID int64) (peers [256]*m.Peer, err error) { l, err := a.api.Peer_List(networkID) if err != nil { return peers, err } for _, p := range l { if len(p.PubKey) != 0 { peers[p.PeerIP] = &m.Peer{ PeerIP: p.PeerIP, Version: p.Version, Name: p.Name, PublicIP: p.PublicIP, Port: p.Port, Relay: p.Relay, PubKey: p.PubKey, PubSignKey: p.PubSignKey, } } } return }