mirror of
https://github.com/hay-kot/homebox.git
synced 2025-08-06 01:20:31 +00:00
cleanup temporary token implementation
This commit is contained in:
parent
9178da7f0b
commit
1c28db89a0
5 changed files with 2 additions and 113 deletions
|
@ -2,10 +2,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||||
|
@ -95,41 +92,6 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleItemAttachmentGet godocs
|
|
||||||
// @Summary retrieves an attachment for an item
|
|
||||||
// @Tags Items Attachments
|
|
||||||
// @Produce application/octet-stream
|
|
||||||
// @Param id path string true "Item ID"
|
|
||||||
// @Param token query string true "Attachment token"
|
|
||||||
// @Success 200
|
|
||||||
// @Router /v1/items/{id}/attachments/download [GET]
|
|
||||||
// @Security Bearer
|
|
||||||
func (ctrl *V1Controller) HandleItemAttachmentDownload() server.HandlerFunc {
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
token := server.GetParam(r, "token", "")
|
|
||||||
|
|
||||||
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to get attachment")
|
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
ext := filepath.Ext(doc.Path)
|
|
||||||
|
|
||||||
title := doc.Title
|
|
||||||
|
|
||||||
if !strings.HasSuffix(doc.Title, ext) {
|
|
||||||
title = doc.Title + ext
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", title))
|
|
||||||
w.Header().Set("Content-Type", "application/octet-stream")
|
|
||||||
http.ServeFile(w, r, doc.Path)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleItemAttachmentGet godocs
|
// HandleItemAttachmentGet godocs
|
||||||
// @Summary retrieves an attachment for an item
|
// @Summary retrieves an attachment for an item
|
||||||
// @Tags Items Attachments
|
// @Tags Items Attachments
|
||||||
|
@ -182,7 +144,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
|
||||||
ctx := services.NewContext(r.Context())
|
ctx := services.NewContext(r.Context())
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
doc, err := ctrl.svc.Items.AttachmentPathV2(r.Context(), attachmentID)
|
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), attachmentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to get attachment path")
|
log.Err(err).Msg("failed to get attachment path")
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
|
|
|
@ -65,10 +65,6 @@ func (a *app) mountRoutes(repos *repo.AllRepos) {
|
||||||
a.server.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration())
|
a.server.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration())
|
||||||
a.server.Post(v1Base("/users/login"), v1Ctrl.HandleAuthLogin())
|
a.server.Post(v1Base("/users/login"), v1Ctrl.HandleAuthLogin())
|
||||||
|
|
||||||
// Attachment download URl needs a `token` query param to be passed in the request.
|
|
||||||
// and also needs to be outside of the `auth` middleware.
|
|
||||||
a.server.Get(v1Base("/items/{id}/attachments/download"), v1Ctrl.HandleItemAttachmentDownload())
|
|
||||||
|
|
||||||
userMW := []server.Middleware{
|
userMW := []server.Middleware{
|
||||||
a.mwAuthToken,
|
a.mwAuthToken,
|
||||||
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
|
a.mwRoles(RoleModeOr, authroles.RoleUser.String()),
|
||||||
|
|
|
@ -38,7 +38,6 @@ func New(repos *repo.AllRepos, opts ...OptionsFunc) *AllServices {
|
||||||
Group: &GroupService{repos},
|
Group: &GroupService{repos},
|
||||||
Items: &ItemService{
|
Items: &ItemService{
|
||||||
repo: repos,
|
repo: repos,
|
||||||
at: attachmentTokens{},
|
|
||||||
autoIncrementAssetID: options.autoIncrementAssetID,
|
autoIncrementAssetID: options.autoIncrementAssetID,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,6 @@ type ItemService struct {
|
||||||
repo *repo.AllRepos
|
repo *repo.AllRepos
|
||||||
|
|
||||||
filepath string
|
filepath string
|
||||||
// at is a map of tokens to attachment IDs. This is used to store the attachment ID
|
|
||||||
// for issued URLs
|
|
||||||
at attachmentTokens
|
|
||||||
|
|
||||||
autoIncrementAssetID bool
|
autoIncrementAssetID bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,80 +4,15 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/attachment"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: this isn't a scalable solution, tokens should be stored in the database
|
func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentId uuid.UUID) (*ent.Document, error) {
|
||||||
type attachmentTokens map[string]uuid.UUID
|
|
||||||
|
|
||||||
func (at attachmentTokens) Add(token string, id uuid.UUID) {
|
|
||||||
at[token] = id
|
|
||||||
|
|
||||||
log.Debug().Str("token", token).Str("uuid", id.String()).Msg("added token")
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
ch := time.After(1 * time.Minute)
|
|
||||||
<-ch
|
|
||||||
at.Delete(token)
|
|
||||||
log.Debug().Str("token", token).Msg("deleted token")
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at attachmentTokens) Get(token string) (uuid.UUID, bool) {
|
|
||||||
id, ok := at[token]
|
|
||||||
return id, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at attachmentTokens) Delete(token string) {
|
|
||||||
delete(at, token)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (svc *ItemService) AttachmentToken(ctx Context, itemId, attachmentId uuid.UUID) (string, error) {
|
|
||||||
_, err := svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
token := hasher.GenerateToken()
|
|
||||||
|
|
||||||
// Ensure that the file exists
|
|
||||||
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(attachment.Edges.Document.Path); os.IsNotExist(err) {
|
|
||||||
_ = svc.AttachmentDelete(ctx, ctx.GID, itemId, attachmentId)
|
|
||||||
return "", ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
svc.at.Add(token.Raw, attachmentId)
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return nil, ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue