Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[full-ci] Bump reva & merge unrestrict combined #3637

Merged
merged 16 commits into from
May 2, 2022
6 changes: 6 additions & 0 deletions changelog/unreleased/graph-me-drives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Change: Reduce drives in graph /me/drives API

Reduced the drives in the graph `/me/drives` API to only the drives the user has access to.
The endpoint `/drives` will list all drives when the user has the permission.

https://github.com/owncloud/ocis/pull/3629
1 change: 1 addition & 0 deletions changelog/unreleased/update-reva.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ https://github.com/owncloud/ocis/pull/3570
https://github.com/owncloud/ocis/pull/3601
https://github.com/owncloud/ocis/pull/3605
https://github.com/owncloud/ocis/pull/3611
https://github.com/owncloud/ocis/pull/3621
26 changes: 13 additions & 13 deletions extensions/audit/pkg/service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@ var testCases = []struct {
}, {
Alias: "File created",
SystemEvent: events.FileUploaded{
FileID: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
Ref: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
},
CheckAuditEvent: func(t *testing.T, b []byte) {
ev := types.AuditEventFileCreated{}
Expand All @@ -312,8 +312,8 @@ var testCases = []struct {
}, {
Alias: "File read",
SystemEvent: events.FileDownloaded{
FileID: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
Ref: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
},
CheckAuditEvent: func(t *testing.T, b []byte) {
ev := types.AuditEventFileRead{}
Expand All @@ -327,8 +327,8 @@ var testCases = []struct {
}, {
Alias: "File trashed",
SystemEvent: events.ItemTrashed{
FileID: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
Ref: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
},
CheckAuditEvent: func(t *testing.T, b []byte) {
ev := types.AuditEventFileDeleted{}
Expand All @@ -342,7 +342,7 @@ var testCases = []struct {
}, {
Alias: "File renamed",
SystemEvent: events.ItemMoved{
FileID: reference("sto-123", "iid-123", "./item"),
Ref: reference("sto-123", "iid-123", "./item"),
OldReference: reference("sto-123", "iid-123", "./anotheritem"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
},
Expand All @@ -361,8 +361,8 @@ var testCases = []struct {
}, {
Alias: "File purged",
SystemEvent: events.ItemPurged{
FileID: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
Ref: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
},
CheckAuditEvent: func(t *testing.T, b []byte) {
ev := types.AuditEventFilePurged{}
Expand All @@ -376,7 +376,7 @@ var testCases = []struct {
}, {
Alias: "File restored",
SystemEvent: events.ItemRestored{
FileID: reference("sto-123", "iid-123", "./item"),
Ref: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
OldReference: reference("sto-123", "sto-123!iid-123/item", "./oldpath"),
Key: "",
Expand All @@ -396,9 +396,9 @@ var testCases = []struct {
}, {
Alias: "File version restored",
SystemEvent: events.FileVersionRestored{
FileID: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
Key: "v1",
Ref: reference("sto-123", "iid-123", "./item"),
Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva
Key: "v1",
},
CheckAuditEvent: func(t *testing.T, b []byte) {
ev := types.AuditEventFileVersionRestored{}
Expand Down
14 changes: 7 additions & 7 deletions extensions/audit/pkg/types/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func FilesAuditEvent(base AuditEvent, itemid, owner, path string) AuditEventFile

// FileUploaded converts a FileUploaded event to an AuditEventFileCreated
func FileUploaded(ev events.FileUploaded) AuditEventFileCreated {
iid, path, uid := extractFileDetails(ev.FileID, ev.Owner)
iid, path, uid := extractFileDetails(ev.Ref, ev.Owner)
base := BasicAuditEvent(uid, "", MessageFileCreated(iid), ActionFileCreated)
return AuditEventFileCreated{
AuditEventFiles: FilesAuditEvent(base, iid, uid, path),
Expand All @@ -243,7 +243,7 @@ func FileUploaded(ev events.FileUploaded) AuditEventFileCreated {

// FileDownloaded converts a FileDownloaded event to an AuditEventFileRead
func FileDownloaded(ev events.FileDownloaded) AuditEventFileRead {
iid, path, uid := extractFileDetails(ev.FileID, ev.Owner)
iid, path, uid := extractFileDetails(ev.Ref, ev.Owner)
base := BasicAuditEvent(uid, "", MessageFileRead(iid), ActionFileRead)
return AuditEventFileRead{
AuditEventFiles: FilesAuditEvent(base, iid, uid, path),
Expand All @@ -252,7 +252,7 @@ func FileDownloaded(ev events.FileDownloaded) AuditEventFileRead {

// ItemMoved converts a ItemMoved event to an AuditEventFileRenamed
func ItemMoved(ev events.ItemMoved) AuditEventFileRenamed {
iid, path, uid := extractFileDetails(ev.FileID, ev.Owner)
iid, path, uid := extractFileDetails(ev.Ref, ev.Owner)

oldpath := ""
if ev.OldReference != nil {
Expand All @@ -268,7 +268,7 @@ func ItemMoved(ev events.ItemMoved) AuditEventFileRenamed {

// ItemTrashed converts a ItemTrashed event to an AuditEventFileDeleted
func ItemTrashed(ev events.ItemTrashed) AuditEventFileDeleted {
iid, path, uid := extractFileDetails(ev.FileID, ev.Owner)
iid, path, uid := extractFileDetails(ev.Ref, ev.Owner)
base := BasicAuditEvent(uid, "", MessageFileTrashed(iid), ActionFileTrashed)
return AuditEventFileDeleted{
AuditEventFiles: FilesAuditEvent(base, iid, uid, path),
Expand All @@ -277,7 +277,7 @@ func ItemTrashed(ev events.ItemTrashed) AuditEventFileDeleted {

// ItemPurged converts a ItemPurged event to an AuditEventFilePurged
func ItemPurged(ev events.ItemPurged) AuditEventFilePurged {
iid, path, uid := extractFileDetails(ev.FileID, ev.Owner)
iid, path, uid := extractFileDetails(ev.Ref, ev.Owner)
base := BasicAuditEvent(uid, "", MessageFilePurged(iid), ActionFilePurged)
return AuditEventFilePurged{
AuditEventFiles: FilesAuditEvent(base, iid, uid, path),
Expand All @@ -286,7 +286,7 @@ func ItemPurged(ev events.ItemPurged) AuditEventFilePurged {

// ItemRestored converts a ItemRestored event to an AuditEventFileRestored
func ItemRestored(ev events.ItemRestored) AuditEventFileRestored {
iid, path, uid := extractFileDetails(ev.FileID, ev.Owner)
iid, path, uid := extractFileDetails(ev.Ref, ev.Owner)

oldpath := ""
if ev.OldReference != nil {
Expand All @@ -302,7 +302,7 @@ func ItemRestored(ev events.ItemRestored) AuditEventFileRestored {

// FileVersionRestored converts a FileVersionRestored event to an AuditEventFileVersionRestored
func FileVersionRestored(ev events.FileVersionRestored) AuditEventFileVersionRestored {
iid, path, uid := extractFileDetails(ev.FileID, ev.Owner)
iid, path, uid := extractFileDetails(ev.Ref, ev.Owner)
base := BasicAuditEvent(uid, "", MessageFileVersionRestored(iid, ev.Key), ActionFileVersionRestored)
return AuditEventFileVersionRestored{
AuditEventFiles: FilesAuditEvent(base, iid, uid, path),
Expand Down
58 changes: 44 additions & 14 deletions extensions/graph/pkg/service/v0/drives.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,19 @@ import (
merrors "go-micro.dev/v4/errors"
)

// GetDrives implements the Service interface.
// GetDrives lists all drives the current user has access to
func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) {
g.getDrives(w, r, false)
}

// GetAllDrives lists all drives, including other user's drives, if the current
// user has the permission.
func (g Graph) GetAllDrives(w http.ResponseWriter, r *http.Request) {
g.getDrives(w, r, true)
}

// getDrives implements the Service interface.
func (g Graph) getDrives(w http.ResponseWriter, r *http.Request, unrestricted bool) {
sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/")
// Parse the request with odata parser
odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query())
Expand All @@ -41,7 +52,10 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
return
}
g.logger.Info().Interface("query", r.URL.Query()).Msg("Calling GetDrives")
g.logger.Debug().
Interface("query", r.URL.Query()).
Bool("unrestricted", unrestricted).
Msg("Calling getDrives")
ctx := r.Context()

filters, err := generateCs3Filters(odataReq)
Expand All @@ -50,7 +64,7 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) {
errorcode.NotSupported.Render(w, r, http.StatusNotImplemented, err.Error())
return
}
res, err := g.ListStorageSpacesWithFilters(ctx, filters)
res, err := g.ListStorageSpacesWithFilters(ctx, filters, unrestricted)
switch {
case err != nil:
g.logger.Error().Err(err).Msg(ListStorageSpacesTransportErr)
Expand Down Expand Up @@ -106,7 +120,7 @@ func (g Graph) GetSingleDrive(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

filters := []*storageprovider.ListStorageSpacesRequest_Filter{listStorageSpacesIDFilter(driveID)}
res, err := g.ListStorageSpacesWithFilters(ctx, filters)
res, err := g.ListStorageSpacesWithFilters(ctx, filters, true)
switch {
case err != nil:
g.logger.Error().Err(err).Msg(ListStorageSpacesTransportErr)
Expand Down Expand Up @@ -273,7 +287,8 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
identifierParts := strings.Split(driveID, "!")
switch len(identifierParts) {
case 1:
root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[0]
sID, _ := resourceid.StorageIDUnwrap(identifierParts[0])
root.StorageId, root.OpaqueId = identifierParts[0], sID
case 2:
root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[1]
default:
Expand Down Expand Up @@ -398,7 +413,7 @@ func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces
}

// ListStorageSpacesWithFilters List Storage Spaces using filters
func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*storageprovider.ListStorageSpacesRequest_Filter) (*storageprovider.ListStorageSpacesResponse, error) {
func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*storageprovider.ListStorageSpacesRequest_Filter, unrestricted bool) (*storageprovider.ListStorageSpacesResponse, error) {
client := g.GetGatewayClient()

permissions := make(map[string]struct{}, 1)
Expand All @@ -423,17 +438,35 @@ func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*stor
Decoder: "json",
Value: value,
},
"unrestricted": {
Decoder: "plain",
Value: []byte(strconv.FormatBool(unrestricted)),
},
}},
Filters: filters,
})
return res, err
}

func generateSpaceId(id *storageprovider.ResourceId) (spaceID string) {
spaceID = id.GetStorageId()
// 2nd ID to compare is the opaque ID of the Space Root
spaceID2 := id.GetOpaqueId()
if strings.Contains(spaceID, "$") {
spaceID2, _ = resourceid.StorageIDUnwrap(spaceID)
}
// Append opaqueID only if it is different from the spaceID2
if id.OpaqueId != spaceID2 {
spaceID += "!" + id.OpaqueId
}
return spaceID
}

func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, space *storageprovider.StorageSpace) (*libregraph.Drive, error) {
if space.Root == nil {
return nil, fmt.Errorf("space has no root")
}
rootID := resourceid.OwnCloudResourceIDWrap(space.Root)
spaceID := generateSpaceId(space.Root)

var permissions []libregraph.Permission
if space.Opaque != nil {
Expand Down Expand Up @@ -491,18 +524,14 @@ func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, spa
}
}

spaceID := space.Root.StorageId
if space.Root.OpaqueId != space.Root.StorageId {
spaceID = rootID
}
drive := &libregraph.Drive{
Id: &spaceID,
Id: libregraph.PtrString(spaceID),
Name: &space.Name,
//"createdDateTime": "string (timestamp)", // TODO read from StorageSpace ... needs Opaque for now
//"description": "string", // TODO read from StorageSpace ... needs Opaque for now
DriveType: &space.SpaceType,
Root: &libregraph.DriveItem{
Id: &rootID,
Id: libregraph.PtrString(resourceid.OwnCloudResourceIDWrap(space.Root)),
Permissions: permissions,
},
}
Expand Down Expand Up @@ -735,9 +764,10 @@ func (g Graph) DeleteDrive(w http.ResponseWriter, r *http.Request) {
root := &storageprovider.ResourceId{}

identifierParts := strings.Split(driveID, "!")
sID, _ := resourceid.StorageIDUnwrap(identifierParts[0])
switch len(identifierParts) {
case 1:
root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[0]
root.StorageId, root.OpaqueId = identifierParts[0], sID
case 2:
root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[1]
default:
Expand Down
8 changes: 4 additions & 4 deletions extensions/graph/pkg/service/v0/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ var _ = Describe("Graph", func() {
Id: &provider.StorageSpaceId{OpaqueId: "aID!differentID"},
SpaceType: "mountpoint",
Root: &provider.ResourceId{
StorageId: "aID",
StorageId: "prID$aID",
OpaqueId: "differentID",
},
Name: "New Folder",
Expand Down Expand Up @@ -246,11 +246,11 @@ var _ = Describe("Graph", func() {
value := response["value"][0]
Expect(*value.DriveAlias).To(Equal("mountpoint/new-folder"))
Expect(*value.DriveType).To(Equal("mountpoint"))
Expect(*value.Id).To(Equal("aID!differentID"))
Expect(*value.Id).To(Equal("prID$aID!differentID"))
Expect(*value.Name).To(Equal("New Folder"))
Expect(*value.Root.WebDavUrl).To(Equal("https://localhost:9200/dav/spaces/aID!differentID"))
Expect(*value.Root.WebDavUrl).To(Equal("https://localhost:9200/dav/spaces/prID$aID!differentID"))
Expect(*value.Root.ETag).To(Equal("101112131415"))
Expect(*value.Root.Id).To(Equal("aID!differentID"))
Expect(*value.Root.Id).To(Equal("prID$aID!differentID"))
Expect(*value.Root.RemoteItem.ETag).To(Equal("123456789"))
Expect(*value.Root.RemoteItem.Id).To(Equal("ownerStorageID!opaqueID"))
Expect(value.Root.RemoteItem.LastModifiedDateTime.UTC()).To(Equal(time.Unix(1648327606, 0).UTC()))
Expand Down
2 changes: 1 addition & 1 deletion extensions/graph/pkg/service/v0/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func NewService(opts ...Option) Service {
account.JWTSecret(options.Config.TokenManager.JWTSecret)),
)
r.Route("/drives", func(r chi.Router) {
r.Get("/", svc.GetDrives)
r.Get("/", svc.GetAllDrives)
r.Post("/", svc.CreateDrive)
r.Route("/{driveID}", func(r chi.Router) {
r.Patch("/", svc.UpdateDrive)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/blevesearch/bleve/v2 v2.3.2
github.com/coreos/go-oidc/v3 v3.1.0
github.com/cs3org/go-cs3apis v0.0.0-20220412090512-93c5918b4bde
github.com/cs3org/reva/v2 v2.0.0-20220427203355-0164880ac7d3
github.com/cs3org/reva/v2 v2.0.0-20220502075009-8bcec2e4663e
github.com/disintegration/imaging v1.6.2
github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733
github.com/go-chi/chi/v5 v5.0.7
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,8 @@ github.com/cs3org/go-cs3apis v0.0.0-20220412090512-93c5918b4bde h1:WrD9O8ZaWvsm0
github.com/cs3org/go-cs3apis v0.0.0-20220412090512-93c5918b4bde/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva v1.18.0 h1:MbPS5ZAa8RzKcTxAVeSDdISB3XXqLIxqB03BTN5ReBY=
github.com/cs3org/reva v1.18.0/go.mod h1:e5VDUDu4vVWIeVkZcW//n6UZzhGGMa+Tz/whCiX3N6o=
github.com/cs3org/reva/v2 v2.0.0-20220427133111-618964eed515 h1:8pPCLxNXVz/q7PMM6Zq1lff3P8SFAu8/CXwB2eA21xc=
github.com/cs3org/reva/v2 v2.0.0-20220427133111-618964eed515/go.mod h1:2e/4HcIy54Mic3V7Ow0bz4n5dkZU0dHIZSWomFe5vng=
github.com/cs3org/reva/v2 v2.0.0-20220427203355-0164880ac7d3 h1:6sKjGI0AUW5tBXWBduaBoc+9sNYZWQR894G0oFCbus0=
github.com/cs3org/reva/v2 v2.0.0-20220427203355-0164880ac7d3/go.mod h1:2e/4HcIy54Mic3V7Ow0bz4n5dkZU0dHIZSWomFe5vng=
github.com/cs3org/reva/v2 v2.0.0-20220502075009-8bcec2e4663e h1:ym80MMvfFLHMxt6aiU67kTe/pzRBaSOUNdPkmeKYejk=
github.com/cs3org/reva/v2 v2.0.0-20220502075009-8bcec2e4663e/go.mod h1:2e/4HcIy54Mic3V7Ow0bz4n5dkZU0dHIZSWomFe5vng=
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/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
Expand Down
4 changes: 0 additions & 4 deletions tests/acceptance/expected-failures-API-on-OCIS-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -1847,10 +1847,6 @@ Not everything needs to be implemented for ocis. While the oc10 testsuite covers
#### [OCS status code zero](https://github.com/owncloud/ocis/issues/3621)
- [apiShareManagementToShares/moveReceivedShare.feature:32](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/moveReceivedShare.feature#L32)

#### [share_with_user_type is not set in response](https://github.com/owncloud/ocis/issues/3622)
- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L37)
- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:38](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L38)

#### [HTTP status code differ while listing the contents of another user's trash bin](https://github.com/owncloud/ocis/issues/3561)
- [apiTrashbin/trashbinFilesFolders.feature:199](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L199)
- [apiTrashbin/trashbinFilesFolders.feature:223](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L223)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1639,10 +1639,6 @@ Not everything needs to be implemented for ocis. While the oc10 testsuite covers
#### [OCS status code zero](https://github.com/owncloud/ocis/issues/3621)
- [apiShareManagementToShares/moveReceivedShare.feature:32](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/moveReceivedShare.feature#L32)

#### [share_with_user_type is not set in response](https://github.com/owncloud/ocis/issues/3622)
- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L37)
- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:38](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L38)

#### [HTTP status code differ while listing the contents of another user's trash bin](https://github.com/owncloud/ocis/issues/3561)
- [apiTrashbin/trashbinFilesFolders.feature:199](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L199)
- [apiTrashbin/trashbinFilesFolders.feature:223](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L223)
Expand Down
Loading