Yōten: A social tracker for your language learning journey built on the atproto.

fix: redirect user to return_url after login #41

merged opened by brookjeynes.dev targeting master from push-wxwkxoqvlknp
Labels

None yet.

Participants 1
AT URI
at://did:plc:4mj54vc4ha3lh32ksxwunnbh/sh.tangled.repo.pull/3memszvv53g22
+77 -15
Diff #0
+5
internal/server/handlers/login.go
··· 26 26 }).Render(r.Context(), w) 27 27 case http.MethodPost: 28 28 handle := r.FormValue("handle") 29 + returnURL := r.FormValue("return_url") 29 30 30 31 // When users copy their handle from bsky.app, it tends to have these 31 32 // characters around it: ··· 63 64 } 64 65 } 65 66 67 + if err := h.Oauth.SetAuthReturn(w, r, returnURL); err != nil { 68 + l.Error("failed to set auth return", "err", err) 69 + } 70 + 66 71 redirectURL, err := h.Oauth.ClientApp.StartAuthFlow(r.Context(), handle) 67 72 if err != nil { 68 73 l.Error("failed to resolve auth flow", "handle", handle, "err", err)
+6 -9
internal/server/handlers/router.go
··· 167 167 168 168 r.Use(mw.LoadUnreadNotificationCount()) 169 169 170 - r.Group(func(r chi.Router) { 171 - r.Use(mw.ResolveIdent()) 172 - r.Route("/{user}", func(r chi.Router) { 173 - r.Get("/", h.HandleProfilePage) 174 - r.Get("/feed", h.HandleProfileFeed) 175 - r.Route("/session/{rkey}", func(r chi.Router) { 176 - r.Get("/", h.HandleStudySessionPage) 177 - r.Get("/feed", h.HandleStudySessionPageCommentFeed) 178 - }) 170 + r.With(mw.ResolveIdent()).Route("/{user}", func(r chi.Router) { 171 + r.Get("/", h.HandleProfilePage) 172 + r.Get("/feed", h.HandleProfileFeed) 173 + r.Route("/session/{rkey}", func(r chi.Router) { 174 + r.Get("/", h.HandleStudySessionPage) 175 + r.Get("/feed", h.HandleStudySessionPageCommentFeed) 179 176 }) 180 177 }) 181 178
+1 -1
internal/server/handlers/static.go
··· 84 84 }` 85 85 86 86 func (h *Handler) PWAManifest(w http.ResponseWriter, r *http.Request) { 87 - w.Header().Set("Content-Type", "application/json") 87 + w.Header().Set("Content-Type", "application/manifest+json") 88 88 w.Write([]byte(manifestJson)) 89 89 }
+9 -4
internal/server/middleware/middleware.go
··· 45 45 return func(next http.Handler) http.Handler { 46 46 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 47 47 returnURL := "/" 48 + if r.URL != nil { 49 + returnURL = r.URL.String() 50 + } 48 51 if u, err := url.Parse(r.Header.Get("Referer")); err == nil { 49 - returnURL = u.RequestURI() 52 + if u.RequestURI() != "/" { 53 + returnURL = u.RequestURI() 54 + } 50 55 } 51 56 52 57 loginURL := fmt.Sprintf("/login?return_url=%s", url.QueryEscape(returnURL)) ··· 81 86 82 87 func (mw Middleware) ResolveIdent() middlewareFunc { 83 88 l := mw.logger.With("middleware", "ResolveIdent") 84 - excluded := []string{"favicon.ico"} 89 + excluded := []string{"favicon.ico", "favicon.svg"} 85 90 86 91 return func(next http.Handler) http.Handler { 87 92 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 88 93 didOrHandle := chi.URLParam(r, "user") 94 + didOrHandle = strings.TrimPrefix(didOrHandle, "@") 95 + 89 96 if slices.Contains(excluded, didOrHandle) { 90 97 next.ServeHTTP(w, r) 91 98 return 92 99 } 93 100 94 - didOrHandle = strings.TrimPrefix(didOrHandle, "@") 95 - 96 101 id, err := mw.idResolver.ResolveIdent(r.Context(), didOrHandle) 97 102 if err != nil { 98 103 l.Error("failed to resolve did/handle", "err", err)
+45
internal/server/oauth/accounts.go
··· 1 + package oauth 2 + 3 + import "net/http" 4 + 5 + func (o *OAuth) SetAuthReturn(w http.ResponseWriter, r *http.Request, returnURL string) error { 6 + session, err := o.SessionStore.Get(r, AuthReturnName) 7 + if err != nil { 8 + return err 9 + } 10 + 11 + session.Values[AuthReturnURL] = returnURL 12 + session.Options.MaxAge = 60 * 30 13 + session.Options.HttpOnly = true 14 + session.Options.Secure = !o.Config.Core.Dev 15 + session.Options.SameSite = http.SameSiteLaxMode 16 + 17 + return session.Save(r, w) 18 + } 19 + 20 + type AuthReturnInfo struct { 21 + ReturnURL string 22 + } 23 + 24 + func (o *OAuth) GetAuthReturn(r *http.Request) *AuthReturnInfo { 25 + session, err := o.SessionStore.Get(r, AuthReturnName) 26 + if err != nil || session.IsNew { 27 + return &AuthReturnInfo{} 28 + } 29 + 30 + returnURL, _ := session.Values[AuthReturnURL].(string) 31 + 32 + return &AuthReturnInfo{ 33 + ReturnURL: returnURL, 34 + } 35 + } 36 + 37 + func (o *OAuth) ClearAuthReturn(w http.ResponseWriter, r *http.Request) error { 38 + session, err := o.SessionStore.Get(r, AuthReturnName) 39 + if err != nil { 40 + return err 41 + } 42 + 43 + session.Options.MaxAge = -1 44 + return session.Save(r, w) 45 + }
+2
internal/server/oauth/consts.go
··· 4 4 ClientName = "Yoten" 5 5 ClientURI = "https://yoten.app" 6 6 SessionName = "yoten-oauth-session-v2" 7 + AuthReturnName = "yoten-auth-return" 8 + AuthReturnURL = "return_url" 7 9 SessionHandle = "handle" 8 10 SessionDid = "did" 9 11 SessionId = "id"
+9 -1
internal/server/oauth/handler.go
··· 58 58 ctx := r.Context() 59 59 l := o.Logger.With("handler", "callback").With("query", r.URL.Query()) 60 60 61 + authReturn := o.GetAuthReturn(r) 62 + _ = o.ClearAuthReturn(w, r) 63 + 61 64 sessData, err := o.ClientApp.ProcessCallback(ctx, r.URL.Query()) 62 65 if err != nil { 63 66 var callbackErr *oauth.AuthRequestCallbackError ··· 164 167 } 165 168 } 166 169 167 - http.Redirect(w, r, "/", http.StatusFound) 170 + redirectURL := "/" 171 + if authReturn.ReturnURL != "" { 172 + redirectURL = authReturn.ReturnURL 173 + } 174 + 175 + http.Redirect(w, r, redirectURL, http.StatusFound) 168 176 }

History

4 rounds 0 comments
sign up or login to add to the discussion
1 commit
expand
fix: redirect user to return_url after login
expand 0 comments
pull request successfully merged
1 commit
expand
fix: redirect user to return_url after login
expand 0 comments
1 commit
expand
fix: redirect user to return_url after login
expand 0 comments
brookjeynes.dev submitted #0
1 commit
expand
fix: redirect user to return_url after login
expand 0 comments