implement attachment token access

This commit is contained in:
Hayden 2022-12-03 10:37:19 -09:00
parent 323fd919d1
commit 9a671dc483
No known key found for this signature in database
GPG key ID: 17CF79474E257545
4 changed files with 55 additions and 41 deletions

View file

@ -13,8 +13,9 @@ import (
type (
TokenResponse struct {
Token string `json:"token"`
ExpiresAt time.Time `json:"expiresAt"`
Token string `json:"token"`
ExpiresAt time.Time `json:"expiresAt"`
AttachmentToken string `json:"attachmentToken"`
}
LoginForm struct {
@ -76,8 +77,9 @@ func (ctrl *V1Controller) HandleAuthLogin() server.HandlerFunc {
}
return server.Respond(w, http.StatusOK, TokenResponse{
Token: "Bearer " + newToken.Raw,
ExpiresAt: newToken.ExpiresAt,
Token: "Bearer " + newToken.Raw,
ExpiresAt: newToken.ExpiresAt,
AttachmentToken: newToken.AttachmentToken,
})
}
}

View file

@ -130,7 +130,7 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() server.HandlerFunc {
}
}
// HandleItemAttachmentToken godocs
// HandleItemAttachmentGet godocs
// @Summary retrieves an attachment for an item
// @Tags Items Attachments
// @Produce application/octet-stream
@ -139,7 +139,7 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() server.HandlerFunc {
// @Success 200 {object} ItemAttachmentToken
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentToken() server.HandlerFunc {
func (ctrl *V1Controller) HandleItemAttachmentGet() server.HandlerFunc {
return ctrl.handleItemAttachmentsHandler
}
@ -181,33 +181,15 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
ctx := services.NewContext(r.Context())
switch r.Method {
// Token Handler
case http.MethodGet:
token, err := ctrl.svc.Items.AttachmentToken(ctx, ID, attachmentID)
doc, err := ctrl.svc.Items.AttachmentPathV2(r.Context(), attachmentID)
if err != nil {
switch err {
case services.ErrNotFound:
log.Err(err).
Str("id", attachmentID.String()).
Msg("failed to find attachment with id")
return validate.NewRequestError(err, http.StatusNotFound)
case services.ErrFileNotFound:
log.Err(err).
Str("id", attachmentID.String()).
Msg("failed to find file path for attachment with id")
log.Warn().Msg("attachment with no file path removed from database")
return validate.NewRequestError(err, http.StatusNotFound)
default:
log.Err(err).Msg("failed to get attachment")
return validate.NewRequestError(err, http.StatusInternalServerError)
}
log.Err(err).Msg("failed to get attachment path")
return validate.NewRequestError(err, http.StatusInternalServerError)
}
return server.Respond(w, http.StatusOK, ItemAttachmentToken{Token: token})
http.ServeFile(w, r, doc.Path)
return nil
// Delete Attachment Handler
case http.MethodDelete:

View file

@ -63,6 +63,15 @@ func (svc *ItemService) AttachmentToken(ctx Context, itemId, attachmentId uuid.U
return token.Raw, nil
}
func (svc *ItemService) AttachmentPathV2(ctx context.Context, attachmentId uuid.UUID) (*ent.Document, error) {
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
if err != nil {
return nil, err
}
return attachment.Edges.Document, nil
}
func (svc *ItemService) AttachmentPath(ctx context.Context, token string) (*ent.Document, error) {
attachmentId, ok := svc.at.Get(token)
if !ok {

View file

@ -6,6 +6,7 @@ import (
"time"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/data/ent/authroles"
"github.com/hay-kot/homebox/backend/internal/data/repo"
"github.com/hay-kot/homebox/backend/pkgs/hasher"
"github.com/rs/zerolog/log"
@ -30,8 +31,9 @@ type (
Password string `json:"password"`
}
UserAuthTokenDetail struct {
Raw string `json:"raw"`
ExpiresAt time.Time `json:"expiresAt"`
Raw string `json:"raw"`
AttachmentToken string `json:"attachmentToken"`
ExpiresAt time.Time `json:"expiresAt"`
}
LoginForm struct {
Username string `json:"username"`
@ -131,16 +133,37 @@ func (svc *UserService) UpdateSelf(ctx context.Context, ID uuid.UUID, data repo.
// ============================================================================
// User Authentication
func (svc *UserService) createToken(ctx context.Context, userId uuid.UUID) (UserAuthTokenDetail, error) {
newToken := hasher.GenerateToken()
func (svc *UserService) createSessionToken(ctx context.Context, userId uuid.UUID) (UserAuthTokenDetail, error) {
created, err := svc.repos.AuthTokens.CreateToken(ctx, repo.UserAuthTokenCreate{
attachmentToken := hasher.GenerateToken()
attachmentData := repo.UserAuthTokenCreate{
UserID: userId,
TokenHash: newToken.Hash,
TokenHash: attachmentToken.Hash,
ExpiresAt: time.Now().Add(oneWeek),
})
}
return UserAuthTokenDetail{Raw: newToken.Raw, ExpiresAt: created.ExpiresAt}, err
_, err := svc.repos.AuthTokens.CreateToken(ctx, attachmentData, authroles.RoleAttachments)
if err != nil {
return UserAuthTokenDetail{}, err
}
userToken := hasher.GenerateToken()
data := repo.UserAuthTokenCreate{
UserID: userId,
TokenHash: userToken.Hash,
ExpiresAt: time.Now().Add(oneWeek),
}
created, err := svc.repos.AuthTokens.CreateToken(ctx, data, authroles.RoleUser)
if err != nil {
return UserAuthTokenDetail{}, err
}
return UserAuthTokenDetail{
Raw: userToken.Raw,
ExpiresAt: created.ExpiresAt,
AttachmentToken: attachmentToken.Raw,
}, nil
}
func (svc *UserService) Login(ctx context.Context, username, password string) (UserAuthTokenDetail, error) {
@ -156,7 +179,7 @@ func (svc *UserService) Login(ctx context.Context, username, password string) (U
return UserAuthTokenDetail{}, ErrorInvalidLogin
}
return svc.createToken(ctx, usr.ID)
return svc.createSessionToken(ctx, usr.ID)
}
func (svc *UserService) Logout(ctx context.Context, token string) error {
@ -174,9 +197,7 @@ func (svc *UserService) RenewToken(ctx context.Context, token string) (UserAuthT
return UserAuthTokenDetail{}, ErrorInvalidToken
}
newToken, _ := svc.createToken(ctx, dbToken.ID)
return newToken, nil
return svc.createSessionToken(ctx, dbToken.ID)
}
// DeleteSelf deletes the user that is currently logged based of the provided UUID