diff --git a/backend/app/api/handlers/v1/v1_ctrl_auth.go b/backend/app/api/handlers/v1/v1_ctrl_auth.go index b005a9d..24b1654 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_auth.go +++ b/backend/app/api/handlers/v1/v1_ctrl_auth.go @@ -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, }) } } diff --git a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go index 4eae453..9f3c74a 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go @@ -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: diff --git a/backend/internal/core/services/service_items_attachments.go b/backend/internal/core/services/service_items_attachments.go index b5df5f8..f395b8e 100644 --- a/backend/internal/core/services/service_items_attachments.go +++ b/backend/internal/core/services/service_items_attachments.go @@ -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 { diff --git a/backend/internal/core/services/service_user.go b/backend/internal/core/services/service_user.go index e3d8f8a..6d3bc6e 100644 --- a/backend/internal/core/services/service_user.go +++ b/backend/internal/core/services/service_user.go @@ -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