Repository: owncloud/ocis
Pull request #3185 (2022-02-16 16:45:30)

[full-ci] Unify id format
# Description

## Change: Unify file IDs

We changed the file IDs to be consistent across all our APIs (WebDAV, LibreGraph, OCS). We removed the base64 encoding. Now they are formatted like `<storageID>!<opaqueID>`. They are using a reserved character ``!`` as a URL safe separator.

## Related Issue

Reva PR https://github.com/cs3org/reva/pull/2542

## Motivation and Context

FileIDs should be consistent across all APIs

## How Has This Been Tested?
- Manually
- CI

## Examples:

### WebDAV
```bash
curl -L -X PROPFIND 'https://localhost:9200/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f' \
-H 'Depth: infinity' \
-H 'Authorization: Basic YWRtaW46YWRtaW4='
```

```xml
<d:multistatus xmlns:s="http://sabredav.org/ns" xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
    <d:response>
        <d:href>/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/</d:href>
        <d:propstat>
            <d:prop>
                <oc:id>6afcb97a-e632-447d-b832-1334a8a9634f!6afcb97a-e632-447d-b832-1334a8a9634f</oc:id>
                <oc:fileid>6afcb97a-e632-447d-b832-1334a8a9634f!6afcb97a-e632-447d-b832-1334a8a9634f</oc:fileid>
                <d:getetag>&#34;55e95f454e48c0047d901686f4f7027c&#34;</d:getetag>
                <oc:permissions>RDNVCK</oc:permissions>
                <d:resourcetype>
                    <d:collection/>
                </d:resourcetype>
                <oc:size>2019472</oc:size>
                <d:getlastmodified>Tue, 15 Feb 2022 11:42:10 GMT</d:getlastmodified>
                <oc:favorite>0</oc:favorite>
            </d:prop>
            <d:status>HTTP/1.1 200 OK</d:status>
        </d:propstat>
    </d:response>
    <d:response>
        <d:href>/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/Space_Image.jpg</d:href>
        <d:propstat>
            <d:prop>
                <oc:id>6afcb97a-e632-447d-b832-1334a8a9634f!83a2c6ab-19f2-4f51-b3cb-41aef54ee5ab</oc:id>
                <oc:fileid>6afcb97a-e632-447d-b832-1334a8a9634f!83a2c6ab-19f2-4f51-b3cb-41aef54ee5ab</oc:fileid>
                <d:getetag>&#34;0440204b65664c18fa73a40cfe625815&#34;</d:getetag>
                <oc:permissions>RDNVW</oc:permissions>
                <d:resourcetype></d:resourcetype>
                <d:getcontentlength>2019367</d:getcontentlength>
                <d:getcontenttype>image/jpeg</d:getcontenttype>
                <d:getlastmodified>Tue, 15 Feb 2022 11:42:10 GMT</d:getlastmodified>
                <oc:checksums>
                    <oc:checksum>SHA1:439c4a6de0489288bb88914913fd1e5ece7d1764 MD5:2540f4e8f934296b617973f1a5cd5ae3 ADLER32:1c056526</oc:checksum>
                </oc:checksums>
                <oc:favorite>0</oc:favorite>
            </d:prop>
            <d:status>HTTP/1.1 200 OK</d:status>
        </d:propstat>
    </d:response>
    <d:response>
        <d:href>/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/NewFile5.md</d:href>
        <d:propstat>
            <d:prop>
                <oc:id>6afcb97a-e632-447d-b832-1334a8a9634f!44b8c8ba-8f57-452f-9b28-85b2058bdac8</oc:id>
                <oc:fileid>6afcb97a-e632-447d-b832-1334a8a9634f!44b8c8ba-8f57-452f-9b28-85b2058bdac8</oc:fileid>
                <d:getetag>&#34;6f35041017b213007453cd8d74ccb331&#34;</d:getetag>
                <oc:permissions>RDNVW</oc:permissions>
                <d:resourcetype></d:resourcetype>
                <d:getcontentlength>105</d:getcontentlength>
                <d:getcontenttype>text/markdown</d:getcontenttype>
                <d:getlastmodified>Tue, 15 Feb 2022 11:41:34 GMT</d:getlastmodified>
                <oc:checksums>
                    <oc:checksum>SHA1:081272bd25665a1a884fd50f3143220411c6e8a3 MD5:9bdb7fc99749fb9b2207358aec781742 ADLER32:dd6928f0</oc:checksum>
                </oc:checksums>
                <oc:favorite>0</oc:favorite>
            </d:prop>
            <d:status>HTTP/1.1 200 OK</d:status>
        </d:propstat>
    </d:response>
    <d:response>
        <d:href>/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/NewFolder/</d:href>
        <d:propstat>
            <d:prop>
                <oc:id>6afcb97a-e632-447d-b832-1334a8a9634f!dc4399c7-1fed-46e1-b81d-36c3db1c74ba</oc:id>
                <oc:fileid>6afcb97a-e632-447d-b832-1334a8a9634f!dc4399c7-1fed-46e1-b81d-36c3db1c74ba</oc:fileid>
                <d:getetag>&#34;0e0ec707e062c806e5e48faefcdca725&#34;</d:getetag>
                <oc:permissions>RDNVCK</oc:permissions>
                <d:resourcetype>
                    <d:collection/>
                </d:resourcetype>
                <oc:size>0</oc:size>
                <d:getlastmodified>Tue, 15 Feb 2022 11:40:51 GMT</d:getlastmodified>
                <oc:favorite>0</oc:favorite>
            </d:prop>
            <d:status>HTTP/1.1 200 OK</d:status>
        </d:propstat>
    </d:response>
</d:multistatus>
```

### GraphAPI
```bash
curl -L -X GET 'https://localhost:9200/graph/v1.0/me/drives/?$filter=id eq '\''6afcb97a-e632-447d-b832-1334a8a9634f'\''' \
-H 'Authorization: Basic YWRtaW46YWRtaW4='
```

```json
{
    "value": [
        {
            "description": "USS Enterprise D",
            "driveType": "project",
            "id": "6afcb97a-e632-447d-b832-1334a8a9634f",
            "lastModifiedDateTime": "2022-02-15T12:42:10.508053+01:00",
            "name": "Project Spaceship",
            "quota": {
                "remaining": 997980528,
                "state": "normal",
                "total": 1000000000,
                "used": 2019472
            },
            "root": {
                "id": "6afcb97a-e632-447d-b832-1334a8a9634f!6afcb97a-e632-447d-b832-1334a8a9634f",
                "permissions": [
                    {
                        "grantedTo": [
                            {
                                "user": {
                                    "id": "ddc2004c-0977-11eb-9d3f-a793888cd0f8"
                                }
                            },
                            {
                                "user": {
                                    "id": "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"
                                }
                            }
                        ],
                        "roles": [
                            "manager"
                        ]
                    }
                ],
                "webDavUrl": "https://localhost:9200/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f"
            },
            "special": [
                {
                    "eTag": "\"0440204b65664c18fa73a40cfe625815\"",
                    "file": {
                        "mimeType": "image/jpeg"
                    },
                    "id": "6afcb97a-e632-447d-b832-1334a8a9634f!83a2c6ab-19f2-4f51-b3cb-41aef54ee5ab",
                    "lastModifiedDateTime": "2022-02-15T12:42:10.507576189+01:00",
                    "name": "Space_Image.jpg",
                    "size": 2019367,
                    "specialFolder": {
                        "name": "image"
                    },
                    "webDavUrl": "https://localhost:9200/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/Space_Image.jpg"
                },
                {
                    "eTag": "\"6f35041017b213007453cd8d74ccb331\"",
                    "file": {
                        "mimeType": "text/markdown"
                    },
                    "id": "6afcb97a-e632-447d-b832-1334a8a9634f!44b8c8ba-8f57-452f-9b28-85b2058bdac8",
                    "lastModifiedDateTime": "2022-02-15T12:41:34.435893364+01:00",
                    "name": "NewFile5.md",
                    "size": 105,
                    "specialFolder": {
                        "name": "readme"
                    },
                    "webDavUrl": "https://localhost:9200/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/NewFile5.md"
                }
            ]
        }
    ]
}
```

### GraphAPI (Set Space Image)
```bash
curl -L -X PATCH 'https://localhost:9200/graph/v1.0/drives/6afcb97a-e632-447d-b832-1334a8a9634f' \
-H 'Authorization: Basic YWRtaW46YWRtaW4=' \
-H 'Content-Type: application/json' \
--data-raw '{
  "description": "Moon over the horizon",
  "special":[
      {
          "specialFolder": {
              "name": "image"
          },
          "id": "6afcb97a-e632-447d-b832-1334a8a9634f!83a2c6ab-19f2-4f51-b3cb-41aef54ee5ab"
      }
  ]
}'
```

```json
{
    "description": "Moon over the horizon",
    "driveType": "project",
    "id": "6afcb97a-e632-447d-b832-1334a8a9634f",
    "lastModifiedDateTime": "2022-02-15T12:42:10.508053+01:00",
    "name": "Project Spaceship",
    "quota": {
        "remaining": 997980528,
        "state": "normal",
        "total": 1000000000,
        "used": 2019472
    },
    "root": {
        "id": "6afcb97a-e632-447d-b832-1334a8a9634f!6afcb97a-e632-447d-b832-1334a8a9634f",
        "permissions": [
            {
                "grantedTo": [
                    {
                        "user": {
                            "id": "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"
                        }
                    },
                    {
                        "user": {
                            "id": "ddc2004c-0977-11eb-9d3f-a793888cd0f8"
                        }
                    }
                ],
                "roles": [
                    "manager"
                ]
            }
        ],
        "webDavUrl": "https://localhost:9200/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f"
    },
    "special": [
        {
            "eTag": "\"0440204b65664c18fa73a40cfe625815\"",
            "file": {
                "mimeType": "image/jpeg"
            },
            "id": "6afcb97a-e632-447d-b832-1334a8a9634f!83a2c6ab-19f2-4f51-b3cb-41aef54ee5ab",
            "lastModifiedDateTime": "2022-02-15T12:42:10.507576189+01:00",
            "name": "Space_Image.jpg",
            "size": 2019367,
            "specialFolder": {
                "name": "image"
            },
            "webDavUrl": "https://localhost:9200/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/Space_Image.jpg"
        },
        {
            "eTag": "\"6f35041017b213007453cd8d74ccb331\"",
            "file": {
                "mimeType": "text/markdown"
            },
            "id": "6afcb97a-e632-447d-b832-1334a8a9634f!44b8c8ba-8f57-452f-9b28-85b2058bdac8",
            "lastModifiedDateTime": "2022-02-15T12:41:34.435893364+01:00",
            "name": "NewFile5.md",
            "size": 105,
            "specialFolder": {
                "name": "readme"
            },
            "webDavUrl": "https://localhost:9200/dav/spaces/6afcb97a-e632-447d-b832-1334a8a9634f/NewFile5.md"
        }
    ]
}
```
### OCS (Add users to spaces)
```bash
curl -L -X POST 'https://localhost:9200/ocs/v1.php/apps/files_sharing/api/v1/shares?shareType=7&shareWith=marie&space_ref=6afcb97a-e632-447d-b832-1334a8a9634f!6afcb97a-e632-447d-b832-1334a8a9634f&role=manager' \
-H 'Authorization: Basic YWRtaW46YWRtaW4='
```

### Manual Archiver Test

<img width="1792" alt="Bildschirmfoto 2022-02-16 um 21 58 09" src="https://user-images.githubusercontent.com/4378513/154356038-383d5de7-48f1-4cd3-8b84-79c89e80b199.png">

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing functionality to change)
- [x] Technical debt
- [ ] Tests only (no source changes)

## Checklist:
<!-- Tick the checkboxes when done. -->
<!-- Raise documentation ticket in owncloud.github.io/ -->
- [x] Code changes
- [x] Unit tests added
- [x] Acceptance tests added
- [ ] Documentation ticket raised: <link> 



Patch:
diff --git a/changelog/unreleased/unify-file-ids.md b/changelog/unreleased/unify-file-ids.md
new file mode 100644
index 00000000000..10f13a9dcf0
--- /dev/null
+++ b/changelog/unreleased/unify-file-ids.md
@@ -0,0 +1,5 @@
+Change: Unify file IDs
+
+We changed the file IDs to be consistent across all our APIs (WebDAV, LibreGraph, OCS). We removed the base64 encoding. Now they are formatted like <storageID>!<opaqueID>. They are using a reserved character ``!`` as a URL safe separator.
+
+https://github.com/owncloud/ocis/pull/3185
diff --git a/go.mod b/go.mod
index a68352d4a9b..1e290ad4e18 100644
--- a/go.mod
+++ b/go.mod
@@ -21,7 +21,7 @@ require (
 	github.com/blevesearch/bleve/v2 v2.3.0
 	github.com/coreos/go-oidc/v3 v3.1.0
 	github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19
-	github.com/cs3org/reva v1.16.1-0.20220215130802-df1264deff58
+	github.com/cs3org/reva v1.16.1-0.20220216213129-67204fec6e50
 	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
diff --git a/go.sum b/go.sum
index 9227da0676c..fc777cd440a 100644
--- a/go.sum
+++ b/go.sum
@@ -337,10 +337,8 @@ github.com/crewjam/saml v0.4.5/go.mod h1:qCJQpUtZte9R1ZjUBcW8qtCNlinbO363ooNl02S
 github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
 github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19 h1:1jqPH58jCxvbaJ9WLIJ7W2/m622bWS6ChptzljSG6IQ=
 github.com/cs3org/go-cs3apis v0.0.0-20220126114148-64c025ccdd19/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
-github.com/cs3org/reva v1.16.1-0.20220214105747-d217886c962b h1:E53EHbKiHIIJeZgDEx5tE3AflxgL1dHughNbBQU7Dfk=
-github.com/cs3org/reva v1.16.1-0.20220214105747-d217886c962b/go.mod h1:gdKuhou74V47snANuHNIhGNJfCKUSCHPPvuhSx7nu5M=
-github.com/cs3org/reva v1.16.1-0.20220215130802-df1264deff58 h1:CBSpClYZp8Q7Cl/xENW42Zy7M9+vqACAulqXFnWn3Ug=
-github.com/cs3org/reva v1.16.1-0.20220215130802-df1264deff58/go.mod h1:gdKuhou74V47snANuHNIhGNJfCKUSCHPPvuhSx7nu5M=
+github.com/cs3org/reva v1.16.1-0.20220216213129-67204fec6e50 h1:K5HI9Pyq7hF6FH5Sc4phrkgFtLNMo0NrEL8NoEjWU/E=
+github.com/cs3org/reva v1.16.1-0.20220216213129-67204fec6e50/go.mod h1:gdKuhou74V47snANuHNIhGNJfCKUSCHPPvuhSx7nu5M=
 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=
diff --git a/graph/pkg/service/v0/driveitems.go b/graph/pkg/service/v0/driveitems.go
index a698652b901..3b188a89d12 100644
--- a/graph/pkg/service/v0/driveitems.go
+++ b/graph/pkg/service/v0/driveitems.go
@@ -11,6 +11,7 @@ import (
 	cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
 	storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
 	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
+	"github.com/cs3org/reva/pkg/utils/resourceid"
 	"github.com/go-chi/render"
 	libregraph "github.com/owncloud/libre-graph-api-go"
 	"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
@@ -113,7 +114,7 @@ func cs3ResourceToDriveItem(res *storageprovider.ResourceInfo) (*libregraph.Driv
 	*size = int64(res.Size) // TODO lurking overflow: make size of libregraph drive item use uint64
 
 	driveItem := &libregraph.DriveItem{
-		Id:   &res.Id.OpaqueId,
+		Id:   libregraph.PtrString(resourceid.OwnCloudResourceIDWrap(res.Id)),
 		Size: size,
 	}
 
@@ -164,7 +165,7 @@ func (g Graph) GetExtendedSpaceProperties(ctx context.Context, baseURL *url.URL,
 
 	for _, itemName := range names {
 		if itemID, ok := metadata[itemName]; ok {
-			spaceItem := g.getSpecialDriveItem(ctx, string(itemID.Value), itemName, baseURL, space)
+			spaceItem := g.getSpecialDriveItem(ctx, resourceid.OwnCloudResourceIDUnwrap(string(itemID.Value)), itemName, baseURL, space)
 			if spaceItem != nil {
 				spaceItems = append(spaceItems, *spaceItem)
 			}
@@ -173,20 +174,20 @@ func (g Graph) GetExtendedSpaceProperties(ctx context.Context, baseURL *url.URL,
 	return spaceItems
 }
 
-func (g Graph) getSpecialDriveItem(ctx context.Context, itemID string, itemName string, baseURL *url.URL, space *storageprovider.StorageSpace) *libregraph.DriveItem {
+func (g Graph) getSpecialDriveItem(ctx context.Context, ID *storageprovider.ResourceId, itemName string, baseURL *url.URL, space *storageprovider.StorageSpace) *libregraph.DriveItem {
 	var spaceItem *libregraph.DriveItem
-	if itemID == "" {
+	if ID == nil {
 		return nil
 	}
 
-	spaceItem, err := g.getDriveItem(ctx, &storageprovider.ResourceId{StorageId: space.Root.StorageId, OpaqueId: itemID})
+	spaceItem, err := g.getDriveItem(ctx, ID)
 	if err != nil {
-		g.logger.Error().Err(err).Str("ID", itemID).Msg("Could not get readme Item")
+		g.logger.Error().Err(err).Str("ID", ID.OpaqueId).Msg("Could not get readme Item")
 		return nil
 	}
-	itemPath, err := g.getPathForDriveItem(ctx, &storageprovider.ResourceId{StorageId: space.Root.StorageId, OpaqueId: itemID})
+	itemPath, err := g.getPathForDriveItem(ctx, ID)
 	if err != nil {
-		g.logger.Error().Err(err).Str("ID", itemID).Msg("Could not get readme path")
+		g.logger.Error().Err(err).Str("ID", ID.OpaqueId).Msg("Could not get readme path")
 		return nil
 	}
 	spaceItem.SpecialFolder = &libregraph.SpecialFolder{Name: libregraph.PtrString(itemName)}
diff --git a/graph/pkg/service/v0/drives.go b/graph/pkg/service/v0/drives.go
index 58daa2c6973..24104af77e9 100644
--- a/graph/pkg/service/v0/drives.go
+++ b/graph/pkg/service/v0/drives.go
@@ -18,6 +18,7 @@ import (
 	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
 	ctxpkg "github.com/cs3org/reva/pkg/ctx"
 	"github.com/cs3org/reva/pkg/utils"
+	"github.com/cs3org/reva/pkg/utils/resourceid"
 	"github.com/go-chi/chi/v5"
 	"github.com/go-chi/render"
 	libregraph "github.com/owncloud/libre-graph-api-go"
@@ -329,7 +330,7 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) {
 	if resp.GetStatus().GetCode() != cs3rpc.Code_CODE_OK {
 		switch resp.Status.GetCode() {
 		case cs3rpc.Code_CODE_NOT_FOUND:
-			errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "Space not found")
+			errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, resp.GetStatus().GetMessage())
 			return
 		case cs3rpc.Code_CODE_PERMISSION_DENIED:
 			errorcode.NotAllowed.Render(w, r, http.StatusForbidden, resp.GetStatus().GetMessage())
@@ -409,11 +410,7 @@ func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*stor
 }
 
 func (g Graph) cs3StorageSpaceToDrive(baseURL *url.URL, space *storageprovider.StorageSpace) (*libregraph.Drive, error) {
-	rootID := space.Root.StorageId + "!" + space.Root.OpaqueId
-	if space.Root.StorageId == space.Root.OpaqueId {
-		// omit opaqueid
-		rootID = space.Root.StorageId
-	}
+	rootID := resourceid.OwnCloudResourceIDWrap(space.Root)
 
 	var permissions []libregraph.Permission
 	if space.Opaque != nil {
@@ -472,7 +469,7 @@ func (g Graph) cs3StorageSpaceToDrive(baseURL *url.URL, space *storageprovider.S
 	}
 
 	drive := &libregraph.Drive{
-		Id:   &rootID,
+		Id:   &space.Root.StorageId,
 		Name: &space.Name,
 		//"createdDateTime": "string (timestamp)", // TODO read from StorageSpace ... needs Opaque for now
 		//"description": "string", // TODO read from StorageSpace ... needs Opaque for now
@@ -501,7 +498,7 @@ func (g Graph) cs3StorageSpaceToDrive(baseURL *url.URL, space *storageprovider.S
 		// TODO read from StorageSpace ... needs Opaque for now
 		// TODO how do we build the url?
 		// for now: read from request
-		webDavURL := baseURL.String() + rootID
+		webDavURL := baseURL.String() + space.Root.StorageId
 		drive.Root.WebDavUrl = &webDavURL
 	}
 


Test patch:
diff --git a/graph/pkg/service/v0/graph_test.go b/graph/pkg/service/v0/graph_test.go
index 2c751b55b6a..976f4509aa6 100644
--- a/graph/pkg/service/v0/graph_test.go
+++ b/graph/pkg/service/v0/graph_test.go
@@ -90,11 +90,11 @@ var _ = Describe("Graph", func() {
 				"value":[
 					{
 						"driveType":"aspacetype",
-						"id":"aspaceid!anopaqueid",
+						"id":"aspaceid",
 						"name":"aspacename",
 						"root":{
 							"id":"aspaceid!anopaqueid",
-							"webDavUrl":"https://localhost:9200/dav/spaces/aspaceid!anopaqueid"
+							"webDavUrl":"https://localhost:9200/dav/spaces/aspaceid"
 						}
 					}
 				]