mirror of
https://github.com/ThisTine/Snip.git
synced 2026-08-18 23:18:47 +07:00
89 lines
2.4 KiB
Go
89 lines
2.4 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/snip/backend/internal/domain"
|
|
)
|
|
|
|
// /api/v1/auth/...
|
|
// GET providers
|
|
// GET {provider}/login
|
|
// GET {provider}/callback
|
|
// GET me
|
|
// POST logout
|
|
func (a *API) authRoutes(w http.ResponseWriter, r *http.Request) {
|
|
rest := pathTail(r.URL.Path, "/api/v1/auth/")
|
|
parts := strings.Split(strings.Trim(rest, "/"), "/")
|
|
|
|
switch {
|
|
case len(parts) == 1 && parts[0] == "providers":
|
|
writeJSON(w, http.StatusOK, map[string][]string{"providers": a.auth.Providers()})
|
|
case len(parts) == 1 && parts[0] == "me":
|
|
a.me(w, r)
|
|
case len(parts) == 1 && parts[0] == "logout":
|
|
a.clearCookie(w, sessionCookie)
|
|
w.WriteHeader(http.StatusNoContent)
|
|
case len(parts) == 2 && parts[1] == "login":
|
|
a.beginLogin(w, r, parts[0])
|
|
case len(parts) == 2 && parts[1] == "callback":
|
|
a.callback(w, r, parts[0])
|
|
default:
|
|
w.WriteHeader(http.StatusNotFound)
|
|
}
|
|
}
|
|
|
|
func (a *API) me(w http.ResponseWriter, r *http.Request) {
|
|
c, err := r.Cookie(sessionCookie)
|
|
if err != nil {
|
|
writeError(w, domain.ErrUnauthorized)
|
|
return
|
|
}
|
|
user, err := a.auth.Me(r.Context(), c.Value)
|
|
if err != nil {
|
|
writeError(w, domain.ErrUnauthorized)
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, userDTO{ID: user.ID, Email: user.Email, Name: user.Name})
|
|
}
|
|
|
|
func (a *API) beginLogin(w http.ResponseWriter, r *http.Request, provider string) {
|
|
state := randomState()
|
|
url, err := a.auth.AuthURL(provider, state)
|
|
if err != nil {
|
|
writeError(w, err)
|
|
return
|
|
}
|
|
// Double-submit: stash state in a short-lived cookie, compare on callback.
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: stateCookie, Value: state, Path: "/", HttpOnly: true,
|
|
Secure: a.cfg.CookieSecure, SameSite: http.SameSiteLaxMode,
|
|
Expires: time.Now().Add(10 * time.Minute),
|
|
})
|
|
http.Redirect(w, r, url, http.StatusFound)
|
|
}
|
|
|
|
func (a *API) callback(w http.ResponseWriter, r *http.Request, provider string) {
|
|
cookie, err := r.Cookie(stateCookie)
|
|
if err != nil || cookie.Value == "" || cookie.Value != r.URL.Query().Get("state") {
|
|
writeError(w, domain.ErrUnauthorized)
|
|
return
|
|
}
|
|
a.clearCookie(w, stateCookie)
|
|
|
|
code := r.URL.Query().Get("code")
|
|
if code == "" {
|
|
writeError(w, domain.ErrUnauthorized)
|
|
return
|
|
}
|
|
_, token, err := a.auth.Complete(r.Context(), provider, code)
|
|
if err != nil {
|
|
writeError(w, err)
|
|
return
|
|
}
|
|
a.setSession(w, token)
|
|
http.Redirect(w, r, a.cfg.PostLoginRedirect, http.StatusFound)
|
|
}
|