···11+package state22+33+import (44+ "fmt"55+ "log"66+ "net/http"77+ "strings"88+99+ "tangled.org/core/appview/pages"1010+)1111+1212+func (s *State) Login(w http.ResponseWriter, r *http.Request) {1313+ switch r.Method {1414+ case http.MethodGet:1515+ returnURL := r.URL.Query().Get("return_url")1616+ s.pages.Login(w, pages.LoginParams{1717+ ReturnUrl: returnURL,1818+ })1919+ case http.MethodPost:2020+ handle := r.FormValue("handle")2121+2222+ // when users copy their handle from bsky.app, it tends to have these characters around it:2323+ //2424+ // @nelind.dk:2525+ // \u202a ensures that the handle is always rendered left to right and2626+ // \u202c reverts that so the rest of the page renders however it should2727+ handle = strings.TrimPrefix(handle, "\u202a")2828+ handle = strings.TrimSuffix(handle, "\u202c")2929+3030+ // `@` is harmless3131+ handle = strings.TrimPrefix(handle, "@")3232+3333+ // basic handle validation3434+ if !strings.Contains(handle, ".") {3535+ log.Println("invalid handle format", "raw", handle)3636+ s.pages.Notice(3737+ w,3838+ "login-msg",3939+ fmt.Sprintf("\"%s\" is an invalid handle. Did you mean %s.bsky.social or %s.tngl.sh?", handle, handle, handle),4040+ )4141+ return4242+ }4343+4444+ redirectURL, err := s.oauth.ClientApp.StartAuthFlow(r.Context(), handle)4545+ if err != nil {4646+ http.Error(w, err.Error(), http.StatusInternalServerError)4747+ return4848+ }4949+5050+ s.pages.HxRedirect(w, redirectURL)5151+ }5252+}5353+5454+func (s *State) Logout(w http.ResponseWriter, r *http.Request) {5555+ err := s.oauth.DeleteSession(w, r)5656+ if err != nil {5757+ log.Println("failed to logout", "err", err)5858+ } else {5959+ log.Println("logged out successfully")6060+ }6161+6262+ s.pages.HxRedirect(w, "/login")6363+}