package hub import ( "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/config/") } 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) _adminConfig(s *api.Session, w http.ResponseWriter, r *http.Request) error { return a.render("/admin-config.html", w, struct { Session *api.Session Config *api.Config }{ s, a.api.Config_Get(), }) } func (a *App) _adminConfigEdit(s *api.Session, w http.ResponseWriter, r *http.Request) error { return a.render("/admin-config-edit.html", w, struct { Session *api.Session Config *api.Config }{ s, a.api.Config_Get(), }) } func (a *App) _adminConfigEditSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var ( conf = a.api.Config_Get() ipStr string ) err := webutil.NewFormScanner(r.Form). Scan("HubAddress", &conf.HubAddress). Scan("VPNNetwork", &ipStr). Error() if err != nil { return err } if conf.VPNNetwork, err = stringToIP(ipStr); err != nil { return err } if err := a.api.Config_Update(conf); err != nil { return err } return a.redirect(w, r, "/admin/config/") } 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 } if err := a.api.Config_UpdatePassword(hash); err != nil { return err } return a.redirect(w, r, "/admin/config/") } func (a *App) _adminPeerList(s *api.Session, w http.ResponseWriter, r *http.Request) error { peers, err := a.api.Peer_List() if err != nil { return err } return a.render("/admin-peer-list.html", w, struct { Session *api.Session Peers []*api.Peer }{ s, peers, }) } func (a *App) _adminHosts(s *api.Session, w http.ResponseWriter, r *http.Request) error { conf := a.api.Config_Get() peers, err := a.api.Peer_List() if err != nil { return err } b := strings.Builder{} for _, peer := range peers { ip := conf.VPNNetwork 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) _adminPeerCreate(s *api.Session, w http.ResponseWriter, r *http.Request) error { return a.render("/admin-peer-create.html", w, struct{ Session *api.Session }{s}) } func (a *App) _adminPeerCreateSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var ipStr string args := api.PeerCreateArgs{} err := webutil.NewFormScanner(r.Form). Scan("Name", &args.Name). Scan("PublicIP", &ipStr). Scan("Port", &args.Port). Scan("Relay", &args.Relay). Error() if err != nil { return err } if args.PublicIP, err = stringToIP(ipStr); err != nil { return err } code := a.api.Peer_CreateIntent(args) return a.redirect(w, r, "/admin/peer/intent-created/?Code=%s", code) } func (a *App) _adminPeerIntentCreated(s *api.Session, w http.ResponseWriter, r *http.Request) error { code := r.FormValue("Code") if code == "" { return errors.New("missing Code") } return a.render("/admin-peer-intent.html", w, struct { Session *api.Session HubAddress string Code string }{s, a.api.Config_Get().HubAddress, code}) } func (a *App) _adminPeerView(s *api.Session, w http.ResponseWriter, r *http.Request) error { var peerIP byte err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error() if err != nil { return err } peer, err := a.api.Peer_Get(peerIP) if err != nil { return err } return a.render("/admin-peer-view.html", w, struct { Session *api.Session Peer *api.Peer }{s, peer}) } func (a *App) _adminPeerEdit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var peerIP byte err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error() if err != nil { return err } peer, err := a.api.Peer_Get(peerIP) if err != nil { return err } return a.render("/admin-peer-edit.html", w, struct { Session *api.Session Peer *api.Peer }{s, peer}) } func (a *App) _adminPeerEditSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var ( peerIP byte ipStr string ) err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error() if err != nil { return err } peer, err := a.api.Peer_Get(peerIP) if err != nil { return err } 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/?PeerIP=%d", peer.PeerIP) } func (a *App) _adminPeerDelete(s *api.Session, w http.ResponseWriter, r *http.Request) error { var peerIP byte err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error() if err != nil { return err } peer, err := a.api.Peer_Get(peerIP) if err != nil { return err } return a.render("/admin-peer-delete.html", w, struct { Session *api.Session Peer *api.Peer }{s, peer}) } func (a *App) _adminPeerDeleteSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { var peerIP byte err := webutil.NewFormScanner(r.Form).Scan("PeerIP", &peerIP).Error() if err != nil { return err } if err := a.api.Peer_Delete(peerIP); err != nil { return err } return a.redirect(w, r, "/admin/peer/list/") } func (a *App) _peerCreate(w http.ResponseWriter, r *http.Request) error { code := r.FormValue("Code") conf, err := a.api.Peer_Create(code) if err != nil { return err } return a.sendJSON(w, conf) } func (a *App) _peerFetchState(w http.ResponseWriter, r *http.Request) error { _, apiKey, ok := r.BasicAuth() if !ok { return api.ErrNotAuthorized } peer, err := a.api.Peer_GetByAPIKey(apiKey) if err != nil { return err } peers, err := a.api.Peer_List() if err != nil { return err } conf := a.api.Config_Get() state := m.NetworkState{ HubAddress: conf.HubAddress, Network: conf.VPNNetwork, PeerIP: peer.PeerIP, PublicIP: peer.PublicIP, Port: peer.Port, } for _, p := range peers { state.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, } } return a.sendJSON(w, state) }