getSession retrieves the browser session associated with the request, if one exists. An error is returned in any of the following cases: - (errNotUsingTailscale) The request was not made over tailscale. - (errNoSession) The request does not have a session. - (errTaggedRemoteSource) The source is
(r *http.Request)
| 107 | // The WhoIsResponse is always populated, with a non-nil Node and UserProfile, |
| 108 | // unless getTailscaleBrowserSession reports errNotUsingTailscale. |
| 109 | func (s *Server) getSession(r *http.Request) (*browserSession, *apitype.WhoIsResponse, *ipnstate.Status, error) { |
| 110 | whoIs, whoIsErr := s.lc.WhoIs(r.Context(), r.RemoteAddr) |
| 111 | status, statusErr := s.lc.StatusWithoutPeers(r.Context()) |
| 112 | switch { |
| 113 | case whoIsErr != nil: |
| 114 | return nil, nil, status, errNotUsingTailscale |
| 115 | case statusErr != nil: |
| 116 | return nil, whoIs, nil, statusErr |
| 117 | case status.Self == nil: |
| 118 | return nil, whoIs, status, errors.New("missing self node in tailscale status") |
| 119 | case whoIs.Node.IsTagged() && whoIs.Node.StableID == status.Self.ID: |
| 120 | return nil, whoIs, status, errTaggedLocalSource |
| 121 | case whoIs.Node.IsTagged(): |
| 122 | return nil, whoIs, status, errTaggedRemoteSource |
| 123 | case !status.Self.IsTagged() && status.Self.UserID != whoIs.UserProfile.ID: |
| 124 | return nil, whoIs, status, errNotOwner |
| 125 | } |
| 126 | srcNode := whoIs.Node.ID |
| 127 | srcUser := whoIs.UserProfile.ID |
| 128 | |
| 129 | cookie, err := r.Cookie(sessionCookieName) |
| 130 | if errors.Is(err, http.ErrNoCookie) { |
| 131 | return nil, whoIs, status, errNoSession |
| 132 | } else if err != nil { |
| 133 | return nil, whoIs, status, err |
| 134 | } |
| 135 | v, ok := s.browserSessions.Load(cookie.Value) |
| 136 | if !ok { |
| 137 | return nil, whoIs, status, errNoSession |
| 138 | } |
| 139 | session := v.(*browserSession) |
| 140 | if session.SrcNode != srcNode || session.SrcUser != srcUser { |
| 141 | // In this case the browser cookie is associated with another tailscale node. |
| 142 | // Maybe the source browser's machine was logged out and then back in as a different node. |
| 143 | // Return errNoSession because there is no session for this user. |
| 144 | return nil, whoIs, status, errNoSession |
| 145 | } else if session.isExpired(s.timeNow()) { |
| 146 | // Session expired, remove from session map and return errNoSession. |
| 147 | s.browserSessions.Delete(session.ID) |
| 148 | return nil, whoIs, status, errNoSession |
| 149 | } |
| 150 | return session, whoIs, status, nil |
| 151 | } |
| 152 | |
| 153 | // newSession creates a new session associated with the given source user/node, |
| 154 | // and stores it back to the session cache. Creating of a new session includes |