fix thumbnailer for the new spaces approach

This commit is contained in:
David Christofas
2022-01-07 16:32:45 +01:00
parent 76592e21d8
commit f602c50ff9
8 changed files with 64 additions and 27 deletions

View File

@@ -65,7 +65,6 @@ type Thumbnail struct {
WebdavAllowInsecure bool `ocisConfig:"webdav_allow_insecure"`
CS3AllowInsecure bool `ocisConfig:"cs3_allow_insecure"`
RevaGateway string `ocisConfig:"reva_gateway"`
WebdavNamespace string `ocisConfig:"webdav_namespace"`
FontMapFile string `ocisConfig:"font_map_file"`
}
@@ -101,7 +100,6 @@ func DefaultConfig() *Config {
},
WebdavAllowInsecure: true,
RevaGateway: "127.0.0.1:9142",
WebdavNamespace: "/home",
CS3AllowInsecure: false,
},
}

View File

@@ -111,9 +111,5 @@ func structMappings(cfg *Config) []shared.EnvBinding {
EnvVars: []string{"OCIS_INSECURE", "THUMBNAILS_CS3SOURCE_INSECURE"},
Destination: &cfg.Thumbnail.CS3AllowInsecure,
},
{
EnvVars: []string{"STORAGE_WEBDAV_NAMESPACE"},
Destination: &cfg.Thumbnail.WebdavNamespace,
},
}
}

View File

@@ -8,6 +8,7 @@ import (
"strings"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
revactx "github.com/cs3org/reva/pkg/ctx"
@@ -30,8 +31,7 @@ func NewService(opts ...Option) v0proto.ThumbnailServiceHandler {
logger.Fatal().Err(err).Msg("resolutions not configured correctly")
}
svc := Thumbnail{
serviceID: options.Config.Server.Namespace + "." + options.Config.Server.Name,
webdavNamespace: options.Config.Thumbnail.WebdavNamespace,
serviceID: options.Config.Server.Namespace + "." + options.Config.Server.Name,
manager: thumbnail.NewSimpleManager(
resolutions,
options.ThumbnailStorage,
@@ -52,7 +52,6 @@ func NewService(opts ...Option) v0proto.ThumbnailServiceHandler {
// Thumbnail implements the GRPC handler.
type Thumbnail struct {
serviceID string
webdavNamespace string
manager thumbnail.Manager
webdavSource imgsource.Source
cs3Source imgsource.Source
@@ -100,7 +99,7 @@ func (g Thumbnail) GetThumbnail(ctx context.Context, req *v0proto.GetThumbnailRe
func (g Thumbnail) handleCS3Source(ctx context.Context, req *v0proto.GetThumbnailRequest, encoder thumbnail.Encoder) ([]byte, error) {
src := req.GetCs3Source()
sRes, err := g.stat(src.Path, src.Authorization)
sRes, err := g.stat(src.Path, src.Authorization, nil)
if err != nil {
return nil, err
}
@@ -144,7 +143,11 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *v0proto.GetThumb
return nil, errors.Wrap(err, "source url is invalid")
}
var auth, statPath string
var (
auth, statPath string
user *userv1beta1.User
)
if src.IsPublicLink {
q := imgURL.Query()
var rsp *gateway.AuthenticateResponse
@@ -171,12 +174,14 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *v0proto.GetThumb
return nil, merrors.InternalServerError(g.serviceID, "could not authenticate: %s", err.Error())
}
auth = rsp.Token
user = rsp.User
statPath = path.Join("/public", src.PublicLinkToken, req.Filepath)
} else {
auth = src.RevaAuthorization
statPath = path.Join(g.webdavNamespace, req.Filepath)
statPath = req.Filepath
user = revactx.ContextMustGetUser(ctx)
}
sRes, err := g.stat(statPath, auth)
sRes, err := g.stat(statPath, auth, user)
if err != nil {
return nil, err
}
@@ -214,7 +219,7 @@ func (g Thumbnail) handleWebdavSource(ctx context.Context, req *v0proto.GetThumb
return thumb, nil
}
func (g Thumbnail) stat(path, auth string) (*provider.StatResponse, error) {
func (g Thumbnail) stat(path, auth string, user *userv1beta1.User) (*provider.StatResponse, error) {
ctx := metadata.AppendToOutgoingContext(context.Background(), revactx.TokenHeader, auth)
req := &provider.StatRequest{

View File

@@ -57,6 +57,7 @@ type Config struct {
Service Service `ocisConfig:"service"`
OcisPublicURL string `ocisConfig:"ocis_public_url"`
WebdavNamespace string `ocisConfig:"webdav_namespace"`
RevaGateway string `ocisConfig:"reva_gateway"`
Context context.Context
Supervised bool
@@ -97,6 +98,7 @@ func DefaultConfig() *Config {
Namespace: "com.owncloud.web",
},
OcisPublicURL: "https://127.0.0.1:9200",
WebdavNamespace: "/home",
WebdavNamespace: "/users/{{.Id.OpaqueId}}",
RevaGateway: "127.0.0.1:9142",
}
}

View File

@@ -103,5 +103,9 @@ func structMappings(cfg *Config) []shared.EnvBinding {
EnvVars: []string{"STORAGE_WEBDAV_NAMESPACE"},
Destination: &cfg.WebdavNamespace,
},
{
EnvVars: []string{"REVA_GATEWAY"},
Destination: &cfg.RevaGateway,
},
}
}

View File

@@ -33,11 +33,13 @@ type ThumbnailRequest struct {
Height int32
// In case of a public share the public link token.
PublicLinkToken string
// The username from the requested URL
Username string
}
// ParseThumbnailRequest extracts all required parameters from a http request.
func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) {
fp, err := extractFilePath(r)
fp, username, err := extractFilePath(r)
if err != nil {
return nil, err
}
@@ -55,6 +57,7 @@ func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) {
Width: int32(width),
Height: int32(height),
PublicLinkToken: chi.URLParam(r, "token"),
Username: username,
}, nil
}
@@ -64,23 +67,23 @@ func ParseThumbnailRequest(r *http.Request) (*ThumbnailRequest, error) {
//
// User and filepath are dynamic and filepath can contain slashes
// So using the URLParam function is not possible.
func extractFilePath(r *http.Request) (string, error) {
func extractFilePath(r *http.Request) (string, string, error) {
user := chi.URLParam(r, "user")
user, err := url.QueryUnescape(user)
if err != nil {
return "", errors.New("could not unescape user")
return "", "", errors.New("could not unescape user")
}
if user != "" {
parts := strings.SplitN(r.URL.Path, user, 2)
return parts[1], nil
return parts[1], user, nil
}
token := chi.URLParam(r, "token")
if token != "" {
parts := strings.SplitN(r.URL.Path, token, 2)
return parts[1], nil
return parts[1], "", nil
}
return "", errors.New("could not extract file path")
return "", "", errors.New("could not extract file path")
}
func parseDimensions(q url.Values) (int64, int64, error) {

View File

@@ -23,7 +23,7 @@ func Server(opts ...Option) (http.Service, error) {
http.Flags(options.Flags...),
)
handle := svc.NewService(
handle, err := svc.NewService(
svc.Logger(options.Logger),
svc.Config(options.Config),
svc.Middleware(
@@ -47,6 +47,9 @@ func Server(opts ...Option) (http.Service, error) {
),
),
)
if err != nil {
return http.Service{}, err
}
{
handle = svc.NewInstrument(handle, options.Metrics)

View File

@@ -3,11 +3,17 @@ package svc
import (
"encoding/xml"
"net/http"
"path"
"path/filepath"
"strings"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/storage/utils/templates"
"github.com/go-chi/render"
merrors "go-micro.dev/v4/errors"
"google.golang.org/grpc/metadata"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
@@ -38,17 +44,24 @@ type Service interface {
}
// NewService returns a service implementation for Service.
func NewService(opts ...Option) Service {
func NewService(opts ...Option) (Service, error) {
options := newOptions(opts...)
conf := options.Config
m := chi.NewMux()
m.Use(options.Middleware...)
gwc, err := pool.GetGatewayServiceClient(conf.RevaGateway)
if err != nil {
return nil, err
}
svc := Webdav{
config: options.Config,
config: conf,
log: options.Logger,
mux: m,
thumbnailsClient: thumbnails.NewThumbnailService("com.owncloud.api.thumbnails", grpc.DefaultClient),
revaClient: gwc,
}
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
@@ -57,7 +70,7 @@ func NewService(opts ...Option) Service {
r.Head("/remote.php/dav/public-files/{token}/*", svc.PublicThumbnailHead)
})
return svc
return svc, nil
}
// Webdav defines implements the business logic for Service.
@@ -66,6 +79,7 @@ type Webdav struct {
log log.Logger
mux *chi.Mux
thumbnailsClient thumbnails.ThumbnailService
revaClient gatewayv1beta1.GatewayAPIClient
}
// ServeHTTP implements the Service interface.
@@ -83,6 +97,18 @@ func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) {
}
t := r.Header.Get(TokenHeader)
ctx := metadata.AppendToOutgoingContext(r.Context(), TokenHeader, t)
userRes, err := g.revaClient.GetUserByClaim(ctx, &userv1beta1.GetUserByClaimRequest{
Claim: "username",
Value: tr.Username,
})
if err != nil || userRes.Status.Code != rpcv1beta1.Code_CODE_OK {
g.log.Error().Err(err).Msg("could not get user")
renderError(w, r, errInternalError("could not get user"))
return
}
fullPath := filepath.Join(templates.WithUser(userRes.User, g.config.WebdavNamespace), tr.Filepath)
rsp, err := g.thumbnailsClient.GetThumbnail(r.Context(), &thumbnails.GetThumbnailRequest{
Filepath: strings.TrimLeft(tr.Filepath, "/"),
ThumbnailType: extensionToThumbnailType(strings.TrimLeft(tr.Extension, ".")),
@@ -90,7 +116,7 @@ func (g Webdav) Thumbnail(w http.ResponseWriter, r *http.Request) {
Height: tr.Height,
Source: &thumbnails.GetThumbnailRequest_Cs3Source{
Cs3Source: &thumbnails.CS3Source{
Path: path.Join(g.config.WebdavNamespace, tr.Filepath),
Path: fullPath,
Authorization: t,
},
},