diff --git a/services/graph/pkg/service/v0/sharedbyme.go b/services/graph/pkg/service/v0/sharedbyme.go index 01b682db1..fc3933edf 100644 --- a/services/graph/pkg/service/v0/sharedbyme.go +++ b/services/graph/pkg/service/v0/sharedbyme.go @@ -1,24 +1,50 @@ package svc import ( - "net/http" - + "fmt" + "github.com/CiscoM31/godata" rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" "github.com/go-chi/render" libregraph "github.com/opencloud-eu/libre-graph-api-go" + "github.com/opencloud-eu/opencloud/services/graph/pkg/odata" + "github.com/opencloud-eu/opencloud/services/thumbnails/pkg/thumbnail" + "github.com/opencloud-eu/reva/v2/pkg/signedurl" + "net/http" + "slices" + "time" "github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode" ) type driveItemsByResourceID map[string]libregraph.DriveItem +// parseShareByMeRequest parses the odata request and returns the parsed request and a boolean indicating if the request should expand thumbnails. +func parseShareByMeRequest(r *http.Request) (*godata.GoDataRequest, bool, error) { + odataReq, err := godata.ParseRequest(r.Context(), sanitizePath(r.URL.Path, APIVersion_1), r.URL.Query()) + if err != nil { + return nil, false, errorcode.New(errorcode.InvalidRequest, err.Error()) + } + exp, err := odata.GetExpandValues(odataReq.Query) + if err != nil { + return nil, false, errorcode.New(errorcode.InvalidRequest, err.Error()) + } + expandThumbnails := slices.Contains(exp, "thumbnails") + return odataReq, expandThumbnails, nil +} + // GetSharedByMe implements the Service interface (/me/drives/sharedByMe endpoint) func (g Graph) GetSharedByMe(w http.ResponseWriter, r *http.Request) { g.logger.Debug().Msg("Calling GetRootDriveChildren") ctx := r.Context() + _, expandThumbnails, err := parseShareByMeRequest(r) + if err != nil { + errorcode.RenderError(w, r, err) + return + } + fmt.Println("expandThumbnails:", expandThumbnails) + driveItems := make(driveItemsByResourceID) - var err error driveItems, err = g.listUserShares(ctx, nil, driveItems) if err != nil { errorcode.RenderError(w, r, err) @@ -39,6 +65,41 @@ func (g Graph) GetSharedByMe(w http.ResponseWriter, r *http.Request) { return } + if expandThumbnails { + for k, item := range driveItems { + mt := item.GetFile().MimeType + if mt == nil { + continue + } + + signer, err := signedurl.NewJWTSignedURL(signedurl.WithSecret("abcde")) + if err != nil { + panic("failed to create signer") + } + + _, match := thumbnail.SupportedMimeTypes[*mt] + if match { + signedURL, err := signer.Sign("https://localhost:9200/", item.GetId(), 30*time.Minute) + if err != nil { + g.logger.Error().Err(err).Msg("Failed to get thumbnail URL") + continue + } + t := libregraph.NewThumbnail() + t.SetUrl(signedURL) + item.SetThumbnails([]libregraph.ThumbnailSet{ + { + Small: t, + Medium: t, + Large: t, + }, + }) + + driveItems[k] = item // assign modified item back to the map + } + } + + } + res := make([]libregraph.DriveItem, 0, len(driveItems)) for _, v := range driveItems { res = append(res, v) diff --git a/services/thumbnails/pkg/service/http/v0/service.go b/services/thumbnails/pkg/service/http/v0/service.go index 04c8f8627..31be4a47a 100644 --- a/services/thumbnails/pkg/service/http/v0/service.go +++ b/services/thumbnails/pkg/service/http/v0/service.go @@ -3,7 +3,9 @@ package svc import ( "context" "fmt" + "github.com/opencloud-eu/reva/v2/pkg/signedurl" "net/http" + "net/url" "strconv" "github.com/go-chi/chi/v5" @@ -65,6 +67,7 @@ func NewService(opts ...Option) Service { m.Route(options.Config.HTTP.Root, func(r chi.Router) { r.Use(svc.TransferTokenValidator) + r.Use(svc.SignedUrlValidator) r.Get("/data", svc.GetThumbnail) }) @@ -114,11 +117,47 @@ func (s Thumbnails) GetThumbnail(w http.ResponseWriter, r *http.Request) { } } +func (s Thumbnails) SignedUrlValidator(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + u, err := url.Parse(r.URL.String()) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + signer, err := signedurl.NewJWTSignedURL(signedurl.WithSecret("abcde")) + if err != nil { + panic("failed to create signer") + } + + sig := u.Query().Get("oc-jwt-sig") + if sig == "" { + next.ServeHTTP(w, r) + } + + _, err = signer.Verify(u.String()) + if err == nil { + // the signature is valid + next.ServeHTTP(w, r) + } else { + w.WriteHeader(http.StatusUnauthorized) + } + + // TODO: make sure that one of the validator validated + // TODO: log errors + }) +} + // TransferTokenValidator validates a transfer token func (s Thumbnails) TransferTokenValidator(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - logger := s.logger.SubloggerWithRequestID(r.Context()) tokenString := r.Header.Get("Transfer-Token") + if tokenString == "" { + next.ServeHTTP(w, r) + return + } + + logger := s.logger.SubloggerWithRequestID(r.Context()) token, err := jwt.ParseWithClaims(tokenString, &tjwt.ThumbnailClaims{}, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])