feat: add token IDs, store tokens in db for early invalidation
This commit is contained in:
parent
58c1c1794e
commit
e5723360a7
7 changed files with 248 additions and 9 deletions
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/mediocregopher/radix/v4"
|
||||
"github.com/rs/xid"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
|
@ -81,11 +82,19 @@ func (s *Server) discordCallback(w http.ResponseWriter, r *http.Request) error {
|
|||
log.Errorf("updating user %v with Discord info: %v", u.ID, err)
|
||||
}
|
||||
|
||||
token, err := s.Auth.CreateToken(u.ID)
|
||||
// TODO: implement user + token permissions
|
||||
tokenID := xid.New()
|
||||
token, err := s.Auth.CreateToken(u.ID, tokenID, false, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save token to database
|
||||
_, err = s.DB.SaveToken(ctx, u.ID, tokenID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "saving token to database")
|
||||
}
|
||||
|
||||
render.JSON(w, r, discordCallbackResponse{
|
||||
HasAccount: true,
|
||||
Token: token,
|
||||
|
@ -206,11 +215,19 @@ func (s *Server) discordSignup(w http.ResponseWriter, r *http.Request) error {
|
|||
}
|
||||
|
||||
// create token
|
||||
token, err := s.Auth.CreateToken(u.ID)
|
||||
// TODO: implement user + token permissions
|
||||
tokenID := xid.New()
|
||||
token, err := s.Auth.CreateToken(u.ID, tokenID, false, true)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "creating token")
|
||||
}
|
||||
|
||||
// save token to database
|
||||
_, err = s.DB.SaveToken(ctx, u.ID, tokenID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "saving token to database")
|
||||
}
|
||||
|
||||
// return user
|
||||
render.JSON(w, r, signupResponse{
|
||||
User: *dbUserToUserResponse(u),
|
||||
|
|
|
@ -67,6 +67,11 @@ func Mount(srv *server.Server, r chi.Router) {
|
|||
// invite routes
|
||||
r.With(server.MustAuth).Get("/invites", server.WrapHandler(s.getInvites))
|
||||
r.With(server.MustAuth).Post("/invites", server.WrapHandler(s.createInvite))
|
||||
|
||||
// tokens
|
||||
r.With(server.MustAuth).Get("/tokens", server.WrapHandler(s.getTokens))
|
||||
r.With(server.MustAuth).Post("/tokens", server.WrapHandler(s.createToken))
|
||||
r.With(server.MustAuth).Delete("/tokens", server.WrapHandler(s.deleteToken))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
72
backend/routes/auth/tokens.go
Normal file
72
backend/routes/auth/tokens.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"codeberg.org/u1f320/pronouns.cc/backend/db"
|
||||
"codeberg.org/u1f320/pronouns.cc/backend/server"
|
||||
"emperror.dev/errors"
|
||||
"github.com/go-chi/render"
|
||||
"github.com/rs/xid"
|
||||
)
|
||||
|
||||
type getTokenResponse struct {
|
||||
TokenID xid.ID `json:"id"`
|
||||
Created time.Time `json:"created"`
|
||||
Expires time.Time `json:"expires"`
|
||||
}
|
||||
|
||||
func dbTokenToGetResponse(t db.Token) getTokenResponse {
|
||||
return getTokenResponse{
|
||||
TokenID: t.TokenID,
|
||||
Created: t.Created,
|
||||
Expires: t.Expires,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) getTokens(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := r.Context()
|
||||
claims, _ := server.ClaimsFromContext(ctx)
|
||||
|
||||
tokens, err := s.DB.Tokens(ctx, claims.UserID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting tokens")
|
||||
}
|
||||
|
||||
resps := make([]getTokenResponse, len(tokens))
|
||||
for i := range tokens {
|
||||
resps[i] = dbTokenToGetResponse(tokens[i])
|
||||
}
|
||||
|
||||
render.JSON(w, r, resps)
|
||||
return nil
|
||||
}
|
||||
|
||||
type deleteTokenResponse struct {
|
||||
TokenID xid.ID `json:"id"`
|
||||
Invalidated bool `json:"invalidated"`
|
||||
Created time.Time `json:"time"`
|
||||
}
|
||||
|
||||
func (s *Server) deleteToken(w http.ResponseWriter, r *http.Request) error {
|
||||
ctx := r.Context()
|
||||
claims, _ := server.ClaimsFromContext(ctx)
|
||||
|
||||
t, err := s.DB.InvalidateToken(ctx, claims.UserID, claims.TokenID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalidating token")
|
||||
}
|
||||
|
||||
render.JSON(w, r, deleteTokenResponse{
|
||||
TokenID: t.TokenID,
|
||||
Invalidated: t.Invalidated,
|
||||
Created: t.Created,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) createToken(w http.ResponseWriter, r *http.Request) error {
|
||||
// unimplemented right now
|
||||
return server.APIError{Code: server.ErrForbidden}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue