@@ -16,3 +16,4 @@ Changelog for reva 2.13.3 (2023-05-17)
|
|||||||
* Enhancement [cs3org/reva#3895](https://github.com/cs3org/reva/pull/3895): Add missing expiry date to shares
|
* Enhancement [cs3org/reva#3895](https://github.com/cs3org/reva/pull/3895): Add missing expiry date to shares
|
||||||
|
|
||||||
https://github.com/owncloud/ocis/pull/6305
|
https://github.com/owncloud/ocis/pull/6305
|
||||||
|
https://github.com/owncloud/ocis/pull/6339
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ require (
|
|||||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||||
github.com/coreos/go-oidc/v3 v3.4.0
|
github.com/coreos/go-oidc/v3 v3.4.0
|
||||||
github.com/cs3org/go-cs3apis v0.0.0-20221012090518-ef2996678965
|
github.com/cs3org/go-cs3apis v0.0.0-20221012090518-ef2996678965
|
||||||
github.com/cs3org/reva/v2 v2.13.3
|
github.com/cs3org/reva/v2 v2.13.4-0.20230517171752-b39e78fd7b28
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||||
github.com/egirna/icap-client v0.1.1
|
github.com/egirna/icap-client v0.1.1
|
||||||
|
|||||||
@@ -627,8 +627,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
|
|||||||
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
|
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
|
||||||
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
|
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
|
||||||
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
|
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
|
||||||
github.com/cs3org/reva/v2 v2.13.3 h1:XP17/bl2EtwYcoX755hcg43EIagP1CAw/+loVFvHHM4=
|
github.com/cs3org/reva/v2 v2.13.4-0.20230517171752-b39e78fd7b28 h1:y8oUHEWGXrs9/jdU0sG3zNRyoDBONyxCRJJfb9Nsbqw=
|
||||||
github.com/cs3org/reva/v2 v2.13.3/go.mod h1:MoymB39kU/myG7LFkaCwqtoXQHct+/8uoZAvJEmNi+I=
|
github.com/cs3org/reva/v2 v2.13.4-0.20230517171752-b39e78fd7b28/go.mod h1:MoymB39kU/myG7LFkaCwqtoXQHct+/8uoZAvJEmNi+I=
|
||||||
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
|
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
|
||||||
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
|
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
|
||||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||||
|
|||||||
Generated
Vendored
+21
-14
@@ -33,6 +33,7 @@ import (
|
|||||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||||
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||||
"github.com/cs3org/reva/v2/internal/http/services/datagateway"
|
"github.com/cs3org/reva/v2/internal/http/services/datagateway"
|
||||||
|
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/net"
|
||||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||||
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
|
||||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||||
@@ -283,26 +284,32 @@ func (s *svc) handleNew(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat the newly created file
|
var fileid string
|
||||||
statRes, err := client.Stat(ctx, statFileReq)
|
if httpRes.Header.Get(net.HeaderOCFileID) != "" {
|
||||||
if err != nil {
|
fileid = httpRes.Header.Get(net.HeaderOCFileID)
|
||||||
writeError(w, r, appErrorServerError, "statting the created file failed", err)
|
} else {
|
||||||
return
|
// Stat the newly created file
|
||||||
}
|
statRes, err := client.Stat(ctx, statFileReq)
|
||||||
|
if err != nil {
|
||||||
|
writeError(w, r, appErrorServerError, "statting the created file failed", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if statRes.Status.Code != rpc.Code_CODE_OK {
|
if statRes.Status.Code != rpc.Code_CODE_OK {
|
||||||
writeError(w, r, appErrorServerError, "statting the created file failed", nil)
|
writeError(w, r, appErrorServerError, "statting the created file failed", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if statRes.Info.Type != provider.ResourceType_RESOURCE_TYPE_FILE {
|
if statRes.Info.Type != provider.ResourceType_RESOURCE_TYPE_FILE {
|
||||||
writeError(w, r, appErrorInvalidParameter, "the given file id does not point to a file", nil)
|
writeError(w, r, appErrorInvalidParameter, "the given file id does not point to a file", nil)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
fileid = storagespace.FormatResourceID(*statRes.Info.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
js, err := json.Marshal(
|
js, err := json.Marshal(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"file_id": storagespace.FormatResourceID(*statRes.Info.Id),
|
"file_id": fileid,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+6
@@ -278,6 +278,12 @@ func (s *svc) handleTusPost(ctx context.Context, w http.ResponseWriter, r *http.
|
|||||||
if length == 0 || httpRes.Header.Get(net.HeaderUploadOffset) == r.Header.Get(net.HeaderUploadLength) {
|
if length == 0 || httpRes.Header.Get(net.HeaderUploadOffset) == r.Header.Get(net.HeaderUploadLength) {
|
||||||
// get uploaded file metadata
|
// get uploaded file metadata
|
||||||
|
|
||||||
|
if resid, err := storagespace.ParseID(httpRes.Header.Get(net.HeaderOCFileID)); err == nil {
|
||||||
|
sReq.Ref = &provider.Reference{
|
||||||
|
ResourceId: &resid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sRes, err := s.gwClient.Stat(ctx, sReq)
|
sRes, err := s.gwClient.Stat(ctx, sReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("error sending grpc stat request")
|
log.Error().Err(err).Msg("error sending grpc stat request")
|
||||||
|
|||||||
Generated
Vendored
+10
-2
@@ -80,8 +80,16 @@ type CapabilitiesCore struct {
|
|||||||
|
|
||||||
// CapabilitiesGraph holds the graph capabilities
|
// CapabilitiesGraph holds the graph capabilities
|
||||||
type CapabilitiesGraph struct {
|
type CapabilitiesGraph struct {
|
||||||
PersonalDataExport ocsBool `json:"personal-data-export" xml:"personal-data-export" mapstructure:"personal_data_export"`
|
PersonalDataExport ocsBool `json:"personal-data-export" xml:"personal-data-export" mapstructure:"personal_data_export"`
|
||||||
ReadOnlyUserAttributes []string `json:"read_only_user_attributes" xml:"read_only_user_attributes" mapstructure:"read_only_user_attributes"`
|
Users CapabilitiesGraphUsers `json:"users" xml:"users" mapstructure:"users"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CapabilitiesGraphUsers holds the graph user capabilities
|
||||||
|
type CapabilitiesGraphUsers struct {
|
||||||
|
ReadOnlyAttributes []string `json:"read_only_attributes" xml:"read_only_attributes" mapstructure:"read_only_attributes"`
|
||||||
|
CreateDisabled ocsBool `json:"create_disabled" xml:"create_disabled" mapstructure:"create_disabled"`
|
||||||
|
DeleteDisabled ocsBool `json:"delete_disabled" xml:"delete_disabled" mapstructure:"delete_disabled"`
|
||||||
|
ChangePasswordSelfDisabled ocsBool `json:"change_password_self_disabled" xml:"change_password_self_disabled" mapstructure:"change_password_self_disabled"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status holds basic status information
|
// Status holds basic status information
|
||||||
|
|||||||
+10
-2
@@ -40,6 +40,7 @@ import (
|
|||||||
"github.com/cs3org/reva/v2/pkg/rhttp/datatx/metrics"
|
"github.com/cs3org/reva/v2/pkg/rhttp/datatx/metrics"
|
||||||
"github.com/cs3org/reva/v2/pkg/storage"
|
"github.com/cs3org/reva/v2/pkg/storage"
|
||||||
"github.com/cs3org/reva/v2/pkg/storage/cache"
|
"github.com/cs3org/reva/v2/pkg/storage/cache"
|
||||||
|
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||||
"github.com/cs3org/reva/v2/pkg/utils"
|
"github.com/cs3org/reva/v2/pkg/utils"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
)
|
)
|
||||||
@@ -144,6 +145,7 @@ func (m *manager) Handler(fs storage.FS) (http.Handler, error) {
|
|||||||
metrics.UploadsActive.Sub(1)
|
metrics.UploadsActive.Sub(1)
|
||||||
}()
|
}()
|
||||||
// set etag, mtime and file id
|
// set etag, mtime and file id
|
||||||
|
setHeaders(fs, w, r)
|
||||||
handler.PostFile(w, r)
|
handler.PostFile(w, r)
|
||||||
case "HEAD":
|
case "HEAD":
|
||||||
handler.HeadFile(w, r)
|
handler.HeadFile(w, r)
|
||||||
@@ -153,7 +155,7 @@ func (m *manager) Handler(fs storage.FS) (http.Handler, error) {
|
|||||||
metrics.UploadsActive.Sub(1)
|
metrics.UploadsActive.Sub(1)
|
||||||
}()
|
}()
|
||||||
// set etag, mtime and file id
|
// set etag, mtime and file id
|
||||||
setExpiresHeader(fs, w, r)
|
setHeaders(fs, w, r)
|
||||||
handler.PatchFile(w, r)
|
handler.PatchFile(w, r)
|
||||||
case "DELETE":
|
case "DELETE":
|
||||||
handler.DelFile(w, r)
|
handler.DelFile(w, r)
|
||||||
@@ -180,7 +182,7 @@ type composable interface {
|
|||||||
UseIn(composer *tusd.StoreComposer)
|
UseIn(composer *tusd.StoreComposer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setExpiresHeader(fs storage.FS, w http.ResponseWriter, r *http.Request) {
|
func setHeaders(fs storage.FS, w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
id := path.Base(r.URL.Path)
|
id := path.Base(r.URL.Path)
|
||||||
datastore, ok := fs.(tusd.DataStore)
|
datastore, ok := fs.(tusd.DataStore)
|
||||||
@@ -202,4 +204,10 @@ func setExpiresHeader(fs storage.FS, w http.ResponseWriter, r *http.Request) {
|
|||||||
if expires != "" {
|
if expires != "" {
|
||||||
w.Header().Set(net.HeaderTusUploadExpires, expires)
|
w.Header().Set(net.HeaderTusUploadExpires, expires)
|
||||||
}
|
}
|
||||||
|
resourceid := provider.ResourceId{
|
||||||
|
StorageId: info.MetaData["providerID"],
|
||||||
|
SpaceId: info.Storage["SpaceRoot"],
|
||||||
|
OpaqueId: info.Storage["NodeId"],
|
||||||
|
}
|
||||||
|
w.Header().Set(net.HeaderOCFileID, storagespace.FormatResourceID(resourceid))
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-19
@@ -652,26 +652,9 @@ func (fs *Decomposedfs) DeleteStorageSpace(ctx context.Context, req *provider.De
|
|||||||
return errtypes.InternalError(fmt.Sprintf("space %s does not have a spacetype, possible corrupt decompsedfs", n.ID))
|
return errtypes.InternalError(fmt.Sprintf("space %s does not have a spacetype, possible corrupt decompsedfs", n.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// - a User with the "delete-all-spaces" permission can delete any space
|
if err := canDeleteSpace(ctx, spaceID, st, purge, n, fs.p); err != nil {
|
||||||
// - spaces of type personal can also be deleted by users with the "delete-all-home-spaces" permission
|
return err
|
||||||
// - otherwise a space can be deleted by its manager (i.e. users have the "remove" grant)
|
|
||||||
switch {
|
|
||||||
case fs.p.DeleteAllSpaces(ctx):
|
|
||||||
// We are allowed to delete any space, no further permission checks needed
|
|
||||||
case st == "personal":
|
|
||||||
if !fs.p.DeleteAllHomeSpaces(ctx) {
|
|
||||||
return errtypes.PermissionDenied(fmt.Sprintf("user is not allowed to delete home space %s", n.ID))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// managers and users with 'space ability' permission are allowed to disable or purge a drive
|
|
||||||
if !fs.p.SpaceAbility(ctx, spaceID) {
|
|
||||||
rp, err := fs.p.AssemblePermissions(ctx, n)
|
|
||||||
if err != nil || !IsManager(rp) {
|
|
||||||
return errtypes.PermissionDenied(fmt.Sprintf("user is not allowed to delete spaces %s", n.ID))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if purge {
|
if purge {
|
||||||
if !n.IsDisabled() {
|
if !n.IsDisabled() {
|
||||||
return errtypes.NewErrtypeFromStatus(status.NewInvalid(ctx, "can't purge enabled space"))
|
return errtypes.NewErrtypeFromStatus(status.NewInvalid(ctx, "can't purge enabled space"))
|
||||||
@@ -1056,3 +1039,35 @@ func isGrantExpired(g *provider.Grant) bool {
|
|||||||
func (fs *Decomposedfs) getSpaceRoot(spaceID string) string {
|
func (fs *Decomposedfs) getSpaceRoot(spaceID string) string {
|
||||||
return filepath.Join(fs.o.Root, "spaces", lookup.Pathify(spaceID, 1, 2))
|
return filepath.Join(fs.o.Root, "spaces", lookup.Pathify(spaceID, 1, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Space deletion can be tricky as there are lots of different cases:
|
||||||
|
// - spaces of type personal can only be disabled and deleted by users with the "delete-all-home-spaces" permission
|
||||||
|
// - a user with the "delete-all-spaces" permission may delete but not enable/disable any project space
|
||||||
|
// - a user with the "Drive.ReadWriteEnabled" permission may enable/disable but not delete any project space
|
||||||
|
// - a project space can always be enabled/disabled/deleted by its manager (i.e. users have the "remove" grant)
|
||||||
|
func canDeleteSpace(ctx context.Context, spaceID string, typ string, purge bool, n *node.Node, p Permissions) error {
|
||||||
|
// delete-all-home spaces allows to disable and delete a personal space
|
||||||
|
if typ == "personal" {
|
||||||
|
if p.DeleteAllHomeSpaces(ctx) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errtypes.PermissionDenied("user is not allowed to delete a personal space")
|
||||||
|
}
|
||||||
|
|
||||||
|
// space managers are allowed to disable and delete their project spaces
|
||||||
|
if rp, err := p.AssemblePermissions(ctx, n); err == nil && IsManager(rp) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete-all-spaces permissions allows to delete (purge, NOT disable) project spaces
|
||||||
|
if purge && p.DeleteAllSpaces(ctx) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drive.ReadWriteEnabled allows to disable a space
|
||||||
|
if !purge && p.SpaceAbility(ctx, spaceID) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return errtypes.PermissionDenied(fmt.Sprintf("user is not allowed to delete space %s", n.ID))
|
||||||
|
}
|
||||||
|
|||||||
Generated
Vendored
+8
-4
@@ -154,6 +154,7 @@ func New(ctx context.Context, info tusd.FileInfo, lu *lookup.Lookup, tp Tree, p
|
|||||||
"BinPath": binPath,
|
"BinPath": binPath,
|
||||||
|
|
||||||
"NodeId": n.ID,
|
"NodeId": n.ID,
|
||||||
|
"NodeExists": "true",
|
||||||
"NodeParentId": n.ParentID,
|
"NodeParentId": n.ParentID,
|
||||||
"NodeName": n.Name,
|
"NodeName": n.Name,
|
||||||
"SpaceRoot": spaceRoot,
|
"SpaceRoot": spaceRoot,
|
||||||
@@ -166,6 +167,11 @@ func New(ctx context.Context, info tusd.FileInfo, lu *lookup.Lookup, tp Tree, p
|
|||||||
|
|
||||||
"LogLevel": log.GetLevel().String(),
|
"LogLevel": log.GetLevel().String(),
|
||||||
}
|
}
|
||||||
|
if !n.Exists {
|
||||||
|
// fill future node info
|
||||||
|
info.Storage["NodeId"] = uuid.New().String()
|
||||||
|
info.Storage["NodeExists"] = "false"
|
||||||
|
}
|
||||||
// Create binary file in the upload folder with no content
|
// Create binary file in the upload folder with no content
|
||||||
log.Debug().Interface("info", info).Msg("Decomposedfs: built storage info")
|
log.Debug().Interface("info", info).Msg("Decomposedfs: built storage info")
|
||||||
file, err := os.OpenFile(binPath, os.O_CREATE|os.O_WRONLY, defaultFilePerm)
|
file, err := os.OpenFile(binPath, os.O_CREATE|os.O_WRONLY, defaultFilePerm)
|
||||||
@@ -267,8 +273,8 @@ func CreateNodeForUpload(upload *Upload, initAttrs node.Attributes) (*node.Node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var f *lockedfile.File
|
var f *lockedfile.File
|
||||||
switch n.ID {
|
switch upload.Info.Storage["NodeExists"] {
|
||||||
case "":
|
case "false":
|
||||||
f, err = initNewNode(upload, n, uint64(fsize))
|
f, err = initNewNode(upload, n, uint64(fsize))
|
||||||
default:
|
default:
|
||||||
f, err = updateExistingNode(upload, n, spaceID, uint64(fsize))
|
f, err = updateExistingNode(upload, n, spaceID, uint64(fsize))
|
||||||
@@ -320,8 +326,6 @@ func CreateNodeForUpload(upload *Upload, initAttrs node.Attributes) (*node.Node,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initNewNode(upload *Upload, n *node.Node, fsize uint64) (*lockedfile.File, error) {
|
func initNewNode(upload *Upload, n *node.Node, fsize uint64) (*lockedfile.File, error) {
|
||||||
n.ID = uuid.New().String()
|
|
||||||
|
|
||||||
// create folder structure (if needed)
|
// create folder structure (if needed)
|
||||||
if err := os.MkdirAll(filepath.Dir(n.InternalPath()), 0700); err != nil {
|
if err := os.MkdirAll(filepath.Dir(n.InternalPath()), 0700); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
Vendored
+1
-1
@@ -349,7 +349,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
|
|||||||
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
|
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
|
||||||
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
|
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
|
||||||
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
|
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
|
||||||
# github.com/cs3org/reva/v2 v2.13.3
|
# github.com/cs3org/reva/v2 v2.13.4-0.20230517171752-b39e78fd7b28
|
||||||
## explicit; go 1.19
|
## explicit; go 1.19
|
||||||
github.com/cs3org/reva/v2/cmd/revad/internal/grace
|
github.com/cs3org/reva/v2/cmd/revad/internal/grace
|
||||||
github.com/cs3org/reva/v2/cmd/revad/runtime
|
github.com/cs3org/reva/v2/cmd/revad/runtime
|
||||||
|
|||||||
Reference in New Issue
Block a user