WIP
This commit is contained in:
@@ -80,7 +80,11 @@ func (a *API) Session_Delete(sessionID string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) Session_Get(sessionID string) (*Session, error) {
|
// Session_Get returns a snapshot copy of the session for sessionID (creating a
|
||||||
|
// fresh one if absent/expired). Returning a value rather than the stored
|
||||||
|
// pointer prevents callers from racing on the shared struct; mutations go
|
||||||
|
// through Session_SignIn / Session_Delete under the lock.
|
||||||
|
func (a *API) Session_Get(sessionID string) (Session, error) {
|
||||||
a.sessionsMu.Lock()
|
a.sessionsMu.Lock()
|
||||||
defer a.sessionsMu.Unlock()
|
defer a.sessionsMu.Unlock()
|
||||||
|
|
||||||
@@ -91,13 +95,13 @@ func (a *API) Session_Get(sessionID string) (*Session, error) {
|
|||||||
if timeSince(s.LastSeenAt) > 86400*7 {
|
if timeSince(s.LastSeenAt) > 86400*7 {
|
||||||
s.LastSeenAt = time.Now().Unix()
|
s.LastSeenAt = time.Now().Unix()
|
||||||
}
|
}
|
||||||
return s, nil
|
return *s, nil
|
||||||
}
|
}
|
||||||
delete(a.sessions, sessionID)
|
delete(a.sessions, sessionID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.session_Create(), nil
|
return *a.session_Create(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// caller must hold sessionsMu
|
// caller must hold sessionsMu
|
||||||
@@ -111,7 +115,7 @@ func (a *API) session_Create() *Session {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) Session_SignIn(s *Session, pwd string) error {
|
func (a *API) Session_SignIn(sessionID, pwd string) error {
|
||||||
conf, err := a.Config_Get()
|
conf, err := a.Config_Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -120,8 +124,13 @@ func (a *API) Session_SignIn(s *Session, pwd string) error {
|
|||||||
return ErrNotAuthorized
|
return ErrNotAuthorized
|
||||||
}
|
}
|
||||||
a.sessionsMu.Lock()
|
a.sessionsMu.Lock()
|
||||||
|
defer a.sessionsMu.Unlock()
|
||||||
|
s, ok := a.sessions[sessionID]
|
||||||
|
if !ok {
|
||||||
|
// Session expired or was evicted between fetch and sign-in.
|
||||||
|
return ErrNotAuthorized
|
||||||
|
}
|
||||||
s.SignedIn = true
|
s.SignedIn = true
|
||||||
a.sessionsMu.Unlock()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func (app *App) handlePub(pattern string, fn handlerFunc) {
|
|||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fn(s, w, r); err != nil {
|
if err := fn(&s, w, r); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func (a *App) _signinSubmit(s *api.Session, w http.ResponseWriter, r *http.Reque
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.api.Session_SignIn(s, pwd); err != nil {
|
if err := a.api.Session_SignIn(s.SessionID, pwd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (a *App) devAddDirect(p *Peer, endpoint netip.AddrPort) {
|
|||||||
func (a *App) devSetRelay(p *Peer, endpoint netip.AddrPort) {
|
func (a *App) devSetRelay(p *Peer, endpoint netip.AddrPort) {
|
||||||
log.Printf("RELAY: %s - %s @ %s", p.Name, p.VPNIP.String(), endpoint.String())
|
log.Printf("RELAY: %s - %s @ %s", p.Name, p.VPNIP.String(), endpoint.String())
|
||||||
devRetry(p.VPNIP, "SetRelay", func() error { return a.dev.SetRelay(p.PubKey(), endpoint, a.vpnNet) })
|
devRetry(p.VPNIP, "SetRelay", func() error { return a.dev.SetRelay(p.PubKey(), endpoint, a.vpnNet) })
|
||||||
p.State = StateDirect
|
p.State = StateDirect // Dirrect connection. The app marks peer as relay.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) devPromote(p *Peer) {
|
func (a *App) devPromote(p *Peer) {
|
||||||
|
|||||||
@@ -14,10 +14,18 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
hostsFile = "/etc/hosts"
|
hostsFile = "/etc/hosts"
|
||||||
hostsBegin = "# BEGIN vppn "
|
hostsBegin = "# BEGIN vppn"
|
||||||
hostsEnd = "# END vppn "
|
hostsEnd = "# END vppn"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// hostMarkers returns the begin/end marker lines that delimit the managed
|
||||||
|
// section for localDomain. The domain is wrapped in parentheses so one domain's
|
||||||
|
// marker can never be a prefix of another's (e.g. "net" vs "net2") when
|
||||||
|
// multiple vppn instances share /etc/hosts.
|
||||||
|
func hostMarkers(localDomain string) (begin, end string) {
|
||||||
|
return hostsBegin + "(" + localDomain + ")", hostsEnd + "(" + localDomain + ")"
|
||||||
|
}
|
||||||
|
|
||||||
// updateHosts rewrites the managed vppn section in /etc/hosts using the
|
// updateHosts rewrites the managed vppn section in /etc/hosts using the
|
||||||
// current peersByIP map. Peers without a Name are skipped.
|
// current peersByIP map. Peers without a Name are skipped.
|
||||||
func (a *App) updateHosts() {
|
func (a *App) updateHosts() {
|
||||||
@@ -36,8 +44,7 @@ func updateHosts(hostsPath, localDomain string, peers map[netip.Addr]*Peer) erro
|
|||||||
}
|
}
|
||||||
defer lockFile.Close()
|
defer lockFile.Close()
|
||||||
|
|
||||||
begin := hostsBegin + localDomain
|
begin, end := hostMarkers(localDomain)
|
||||||
end := hostsEnd + localDomain
|
|
||||||
|
|
||||||
info, err := os.Stat(hostsPath)
|
info, err := os.Stat(hostsPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ func readManagedSection(t *testing.T, path, localDomain string) (inside, outside
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
begin := hostsBegin + localDomain
|
begin, end := hostMarkers(localDomain)
|
||||||
end := hostsEnd + localDomain
|
|
||||||
|
|
||||||
inSection := false
|
inSection := false
|
||||||
for _, line := range strings.Split(string(raw), "\n") {
|
for _, line := range strings.Split(string(raw), "\n") {
|
||||||
@@ -157,6 +156,45 @@ func TestUpdateHosts_Idempotent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestUpdateHosts_PrefixDomainsCoexist guards finding 4.4: two domains where
|
||||||
|
// one label is a prefix of the other ("net" vs "net2") must each manage their
|
||||||
|
// own section without clobbering the other's, even sharing one hosts file.
|
||||||
|
func TestUpdateHosts_PrefixDomainsCoexist(t *testing.T) {
|
||||||
|
path := writeTempHosts(t, "127.0.0.1 localhost\n")
|
||||||
|
|
||||||
|
if err := updateHosts(path, "net2.local", map[netip.Addr]*Peer{
|
||||||
|
netip.MustParseAddr("10.0.2.1"): peer("a"),
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := updateHosts(path, "net.local", map[netip.Addr]*Peer{
|
||||||
|
netip.MustParseAddr("10.0.1.1"): peer("b"),
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Both sections coexist after writing the prefix domain.
|
||||||
|
if in, _ := readManagedSection(t, path, "net2.local"); len(in) != 1 || in[0] != "10.0.2.1 a.net2.local" {
|
||||||
|
t.Errorf("net2 section clobbered: %v", in)
|
||||||
|
}
|
||||||
|
if in, _ := readManagedSection(t, path, "net.local"); len(in) != 1 || in[0] != "10.0.1.1 b.net.local" {
|
||||||
|
t.Errorf("net section wrong: %v", in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-updating net2 must not disturb the net section.
|
||||||
|
if err := updateHosts(path, "net2.local", map[netip.Addr]*Peer{
|
||||||
|
netip.MustParseAddr("10.0.2.2"): peer("c"),
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if in, _ := readManagedSection(t, path, "net.local"); len(in) != 1 || in[0] != "10.0.1.1 b.net.local" {
|
||||||
|
t.Errorf("net section disturbed by net2 update: %v", in)
|
||||||
|
}
|
||||||
|
if in, _ := readManagedSection(t, path, "net2.local"); len(in) != 1 || in[0] != "10.0.2.2 c.net2.local" {
|
||||||
|
t.Errorf("net2 section not updated: %v", in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func contains(ss []string, s string) bool {
|
func contains(ss []string, s string) bool {
|
||||||
for _, x := range ss {
|
for _, x := range ss {
|
||||||
if x == s {
|
if x == s {
|
||||||
|
|||||||
Reference in New Issue
Block a user