add API boilerplate + /accounts/{accountID} and /accounts/@me endpoints
This commit is contained in:
parent
0fa769a248
commit
dfc116d828
7 changed files with 335 additions and 0 deletions
|
@ -3,9 +3,12 @@ package app
|
|||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.sleepycat.moe/sam/mercury/internal/database"
|
||||
"git.sleepycat.moe/sam/mercury/web/api"
|
||||
"github.com/go-chi/render"
|
||||
)
|
||||
|
||||
type ctxKey int
|
||||
|
@ -42,6 +45,62 @@ func (app *App) FrontendAuth(next http.Handler) http.Handler {
|
|||
return http.HandlerFunc(fn)
|
||||
}
|
||||
|
||||
func (app *App) APIAuth(scope database.TokenScope, anonAccess bool) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
header := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
|
||||
if header == "" {
|
||||
cookie, err := r.Cookie(database.TokenCookieName)
|
||||
if err != nil || cookie.Value == "" {
|
||||
if anonAccess { // no token supplied, but the endpoint allows anonymous access
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, api.ErrCodeStatus(api.ErrInvalidToken))
|
||||
render.JSON(w, r, api.Error{
|
||||
Code: api.ErrInvalidToken,
|
||||
Message: api.ErrCodeMessage(api.ErrInvalidToken),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
token, err := app.ParseToken(r.Context(), header)
|
||||
if err != nil {
|
||||
render.Status(r, api.ErrCodeStatus(api.ErrInvalidToken))
|
||||
render.JSON(w, r, api.Error{
|
||||
Code: api.ErrInvalidToken,
|
||||
Message: api.ErrCodeMessage(api.ErrInvalidToken),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if token.Expires.Before(time.Now()) {
|
||||
render.Status(r, api.ErrCodeStatus(api.ErrInvalidToken))
|
||||
render.JSON(w, r, api.Error{
|
||||
Code: api.ErrInvalidToken,
|
||||
Message: api.ErrCodeMessage(api.ErrInvalidToken),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if !token.Scopes.Has(scope) {
|
||||
render.Status(r, api.ErrCodeStatus(api.ErrMissingScope))
|
||||
render.JSON(w, r, api.Error{
|
||||
Code: api.ErrMissingScope,
|
||||
Message: api.ErrCodeMessage(api.ErrMissingScope),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), ctxKeyClaims, token)
|
||||
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (app *App) TokenFromContext(ctx context.Context) (database.Token, bool) {
|
||||
v := ctx.Value(ctxKeyClaims)
|
||||
if v == nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue