1
0
mirror of https://github.com/cs3org/reva.git synced 2025-04-18 13:44:12 +03:00

All required features and fixes for the OC/NC ScienceMesh apps (#4115)

This commit is contained in:
Giuseppe Lo Presti 2023-09-08 10:43:33 +02:00 committed by GitHub
parent c4fa2e5855
commit 5bbd158a0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
124 changed files with 3656 additions and 1209 deletions

View File

@ -1,2 +1,4 @@
scss:
enabled: false
jshint:
ignore_file: .hound_js_ignore

1
.hound_js_ignore Normal file
View File

@ -0,0 +1 @@
tests/**/*,js

View File

@ -0,0 +1,6 @@
Enhancement: All required features and fixes for the OC/NC ScienceMesh apps
This PR includes all necessary code in Reva
to interface with the ScienceMesh apps in OC and NC
https://github.com/cs3org/reva/pull/4115

View File

@ -9,7 +9,7 @@ description: >
# _struct: config_
{{% dir name="provider_domain" type="string" default="The same domain registered in the provider authorizer" %}}
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/ocminvitemanager/ocminvitemanager.go#L61)
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/grpc/services/ocminvitemanager/ocminvitemanager.go#L62)
{{< highlight toml >}}
[grpc.services.ocminvitemanager]
provider_domain = "The same domain registered in the provider authorizer"

View File

@ -9,7 +9,7 @@ description: >
# _struct: config_
{{% dir name="ocm_prefix" type="string" default="ocm" %}}
The prefix URL where the OCM API is served. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L37)
The prefix URL where the OCM API is served. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L39)
{{< highlight toml >}}
[http.services.ocmprovider]
ocm_prefix = "ocm"
@ -17,7 +17,7 @@ ocm_prefix = "ocm"
{{% /dir %}}
{{% dir name="endpoint" type="string" default="This host's URL. If it's not configured, it is assumed OCM is not available." %}}
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L38)
[[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L40)
{{< highlight toml >}}
[http.services.ocmprovider]
endpoint = "This host's URL. If it's not configured, it is assumed OCM is not available."
@ -25,7 +25,7 @@ endpoint = "This host's URL. If it's not configured, it is assumed OCM is not av
{{% /dir %}}
{{% dir name="provider" type="string" default="reva" %}}
A friendly name that defines this service. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L39)
A friendly name that defines this service. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L41)
{{< highlight toml >}}
[http.services.ocmprovider]
provider = "reva"
@ -33,7 +33,7 @@ provider = "reva"
{{% /dir %}}
{{% dir name="webdav_root" type="string" default="/remote.php/dav/ocm" %}}
The root URL of the WebDAV endpoint to serve OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L40)
The root URL of the WebDAV endpoint to serve OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L42)
{{< highlight toml >}}
[http.services.ocmprovider]
webdav_root = "/remote.php/dav/ocm"
@ -41,7 +41,7 @@ webdav_root = "/remote.php/dav/ocm"
{{% /dir %}}
{{% dir name="webapp_root" type="string" default="/external/sciencemesh" %}}
The root URL to serve Web apps via OCM. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L41)
The root URL to serve Web apps via OCM. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L43)
{{< highlight toml >}}
[http.services.ocmprovider]
webapp_root = "/external/sciencemesh"
@ -49,7 +49,7 @@ webapp_root = "/external/sciencemesh"
{{% /dir %}}
{{% dir name="enable_webapp" type="bool" default=false %}}
Whether web apps are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L42)
Whether web apps are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L44)
{{< highlight toml >}}
[http.services.ocmprovider]
enable_webapp = false
@ -57,7 +57,7 @@ enable_webapp = false
{{% /dir %}}
{{% dir name="enable_datatx" type="bool" default=false %}}
Whether data transfers are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L43)
Whether data transfers are enabled in OCM shares. [[Ref]](https://github.com/cs3org/reva/tree/master/internal/http/services/ocmprovider/ocmprovider.go#L45)
{{< highlight toml >}}
[http.services.ocmprovider]
enable_datatx = false

View File

@ -9,7 +9,7 @@ description: >
# _struct: AuthManagerConfig_
{{% dir name="endpoint" type="string" default="" %}}
The Nextcloud backend endpoint for user check [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/auth/manager/nextcloud/nextcloud.go#L54)
The Nextcloud backend endpoint for user check [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/auth/manager/nextcloud/nextcloud.go#L55)
{{< highlight toml >}}
[auth.manager.nextcloud]
endpoint = ""

View File

@ -9,10 +9,18 @@ description: >
# _struct: ShareManagerConfig_
{{% dir name="endpoint" type="string" default="" %}}
The Nextcloud backend endpoint for user check [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/ocm/share/repository/nextcloud/nextcloud.go#L60)
The Nextcloud backend endpoint for user check [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/ocm/share/repository/nextcloud/nextcloud.go#L63)
{{< highlight toml >}}
[ocm.share.repository.nextcloud]
endpoint = ""
{{< /highlight >}}
{{% /dir %}}
{{% dir name="mount_id" type="string" default="" %}}
The Reva mount id to identify the storage provider proxying the EFSS. Note that only one EFSS can be proxied by a given Reva process. [[Ref]](https://github.com/cs3org/reva/tree/master/pkg/ocm/share/repository/nextcloud/nextcloud.go#L67)
{{< highlight toml >}}
[ocm.share.repository.nextcloud]
mount_id = ""
{{< /highlight >}}
{{% /dir %}}

View File

@ -1,4 +0,0 @@
{
"zmd": "application/compressed-markdown",
"zep": "application/compressed-etherpad"
}

View File

@ -1,154 +0,0 @@
[shared]
gatewaysvc = "localhost:19000"
[grpc]
address = "0.0.0.0:19000"
[grpc.services.gateway]
authregistrysvc = "localhost:19000"
appprovidersvc = "localhost:19000"
appregistrysvc = "localhost:19000"
storageregistrysvc = "localhost:19000"
preferencessvc = "localhost:19000"
userprovidersvc = "localhost:19000"
usershareprovidersvc = "localhost:19000"
publicshareprovidersvc = "localhost:19000"
ocmcoresvc = "localhost:19000"
ocmshareprovidersvc = "localhost:19000"
ocminvitemanagersvc = "localhost:19000"
ocmproviderauthorizersvc = "localhost:19000"
commit_share_to_storage_grant = false
datagateway = "http://localhost:19001/data"
transfer_expires = 6 # give it a moment
[grpc.services.appregistry]
driver = "static"
[grpc.services.appregistry.drivers.static]
mime_types = [
{"mime_type" = "text/plain", "extension" = "txt", "name" = "Text file", "description" = "Text file", "allow_creation" = true},
{"mime_type" = "text/markdown", "extension" = "md", "name" = "Markdown file", "description" = "Markdown file", "allow_creation" = true},
{"mime_type" = "application/vnd.oasis.opendocument.text", "extension" = "odt", "name" = "OpenDocument", "description" = "OpenDocument text document", "default_app" = "Collabora", "allow_creation" = true},
{"mime_type" = "application/vnd.oasis.opendocument.spreadsheet", "extension" = "ods", "name" = "OpenSpreadsheet", "description" = "OpenDocument spreadsheet document", "default_app" = "Collabora", "allow_creation" = true},
{"mime_type" = "application/vnd.oasis.opendocument.presentation", "extension" = "odp", "name" = "OpenPresentation", "description" = "OpenDocument presentation document", "default_app" = "Collabora", "allow_creation" = true},
{"mime_type" = "application/vnd.jupyter", "extension" = "ipynb", "name" = "Jupyter Notebook", "description" = "Jupyter Notebook"}
]
[grpc.services.appprovider]
driver = "wopi"
app_provider_url = "localhost:19000"
[grpc.services.appprovider.drivers.wopi]
iop_secret = "shared-secret-with-wopiserver"
wopi_url = "http://0.0.0.0:8880/"
app_name = "Collabora"
app_url = "https://your-collabora-server.org:9980"
[grpc.services.authregistry]
driver = "static"
[grpc.services.authregistry.drivers.static.rules]
basic = "localhost:19000"
[grpc.services.storageregistry]
driver = "static"
[grpc.services.storageregistry.drivers.static]
home_provider = "/home"
[grpc.services.storageregistry.drivers.static.rules]
"/home" = {"address" = "localhost:19000"}
"123e4567-e89b-12d3-a456-426655440000" = {"address" = "localhost:19000"}
[grpc.services.usershareprovider]
driver = "memory"
[grpc.services.ocmcore]
driver = "json"
# Note that ocmcore and ocmshareprovider should use the same file for storing the shares.
[grpc.services.ocmcore.drivers.json]
file = "/var/tmp/reva/shares_server_1.json"
[grpc.services.ocminvitemanager]
driver = "json"
[grpc.services.ocmshareprovider]
driver = "json"
[grpc.services.ocmshareprovider.drivers.json]
file = "/var/tmp/reva/shares_server_1.json"
[grpc.services.ocmproviderauthorizer]
driver = "json"
[grpc.services.ocmproviderauthorizer.drivers.json]
providers = "/etc/revad/providers.json"
[grpc.services.publicshareprovider]
driver = "memory"
[grpc.services.storageprovider]
driver = "nextcloud"
mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
data_server_url = "http://127.0.0.1:19001/data"
enable_home_creation = true
disable_tus = true
custom_mime_types_json = "custom-mime-types-demo.json"
[grpc.services.storageprovider.drivers.nextcloud]
endpoint = "http://localhost/apps/sciencemesh/"
user_layout = "{{.Username}}"
[grpc.services.authprovider]
auth_manager = "nextcloud"
[grpc.services.authprovider.drivers.nextcloud]
endpoint = "http://localhost/apps/sciencemesh/"
[grpc.services.userprovider]
driver = "nextcloud"
[grpc.services.userprovider.drivers.nextcloud]
endpoint = "http://localhost/apps/sciencemesh/"
[http]
address = "0.0.0.0:19001"
[http.services.appprovider]
[http.services.dataprovider]
driver = "nextcloud"
[http.services.prometheus]
[http.services.sysinfo]
[http.services.dataprovider.drivers.localhome]
user_layout = "{{.Username}}"
[http.services.ocmd]
[http.services.ocmprovider]
provider = "Reva-Nextcloud"
endpoint = "http://localhost"
webdav_root = "/remote.php/dav/ocm"
enable_webapp = true
enable_datatx = true
[http.services.sciencemesh]
mesh_directory_url = 'https://sciencemesh.cesnet.cz/iop/meshdir'
provider_domain = 'your-domain.org'
ocm_mount_point = '/sciencemesh'
[http.middlewares.providerauthorizer]
driver = "json"
[http.middlewares.providerauthorizer.drivers.json]
providers = "/etc/revad/providers.json"
[http.services.ocs]
prefix = "ocs"
[http.services.ocdav]
[http.middlewares.cors]

View File

@ -27,7 +27,7 @@ mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
data_server_url = "http://localhost:12001/data"
enable_home_creation = true
enable_home_creation = false
[grpc.services.storageprovider.drivers.owncloud]
datadirectory = "/var/tmp/reva/data"

View File

@ -90,7 +90,7 @@ mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
data_server_url = "http://localhost:{{ http.services.dataprovider[0].address.port }}/data"
enable_home_creation = true
enable_home_creation = false
[grpc.services.storageprovider.drivers.localhome]
user_layout = "{{.Username}}"

View File

@ -90,7 +90,7 @@ mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
data_server_url = "http://localhost:{{ http.services.dataprovider[0].address.port }}/data"
enable_home_creation = true
enable_home_creation = false
[grpc.services.storageprovider.drivers.localhome]
user_layout = "{{.Username}}"

View File

@ -35,7 +35,7 @@ mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
data_server_url = "http://localhost:19001/data"
enable_home_creation = true
enable_home_creation = false
[grpc.services.usershareprovider]
[grpc.services.groupprovider]

View File

@ -35,7 +35,7 @@ mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
data_server_url = "http://localhost:17001/data"
enable_home_creation = true
enable_home_creation = false
[grpc.services.usershareprovider]
[grpc.services.groupprovider]

View File

@ -0,0 +1,3 @@
{
".zmd": "application/compressed-markdown"
}

View File

@ -0,0 +1,74 @@
[
{
"name": "reva1.pondersource.net",
"full_name": "reva1.pondersource.net",
"organization": "reva1.pondersource.net",
"domain": "reva1.pondersource.net",
"homepage": "https://reva1.pondersource.net",
"description": "reva1.pondersource.net",
"services": [
{
"endpoint": {
"type": {
"name": "OCM",
"description": "Open Cloud Mesh"
},
"name": "OCM API",
"path": "https://reva1.pondersource.net",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "https://reva1.pondersource.net"
},
{
"endpoint": {
"type": {
"name": "Webdav",
"description": "Webdav"
},
"name": "Webdav API",
"path": "https://reva1.pondersource.net/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "https://reva1.pondersource.net"
}
]
},
{
"name": "reva2.pondersource.net",
"full_name": "reva2.pondersource.net",
"organization": "reva2.pondersource.net",
"domain": "reva2.pondersource.net",
"homepage": "https://reva2.pondersource.net",
"description": "reva2.pondersource.net",
"services": [
{
"endpoint": {
"type": {
"name": "OCM",
"description": "Open Cloud Mesh"
},
"name": "OCM API",
"path": "https://reva2.pondersource.net",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "https://reva2.pondersource.net"
},
{
"endpoint": {
"type": {
"name": "Webdav",
"description": "Webdav"
},
"name": "Webdav API",
"path": "https://reva2.pondersource.net/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "https://reva2.pondersource.net"
}
]
}
]

View File

@ -0,0 +1,198 @@
[
{
"name": "cernbox",
"full_name": "CERNBox",
"organization": "CERN",
"domain": "cernbox.cern.ch",
"homepage": "https://cernbox.web.cern.ch",
"description": "CERNBox provides cloud data storage to all CERN users.",
"services": [
{
"endpoint": {
"type": {
"name": "OCM",
"description": "CERNBox Open Cloud Mesh API"
},
"name": "CERNBox - OCM API",
"path": "http://127.0.0.1:19001/ocm/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:19001/"
},
{
"endpoint": {
"type": {
"name": "Webdav",
"description": "CERNBox Webdav API"
},
"name": "CERNBox - Webdav API",
"path": "http://127.0.0.1:19001/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:19001/"
},
{
"endpoint": {
"type": {
"name": "Gateway",
"description": "CERNBox GRPC Gateway"
},
"name": "CERNBox - GRPC Gateway",
"path": "127.0.0.1:19000",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "127.0.0.1:19000"
}
]
},
{
"name": "oc-cesnet",
"full_name": "ownCloud@CESNET",
"organization": "CESNET",
"domain": "cesnet.cz",
"homepage": "https://owncloud.cesnet.cz",
"description": "OwnCloud has been designed for individual users.",
"services": [
{
"endpoint": {
"type": {
"name": "OCM",
"description": "CESNET Open Cloud Mesh API"
},
"name": "CESNET - OCM API",
"path": "http://127.0.0.1:17001/ocm/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:17001/"
},
{
"endpoint": {
"type": {
"name": "Webdav",
"description": "CESNET Webdav API"
},
"name": "CESNET - Webdav API",
"path": "http://127.0.0.1:17001/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:17001/"
},
{
"endpoint": {
"type": {
"name": "Gateway",
"description": "CESNET GRPC Gateway"
},
"name": "CESNET - GRPC Gateway",
"path": "127.0.0.1:17000",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "127.0.0.1:17000"
}
]
},
{
"name": "example",
"full_name": "ownCloud@Example",
"organization": "Example",
"domain": "example.org",
"homepage": "http://example.org",
"description": "Example cloud storage.",
"services": [
{
"endpoint": {
"type": {
"name": "OCM",
"description": "Example Open Cloud Mesh API"
},
"name": "Example - OCM API",
"path": "http://127.0.0.1:19001/ocm/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:19001/"
},
{
"endpoint": {
"type": {
"name": "Webdav",
"description": "Example Webdav API"
},
"name": "Example - Webdav API",
"path": "http://127.0.0.1:19001/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:19001/"
},
{
"endpoint": {
"type": {
"name": "Gateway",
"description": "Example GRPC Gateway"
},
"name": "Example - GRPC Gateway",
"path": "127.0.0.1:19000",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "127.0.0.1:19000"
}
]
},
{
"name": "test",
"full_name": "ownCloud@Test",
"organization": "Test",
"domain": "test.org",
"homepage": "http://test.org",
"description": "Test cloud storage.",
"services": [
{
"endpoint": {
"type": {
"name": "OCM",
"description": "Test Open Cloud Mesh API"
},
"name": "Test - OCM API",
"path": "http://127.0.0.1:19001/ocm/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:19001/"
},
{
"endpoint": {
"type": {
"name": "Webdav",
"description": "Test Webdav API"
},
"name": "Test - Webdav API",
"path": "http://127.0.0.1:19001/remote.php/webdav/",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "http://127.0.0.1:19001/"
},
{
"endpoint": {
"type": {
"name": "Gateway",
"description": "Test GRPC Gateway"
},
"name": "Test - GRPC Gateway",
"path": "127.0.0.1:19000",
"is_monitored": true
},
"api_version": "0.0.1",
"host": "127.0.0.1:19000"
}
]
}
]

View File

@ -0,0 +1,26 @@
[
{ "domain": "revad1.docker", "services": [
{ "endpoint": { "type": { "name": "OCM" }, "path": "https://revad1.docker/ocm/" }, "host": "revad1.docker" },
{ "endpoint": { "type": { "name": "Webdav" }, "path": "https://revad1.docker/remote.php/webdav/" }, "host": "revad1.docker" }
] },
{ "domain": "revad2.docker", "services": [
{ "endpoint": { "type": { "name": "OCM" }, "path": "https://revad2.docker/ocm/" }, "host": "revad2.docker" },
{ "endpoint": { "type": { "name": "Webdav" }, "path": "https://revad2.docker/remote.php/webdav/" }, "host": "revad2.docker" }
] },
{ "domain": "revanextcloud1.docker", "services": [
{ "endpoint": { "type": { "name": "OCM" }, "path": "https://revanextcloud1.docker/ocm/" }, "host": "revanextcloud1.docker" },
{ "endpoint": { "type": { "name": "Webdav" }, "path": "https://nc1.docker/remote.php/webdav/" }, "host": "nc1.docker" }
] },
{ "domain": "revanextcloud2.docker", "services": [
{ "endpoint": { "type": { "name": "OCM" }, "path": "https://revanextcloud2.docker/ocm/" }, "host": "revanextcloud2.docker" },
{ "endpoint": { "type": { "name": "Webdav" }, "path": "https://nc2.docker/remote.php/webdav/" }, "host": "nc2.docker" }
] },
{ "domain": "revaowncloud1.docker", "services": [
{ "endpoint": { "type": { "name": "OCM" }, "path": "https://revaowncloud1.docker/ocm/" }, "host": "revaowncloud1.docker" },
{ "endpoint": { "type": { "name": "Webdav" }, "path": "https://oc1.docker/remote.php/webdav/" }, "host": "oc1.docker" }
] },
{ "domain": "revaowncloud2.docker", "services": [
{ "endpoint": { "type": { "name": "OCM" }, "path": "https://revaowncloud2.docker/ocm/" }, "host": "revaowncloud2.docker" },
{ "endpoint": { "type": { "name": "Webdav" }, "path": "https://oc2.docker/remote.php/webdav/" }, "host": "oc2.docker" }
] }
]

View File

@ -0,0 +1,22 @@
[log]
level = "debug"
[shared]
gatewaysvc = "your.revad.com:19000"
[grpc]
address = "0.0.0.0:19100"
[grpc.services.appprovider]
driver = "wopi"
custom_mime_types_json = "custom-mime-types-demo.json"
mime_types = ["application/vnd.oasis.opendocument.text", "application/vnd.oasis.opendocument.spreadsheet", "application/vnd.oasis.opendocument.presentation", "text/rtf"]
app_provider_url = "your.revad.com:19100"
language = "en-GB"
[grpc.services.appprovider.drivers.wopi]
iop_secret = "hello"
wopi_url = "http://wopi.docker:8880/"
app_name = "Collabora"
app_url = "http://collabora.docker:9980"
app_int_url = "http://collabora.docker:9980"

View File

@ -0,0 +1,252 @@
[vars]
machine_api_key = "machine-api-key"
provider_domain = "your.revad.com"
shared_secret = "shared-secret-1"
[log]
level = "trace"
[shared]
gatewaysvc = "your.revad.com:19000"
[grpc.services.gateway]
address = "your.revad.com:19000"
authregistrysvc = "{{ grpc.services.authregistry.address }}"
appregistrysvc = "{{ grpc.services.appregistry.address }}"
storageregistrysvc = "{{ grpc.services.storageregistry.address }}"
preferencessvc = "{{ grpc.services.userprovider.address }}"
userprovidersvc = "{{ grpc.services.userprovider.address }}"
usershareprovidersvc = "{{ grpc.services.usershareprovider.address }}"
ocmcoresvc = "{{ grpc.services.ocmcore.address }}"
ocmshareprovidersvc = "{{ grpc.services.ocmshareprovider.address }}"
ocminvitemanagersvc = "{{ grpc.services.ocminvitemanager.address }}"
ocmproviderauthorizersvc = "{{ grpc.services.ocmproviderauthorizer.address }}"
datagateway = "https://{{ http.services.datagateway.address }}/data"
transfer_expires = 6 # give it a moment
commit_share_to_storage_grant = true
commit_share_to_storage_ref = true
[grpc.services.appregistry]
driver = "static"
[grpc.services.appregistry.drivers.static]
mime_types = [
{"mime_type" = "text/plain", "extension" = "txt", "name" = "Text file", "description" = "Text file", "allow_creation" = true},
{"mime_type" = "text/markdown", "extension" = "md", "name" = "Markdown file", "description" = "Markdown file", "allow_creation" = true},
{"mime_type" = "application/vnd.oasis.opendocument.text", "extension" = "odt", "name" = "OpenDocument", "description" = "OpenDocument text document", "default_app" = "Collabora", "allow_creation" = true},
{"mime_type" = "application/vnd.oasis.opendocument.spreadsheet", "extension" = "ods", "name" = "OpenSpreadsheet", "description" = "OpenDocument spreadsheet document", "default_app" = "Collabora", "allow_creation" = true},
{"mime_type" = "application/vnd.oasis.opendocument.presentation", "extension" = "odp", "name" = "OpenPresentation", "description" = "OpenDocument presentation document", "default_app" = "Collabora", "allow_creation" = true},
{"mime_type" = "application/vnd.jupyter", "extension" = "ipynb", "name" = "Jupyter Notebook", "description" = "Jupyter Notebook"}
]
### AUTH PROVIDERS ###
[grpc.services.authregistry]
driver = "static"
[grpc.services.authregistry.drivers.static.rules]
basic = "{{ grpc.services.authprovider[0].address }}"
machine = "{{ grpc.services.authprovider[1].address }}"
ocmshares = "{{ grpc.services.authprovider[2].address }}"
[[grpc.services.authprovider]]
auth_manager = "nextcloud"
[grpc.services.authprovider.auth_managers.nextcloud]
endpoint = "https://your.efss.com/index.php/apps/sciencemesh/"
shared_secret = "{{ vars.shared_secret }}"
mock_http = false
[[grpc.services.authprovider]]
auth_manager = "machine"
[grpc.services.authprovider.auth_managers.machine]
api_key = "{{ vars.machine_api_key }}"
gateway_addr = "your.revad.com:19000"
[[grpc.services.authprovider]]
auth_manager = "ocmshares"
### STORAGE PROVIDERS ###
[grpc.services.storageregistry]
driver = "static"
[grpc.services.storageregistry.drivers.static]
home_provider = "/home"
[grpc.services.storageregistry.drivers.static.rules]
"/home" = {"address" = "{{ grpc.services.storageprovider[0].address }}"}
"nextcloud" = {"address" = "{{ grpc.services.storageprovider[0].address }}"}
"/ocm" = {"address" = "{{ grpc.services.storageprovider[1].address }}"}
"ocm" = {"address" = "{{ grpc.services.storageprovider[1].address }}"}
[[grpc.services.storageprovider]]
driver = "nextcloud"
mount_id = "nextcloud"
expose_data_server = true
enable_home_creation = false
data_server_url = "https://your.revad.com:{{ http.services.dataprovider[0].address.port }}/data"
[grpc.services.storageprovider.drivers.nextcloud]
endpoint = "https://your.efss.com/index.php/apps/sciencemesh/"
shared_secret = "{{ vars.shared_secret }}"
mock_http = false
[[grpc.services.storageprovider]]
driver = "ocmoutcoming"
mount_id = "ocm"
mount_path = "/ocm"
expose_data_server = true
enable_home_creation = false
data_server_url = "https://your.revad.com:{{ http.services.dataprovider[1].address.port }}/data"
[grpc.services.storageprovider.drivers.ocmoutcoming]
machine_secret = "{{ vars.machine_api_key }}"
### OTHER PROVIDERS ###
[grpc.services.usershareprovider]
driver = "memory"
[grpc.services.ocmcore]
driver = "nextcloud"
[grpc.services.ocmcore.drivers.nextcloud]
host = "https://your.revad.com/"
endpoint = "https://your.efss.com/index.php/apps/sciencemesh/"
shared_secret = "{{ vars.shared_secret }}"
mock_http = false
[grpc.services.ocminvitemanager]
# TODO the driver should become "nextcloud"
driver = "json"
provider_domain = "your.revad.com"
[grpc.services.ocmshareprovider]
driver = "nextcloud"
provider_domain = "your.revad.com"
endpoint = "https://your.revad.com/"
webdav_endpoint = "https://your.revad.com/"
webdav_prefix = "https://your.revad.com/remote.php/dav/files"
webapp_template = "https://your.revad.com/external/sciencemesh/{{.Token}}/{relative-path-to-shared-resource}"
[grpc.services.ocmshareprovider.drivers.nextcloud]
webdav_host = "https://your.revad.com/"
endpoint = "https://your.efss.com/index.php/apps/sciencemesh/"
shared_secret = "{{ vars.shared_secret }}"
mock_http = false
mount_id = "nextcloud"
[grpc.services.ocmproviderauthorizer]
driver = "json"
[grpc.services.ocmproviderauthorizer.drivers.json]
providers = "providers.testnet.json"
verify_request_hostname = true
[grpc.services.userprovider]
driver = "nextcloud"
[grpc.services.userprovider.drivers.nextcloud]
endpoint = "https://your.efss.com/index.php/apps/sciencemesh/"
shared_secret = "shared-secret-1"
mock_http = false
[grpc.services.datatx]
txdriver = "rclone"
storagedriver = "json"
remove_transfer_on_cancel = true
[grpc.services.datatx.txdrivers.rclone]
# rclone endpoint
endpoint = "http://rclone.docker"
# basic auth is used
auth_user = "rcloneuser"
auth_pass = "eilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek"
auth_header = "x-access-token"
job_status_check_interval = 2000
job_timeout = 120000
storagedriver = "json"
remove_transfer_job_on_cancel = true
[grpc.services.datatx.storagedrivers.json]
file = ""
[grpc.services.datatx.txdrivers.rclone.storagedrivers.json]
file = ""
### HTTP ENDPOINTS ###
[http]
certfile = "/etc/revad/tls/your.revad.ssl.crt"
keyfile = "/etc/revad/tls/your.revad.ssl.key"
[http.services.appprovider]
address = "0.0.0.0:443"
insecure = true
[http.services.datagateway]
address = "0.0.0.0:443"
[[http.services.dataprovider]]
driver = "nextcloud"
[http.services.dataprovider.drivers.nextcloud]
endpoint = "https://your.efss.com/index.php/apps/sciencemesh/"
shared_secret = "shared-secret-1"
mock_http = false
[[http.services.dataprovider]]
driver = "ocmoutcoming"
[http.services.dataprovider.drivers.ocmoutcoming]
machine_secret = "{{ vars.machine_api_key }}"
[http.services.sciencemesh]
address = "0.0.0.0:443"
provider_domain = "your.revad.com"
mesh_directory_url = "https://meshdir.docker/meshdir"
# for a production deployment, use:
# mesh_directory_url = 'https://sciencemesh.cesnet.cz/iop/meshdir'
ocm_mount_point = "/sciencemesh"
[http.services.sciencemesh.smtp_credentials]
disable_auth = true
sender_mail = "sciencemesh@your.revad.com"
smtp_server = "smtp.your.revad.com"
smtp_port = 25
[http.services.ocmprovider]
address = "0.0.0.0:443"
ocm_prefix = "ocm"
provider = "Reva for ownCloud/Nextcloud"
endpoint = "https://your.revad.com"
enable_webapp = true
enable_datatx = true
[http.services.ocmd]
address = "0.0.0.0:443"
prefix = "ocm"
[http.services.ocmd.config]
host = "your.revad.com"
[http.services.ocs]
address = "0.0.0.0:443"
prefix = "ocs"
[http.services.ocdav]
address = "0.0.0.0:443"
[http.services.prometheus]
[http.services.sysinfo]
[http.middlewares.cors]
[http.middlewares.log]

View File

@ -0,0 +1,106 @@
[
{
"id": {
"opaque_id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
"idp": "cernbox.cern.ch",
"type": 1
},
"username": "einstein",
"secret": "relativity",
"mail": "einstein@cern.ch",
"display_name": "Albert Einstein",
"groups": ["sailing-lovers", "violin-haters", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 987",
"decoder":"plain",
"value":"OTg3"
},
"uid":{
"_comment": "decodes to 123",
"decoder":"plain",
"value":"MTIz"
}
}
}
},
{
"id": {
"opaque_id": "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
"idp": "cesnet.cz",
"type": 1
},
"username": "marie",
"secret": "radioactivity",
"mail": "marie@cesnet.cz",
"display_name": "Marie Curie",
"groups": ["radium-lovers", "polonium-lovers", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 987",
"decoder":"plain",
"value":"OTg3"
},
"uid":{
"_comment": "decodes to 456",
"decoder":"plain",
"value":"NDU2"
}
}
}
},
{
"id": {
"opaque_id": "932b4540-8d16-481e-8ef4-588e4b6b151c",
"idp": "example.org",
"type": 1
},
"username": "richard",
"secret": "superfluidity",
"mail": "richard@example.org",
"display_name": "Richard Feynman",
"groups": ["quantum-lovers", "philosophy-haters", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 135",
"decoder":"plain",
"value":"MTM1"
},
"uid":{
"_comment": "decodes to 246",
"decoder":"plain",
"value":"MjQ2"
}
}
}
},
{
"id": {
"opaque_id": "932b4522-139b-4815-8ef4-42cdf82c3d51",
"idp": "example.com",
"type": 1
},
"username": "test",
"secret": "test",
"mail": "test@example.com",
"display_name": "Test Testman",
"groups": ["quantum-lovers", "philosophy-haters", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 135",
"decoder":"plain",
"value":"MTM1"
},
"uid":{
"_comment": "decodes to 468",
"decoder":"plain",
"value":"NDY4"
}
}
}
}
]

View File

@ -0,0 +1,106 @@
[
{
"id": {
"opaque_id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
"idp": "revad1.docker",
"type": 1
},
"username": "einstein",
"secret": "relativity",
"mail": "einstein@revad1-email.com",
"display_name": "Albert Einstein",
"groups": ["sailing-lovers", "violin-haters", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 987",
"decoder":"plain",
"value":"OTg3"
},
"uid":{
"_comment": "decodes to 123",
"decoder":"plain",
"value":"MTIz"
}
}
}
},
{
"id": {
"opaque_id": "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
"idp": "revad2.docker",
"type": 1
},
"username": "marie",
"secret": "radioactivity",
"mail": "marie@revad2-email.com",
"display_name": "Marie Curie",
"groups": ["radium-lovers", "polonium-lovers", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 987",
"decoder":"plain",
"value":"OTg3"
},
"uid":{
"_comment": "decodes to 456",
"decoder":"plain",
"value":"NDU2"
}
}
}
},
{
"id": {
"opaque_id": "932b4540-8d16-481e-8ef4-588e4b6b151c",
"idp": "example.org",
"type": 1
},
"username": "richard",
"secret": "superfluidity",
"mail": "richard@example.org",
"display_name": "Richard Feynman",
"groups": ["quantum-lovers", "philosophy-haters", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 135",
"decoder":"plain",
"value":"MTM1"
},
"uid":{
"_comment": "decodes to 246",
"decoder":"plain",
"value":"MjQ2"
}
}
}
},
{
"id": {
"opaque_id": "932b4522-139b-4815-8ef4-42cdf82c3d51",
"idp": "example.com",
"type": 1
},
"username": "test",
"secret": "test",
"mail": "test@example.com",
"display_name": "Test Testman",
"groups": ["quantum-lovers", "philosophy-haters", "physics-lovers"],
"opaque": {
"map": {
"gid": {
"_comment": "decodes to 135",
"decoder":"plain",
"value":"MTM1"
},
"uid":{
"_comment": "decodes to 468",
"decoder":"plain",
"value":"NDY4"
}
}
}
}
]

View File

@ -36,16 +36,6 @@ mime_types = [
{"mime_type" = "application/vnd.jupyter", "extension" = "ipynb", "name" = "Jupyter Notebook", "description" = "Jupyter Notebook"}
]
[grpc.services.appprovider]
driver = "wopi"
app_provider_url = "localhost:19000"
[grpc.services.appprovider.drivers.wopi]
iop_secret = "shared-secret-with-wopiserver"
wopi_url = "http://0.0.0.0:8880/"
app_name = "Collabora"
app_url = "https://your-collabora-server.org:9980"
[grpc.services.storageregistry]
[grpc.services.storageregistry.drivers.static]
home_provider = "/home"
@ -91,7 +81,6 @@ providers = "providers.demo.json"
[http]
address = "0.0.0.0:19001"
[http.services.appprovider]
[http.services.datagateway]
[http.services.prometheus]
[http.services.ocmd]

View File

@ -36,16 +36,6 @@ mime_types = [
{"mime_type" = "application/vnd.jupyter", "extension" = "ipynb", "name" = "Jupyter Notebook", "description" = "Jupyter Notebook"}
]
[grpc.services.appprovider]
driver = "wopi"
appregistrysvc = "localhost:29000"
[grpc.services.appprovider.drivers.wopi]
iop_secret = "shared-secret-with-wopiserver"
wopi_url = "http://0.0.0.0:8880/"
app_name = "Collabora"
app_url = "https://your-collabora-server.org:9980"
[grpc.services.storageregistry]
[grpc.services.storageregistry.drivers.static]
home_provider = "/home"
@ -91,7 +81,6 @@ providers = "providers.demo.json"
[http]
address = "0.0.0.0:29001"
[http.services.appprovider]
[http.services.datagateway]
[http.services.prometheus]
[http.services.ocmd]

View File

@ -58,7 +58,7 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
if err != nil {
return err
}
log.Trace().Msg("Extracting scope from token")
if ref, ok := extractRef(req, tokenScope); ok {
// The request is for a storage reference. This can be the case for multiple scenarios:
// - If the path is not empty, the request might be coming from a share where the accessor is
@ -87,6 +87,8 @@ func expandAndVerifyScope(ctx context.Context, req interface{}, tokenScope map[s
log.Err(err).Msgf("error resolving reference %s under scope %+v", ref.String(), k)
}
}
} else {
log.Trace().Msg("Token scope is not ok")
}
if checkLightweightScope(ctx, req, tokenScope, client) {

View File

@ -23,6 +23,7 @@ import (
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
datatx "github.com/cs3org/go-cs3apis/cs3/tx/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
txdriver "github.com/cs3org/reva/pkg/datatx"
txregistry "github.com/cs3org/reva/pkg/datatx/manager/registry"
@ -121,6 +122,7 @@ func (s *service) UnprotectedEndpoints() []string {
func (s *service) CreateTransfer(ctx context.Context, req *datatx.CreateTransferRequest) (*datatx.CreateTransferResponse, error) {
txInfo, startTransferErr := s.txManager.CreateTransfer(ctx, req.SrcTargetUri, req.DestTargetUri)
log := appctx.GetLogger(ctx)
// we always save the transfer regardless of start transfer outcome
// only then, if starting fails, can we try to restart it
@ -132,6 +134,8 @@ func (s *service) CreateTransfer(ctx context.Context, req *datatx.CreateTransfer
ShareID: req.GetShareId().OpaqueId,
UserID: userID,
}
log.Debug().Interface("transfer", transfer).Msg("CreateTransfer")
if err := s.storageDriver.StoreTransfer(transfer); err != nil {
err = errors.Wrap(err, "datatx service: error NEW saving transfer share: "+datatx.Status_STATUS_INVALID.String())
return &datatx.CreateTransferResponse{
@ -155,6 +159,7 @@ func (s *service) CreateTransfer(ctx context.Context, req *datatx.CreateTransfer
}
func (s *service) GetTransferStatus(ctx context.Context, req *datatx.GetTransferStatusRequest) (*datatx.GetTransferStatusResponse, error) {
log := appctx.GetLogger(ctx)
transfer, err := s.storageDriver.GetTransfer(req.TxId.OpaqueId)
if err != nil {
return nil, errtypes.InternalError("datatx service: transfer not found")
@ -171,6 +176,7 @@ func (s *service) GetTransferStatus(ctx context.Context, req *datatx.GetTransfer
txInfo.ShareId = &ocm.ShareId{OpaqueId: transfer.ShareID}
log.Debug().Interface("txInfo", txInfo).Msg("GetTransferStatus")
return &datatx.GetTransferStatusResponse{
Status: status.NewOK(ctx),
TxInfo: txInfo,

View File

@ -26,6 +26,7 @@ import (
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/ocm/client"
@ -203,7 +204,7 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite
// know each other
remoteUserID := &userpb.UserId{
Type: userpb.UserType_USER_TYPE_PRIMARY,
Type: userpb.UserType_USER_TYPE_FEDERATED,
Idp: req.GetOriginSystemProvider().Domain,
OpaqueId: remoteUser.UserID,
}
@ -306,7 +307,9 @@ func isTokenValid(token *invitepb.InviteToken) bool {
}
func (s *service) GetAcceptedUser(ctx context.Context, req *invitepb.GetAcceptedUserRequest) (*invitepb.GetAcceptedUserResponse, error) {
logger := appctx.GetLogger(ctx)
user, ok := getUserFilter(ctx, req)
logger.Info().Msgf("GetAcceptedUser %s at %s", user.Id.OpaqueId, user.Id.Idp)
if !ok {
return &invitepb.GetAcceptedUserResponse{
Status: status.NewInvalidArg(ctx, "user not found"),

View File

@ -823,6 +823,8 @@ func (s *service) Stat(ctx context.Context, req *provider.StatRequest) (*provide
Status: status.NewOK(ctx),
Info: md,
}
log := appctx.GetLogger(ctx)
log.Trace().Interface("md", md).Msg("GetMD returns")
return res, nil
}

View File

@ -29,6 +29,8 @@ import (
"github.com/cs3org/reva/pkg/utils/cfg"
)
const OCMAPIVersion = "1.1.0"
func init() {
global.Register("ocmprovider", New)
}
@ -89,7 +91,7 @@ func (c *config) prepare() *discoveryData {
if c.Endpoint == "" {
d.Enabled = false
d.Endpoint = ""
d.APIVersion = "1.1.0"
d.APIVersion = OCMAPIVersion
d.Provider = c.Provider
d.ResourceTypes = []resourceTypes{{
Name: "file",
@ -100,7 +102,7 @@ func (c *config) prepare() *discoveryData {
return d
}
d.Enabled = true
d.APIVersion = "1.1.0"
d.APIVersion = OCMAPIVersion
d.Endpoint = fmt.Sprintf("%s/%s", c.Endpoint, c.OCMPrefix)
d.Provider = c.Provider
rtProtos := map[string]string{}
@ -153,10 +155,11 @@ func (s *svc) Handler() http.Handler {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if r.UserAgent() == "Nextcloud Server Crawler" {
// TODO(lopresti) remove this hack once Nextcloud is able to talk OCM!
s.data.APIVersion = "1.0-proposal1"
// Nextcloud decided to only support OCM 1.0 and 1.1, not any 1.x as per SemVer. See
// https://github.com/nextcloud/server/pull/39574#issuecomment-1679191188
s.data.APIVersion = "1.1"
} else {
s.data.APIVersion = "1.1.0"
s.data.APIVersion = OCMAPIVersion
}
indented, _ := json.MarshalIndent(s.data, "", " ")
if _, err := w.Write(indented); err != nil {

View File

@ -21,6 +21,7 @@ package ocdav
import (
"context"
"fmt"
"io"
"net/http"
"path"
@ -85,8 +86,10 @@ func (s *svc) handleSpacesMkCol(w http.ResponseWriter, r *http.Request, spaceID
func (s *svc) handleMkcol(ctx context.Context, w http.ResponseWriter, r *http.Request, parentRef, childRef *provider.Reference, log zerolog.Logger) {
if r.Body != http.NoBody {
w.WriteHeader(http.StatusUnsupportedMediaType)
return
if d, _ := io.ReadAll(r.Body); len(d) != 0 { // an empty body is also fine
w.WriteHeader(http.StatusUnsupportedMediaType)
return
}
}
client, err := s.getClient()

View File

@ -25,6 +25,7 @@ import (
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/auth"
"github.com/cs3org/reva/pkg/auth/manager/registry"
"github.com/cs3org/reva/pkg/auth/scope"
@ -73,6 +74,8 @@ func New(ctx context.Context, conf map[string]interface{}) (auth.Manager, error)
// Authenticate impersonate an user if the provided secret is equal to the api-key.
func (m *manager) Authenticate(ctx context.Context, user, secret string) (*userpb.User, map[string]*authpb.Scope, error) {
log := appctx.GetLogger(ctx)
log.Trace().Msgf("Machine Authenticate user '%s' secret '%s'", user, secret)
if m.APIKey != secret {
return nil, nil, errtypes.InvalidCredentials("")
}

View File

@ -33,6 +33,7 @@ import (
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/auth"
"github.com/cs3org/reva/pkg/auth/manager/registry"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/utils/cfg"
"github.com/pkg/errors"
)
@ -141,18 +142,17 @@ func (am *Manager) Authenticate(ctx context.Context, clientID, clientSecret stri
type paramsObj struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
// Scope authpb.Scope
}
if clientSecret == "" {
// This may happen when the remote OCM user attempts to do basic auth with (username = sharedSecret and pwd = empty),
// and the interceptors bring us here. But authentication is properly handled by the ocm share provider.
return nil, nil, errtypes.PermissionDenied("secret is empty, ignoring")
}
bodyObj := &paramsObj{
ClientID: clientID,
ClientSecret: clientSecret,
// Scope: authpb.Scope{
// Resource: &types.OpaqueEntry{
// Decoder: "json",
// Value: []byte(`{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"}`),
// },
// Role: authpb.Role_ROLE_OWNER,
// },
}
bodyStr, err := json.Marshal(bodyObj)
if err != nil {
@ -168,7 +168,7 @@ func (am *Manager) Authenticate(ctx context.Context, clientID, clientSecret stri
}
if statusCode != 200 {
return nil, nil, errors.New("Username/password not recognized by Nextcloud backend")
return nil, nil, errtypes.PermissionDenied("Username/password not recognized by Nextcloud backend")
}
type resultsObj struct {

View File

@ -106,6 +106,7 @@ func (m *manager) Authenticate(ctx context.Context, token, _ string) (*userpb.Us
// the user authenticated using the ocmshares authentication method
// is the recipient of the share
u := shareRes.Share.Grantee.GetUserId()
log.Debug().Msgf("ocmshares found grantee '%s' at '%s'", u.OpaqueId, u.Idp)
d, err := utils.MarshalProtoV1ToJSON(shareRes.GetShare().Creator)
if err != nil {

View File

@ -48,11 +48,13 @@ func VerifyScope(ctx context.Context, scopeMap map[string]*authpb.Scope, resourc
for s, f := range supportedScopes {
if strings.HasPrefix(k, s) {
if valid, err := f(ctx, scope, resource, logger); err == nil && valid {
logger.Trace().Interface("scope", scope).Interface("resource", resource).Msg("scope is valid")
return true, nil
}
}
}
}
logger.Trace().Interface("scopemap", scopeMap).Interface("resource", resource).Msg("no valid scope found")
return false, nil
}

View File

@ -142,6 +142,7 @@ func getStorageManager(ctx context.Context, c *config) (repository.Repository, e
// CreateTransfer creates a transfer job and returns a TxInfo object that includes a unique transfer id.
// Specified target URIs are of form scheme://userinfo@host:port?name={path}
func (driver *rclone) CreateTransfer(ctx context.Context, srcTargetURI string, dstTargetURI string) (*datatx.TxInfo, error) {
log := appctx.GetLogger(ctx)
srcEp, err := driver.extractEndpointInfo(ctx, srcTargetURI)
if err != nil {
return nil, err
@ -159,6 +160,7 @@ func (driver *rclone) CreateTransfer(ctx context.Context, srcTargetURI string, d
// we always set the userinfo part of the destination url for rclone tpc push support
dstRemote := fmt.Sprintf("%s://%s@%s", destEp.endpointScheme, dstToken, destEp.endpoint)
log.Debug().Str("srcRemote", srcRemote).Str("srcPath", srcPath).Str("srcToken", srcToken).Str("dstRemote", dstRemote).Str("dstPath", dstPath).Str("dstToken", dstToken).Msg("starting rclone job")
return driver.startJob(ctx, "", srcRemote, srcPath, srcToken, dstRemote, dstPath, dstToken)
}

View File

@ -22,6 +22,7 @@ import (
// Load core share manager drivers.
_ "github.com/cs3org/reva/pkg/ocm/invite/repository/json"
_ "github.com/cs3org/reva/pkg/ocm/invite/repository/memory"
_ "github.com/cs3org/reva/pkg/ocm/invite/repository/nextcloud"
_ "github.com/cs3org/reva/pkg/ocm/invite/repository/sql"
// Add your own here.
)

View File

@ -0,0 +1,410 @@
// Copyright 2018-2023 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package nextcloud
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"time"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
conversions "github.com/cs3org/reva/pkg/cbox/utils"
"github.com/cs3org/reva/pkg/ocm/invite"
"github.com/cs3org/reva/pkg/ocm/invite/repository/registry"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
// This module implement the invite.Repository interface as a nextcloud (calling an external OC/NC instance) driver.
func init() {
registry.Register("nextcloud", New)
}
// Client is an API client.
type Client struct {
Config *config
HTTPClient *http.Client
GatewayClient gatewayv1beta1.GatewayAPIClient
}
type config struct {
BaseURL string `mapstructure:"base_url" default:"http://localhost"`
APIKey string `mapstructure:"api_key"`
GatewaySvc string `mapstructure:"gatewaysvc"`
}
type apiToken struct {
Token string `json:"token"`
Initiator string `json:"initiator"`
Description string `json:"description"`
Expiration time.Time `json:"expiration"`
}
type apiOCMUser struct {
OpaqueUserID string `json:"opaqueUserId"`
Idp string `json:"idp"`
Email string `json:"email"`
DisplayName string `json:"displayName"`
}
// New returns a new invite manager object.
func New(ctx context.Context, m map[string]interface{}) (invite.Repository, error) {
config, err := parseConfig(m)
if err != nil {
return nil, errors.Wrap(err, "error parsing config for nextcloud invite repository")
}
gw, err := pool.GetGatewayServiceClient(pool.Endpoint(config.GatewaySvc))
if err != nil {
return nil, err
}
client := &Client{
Config: config,
HTTPClient: &http.Client{},
GatewayClient: gw,
}
return client, nil
}
func parseConfig(c map[string]interface{}) (*config, error) {
var conf config
if err := mapstructure.Decode(c, &conf); err != nil {
return nil, err
}
return &conf, nil
}
func timestampToTime(ctx context.Context, t *types.Timestamp) time.Time {
return time.Unix(int64(t.Seconds), int64(t.Nanos))
}
func (c *Client) convertToInviteToken(ctx context.Context, tkn *apiToken) (*invitepb.InviteToken, error) {
usr, err := conversions.ExtractUserID(ctx, c.GatewayClient, tkn.Initiator)
if err != nil {
return nil, err
}
return &invitepb.InviteToken{
Token: tkn.Token,
UserId: usr,
Expiration: &types.Timestamp{
Seconds: uint64(tkn.Expiration.Unix()),
},
Description: tkn.Description,
}, nil
}
func (u *apiOCMUser) toCS3User() *userpb.User {
return &userpb.User{
Id: &userpb.UserId{
Idp: u.Idp,
OpaqueId: u.OpaqueUserID,
Type: userpb.UserType_USER_TYPE_FEDERATED,
},
Mail: u.Email,
DisplayName: u.DisplayName,
}
}
func (c *Client) doPostToken(token string, initiator string, description string, expiration time.Time) (bool, error) {
bodyObj := &apiToken{
Token: token,
Initiator: initiator,
Description: description,
Expiration: expiration,
}
bodyStr, err := json.Marshal(bodyObj)
if err != nil {
return false, err
}
requestURL := c.Config.BaseURL + "/api/v1/add_token/" + initiator
req, err := http.NewRequest(http.MethodPost, requestURL, strings.NewReader(string(bodyStr)))
if err != nil {
return false, err
}
req.Header.Set("apikey", c.Config.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return false, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode))
}
return true, nil
}
func (c *Client) doGetToken(token string) (*apiToken, error) {
requestURL := c.Config.BaseURL + "/api/v1/get_token" + "?token=" + token
req, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("apikey", c.Config.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Unexpected response code from API: " + strconv.Itoa(resp.StatusCode))
}
result := &apiToken{}
err = json.Unmarshal(body, &result)
if err != nil {
return nil, err
}
return result, nil
}
func (c *Client) doGetAllTokens(initiator string) ([]*apiToken, error) {
requestURL := c.Config.BaseURL + "/api/v1/tokens_list/" + initiator
req, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("apikey", c.Config.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Unexpected response code from API: " + strconv.Itoa(resp.StatusCode))
}
result := []*apiToken{}
err = json.Unmarshal(body, &result)
if err != nil {
return nil, err
}
return result, nil
}
func (c *Client) doPostRemoteUser(initiator string, opaqueUserID string, idp string, email string, displayName string) (bool, error) {
bodyObj := &apiOCMUser{
DisplayName: displayName,
Email: email,
Idp: idp,
OpaqueUserID: opaqueUserID,
}
bodyStr, err := json.Marshal(bodyObj)
if err != nil {
return false, err
}
requestURL := c.Config.BaseURL + "/api/v1/add_remote_user/" + initiator
req, err := http.NewRequest(http.MethodPost, requestURL, strings.NewReader(string(bodyStr)))
if err != nil {
return false, err
}
req.Header.Set("apikey", c.Config.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return false, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return false, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode))
}
return true, nil
}
func (c *Client) doGetRemoteUser(initiator string, opaqueUserID string, idp string) (*apiOCMUser, error) {
requestURL := c.Config.BaseURL + "/api/v1/get_remote_user/" + initiator + "?userId=" + opaqueUserID + "&idp=" + idp
req, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("apikey", c.Config.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Unexpected response code from API: " + strconv.Itoa(resp.StatusCode))
}
result := &apiOCMUser{}
err = json.Unmarshal(body, &result)
if err != nil {
return nil, err
}
return result, nil
}
func (c *Client) doGetAllRemoteUsers(initiator string, search string) ([]*apiOCMUser, error) {
requestURL := c.Config.BaseURL + "/api/v1/find_remote_user/" + initiator + "?search=" + search
req, err := http.NewRequest(http.MethodGet, requestURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("apikey", c.Config.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Unexpected response code from API: " + strconv.Itoa(resp.StatusCode))
}
result := []*apiOCMUser{}
err = json.Unmarshal(body, &result)
if err != nil {
return nil, err
}
return result, nil
}
// AddToken stores the token in the external repository.
func (c *Client) AddToken(ctx context.Context, token *invitepb.InviteToken) error {
result, err := c.doPostToken(token.Token, conversions.FormatUserID(token.UserId), token.Description, timestampToTime(ctx, token.Expiration))
if !result {
return err
}
return nil
}
// GetToken gets the token from the external repository.
func (c *Client) GetToken(ctx context.Context, token string) (*invitepb.InviteToken, error) {
t, err := c.doGetToken(token)
if err != nil {
return nil, err
}
it, cerr := c.convertToInviteToken(ctx, t)
if cerr != nil {
return nil, cerr
}
return it, nil
}
func (c *Client) ListTokens(ctx context.Context, initiator *userpb.UserId) ([]*invitepb.InviteToken, error) {
tokens := []*invitepb.InviteToken{}
rows, err := c.doGetAllTokens(conversions.FormatUserID(initiator))
if err != nil {
return nil, err
}
for _, row := range rows {
it, cerr := c.convertToInviteToken(ctx, row)
if cerr != nil {
return nil, cerr
}
tokens = append(tokens, it)
}
return tokens, nil
}
// AddRemoteUser stores the remote user.
func (c *Client) AddRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.User) error {
if _, err := c.doPostRemoteUser(conversions.FormatUserID(initiator), conversions.FormatUserID(remoteUser.Id), remoteUser.Id.Idp, remoteUser.Mail, remoteUser.DisplayName); err != nil {
return err
}
return nil
}
// GetRemoteUser retrieves details about a remote user who has accepted an invite to share.
func (c *Client) GetRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUserID *userpb.UserId) (*userpb.User, error) {
result, err := c.doGetRemoteUser(conversions.FormatUserID(initiator), conversions.FormatUserID(remoteUserID), remoteUserID.Idp)
if err != nil {
return nil, err
}
return result.toCS3User(), nil
}
// FindRemoteUsers finds remote users who have accepted invites based on their attributes.
func (c *Client) FindRemoteUsers(ctx context.Context, initiator *userpb.UserId, attr string) ([]*userpb.User, error) {
rows, err := c.doGetAllRemoteUsers(conversions.FormatUserID(initiator), attr)
if err != nil {
return nil, err
}
result := []*userpb.User{}
for _, row := range rows {
result = append(result, row.toCS3User())
}
return result, nil
}
// DeleteRemoteUser removes from the remote user from the initiator's list.
func (c *Client) DeleteRemoteUser(ctx context.Context, initiator *userpb.UserId, remoteUser *userpb.UserId) error {
return nil
}

View File

@ -33,7 +33,9 @@ import (
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/ocm/share"
"github.com/cs3org/reva/pkg/ocm/share/repository/registry"
"github.com/cs3org/reva/pkg/utils"
@ -53,6 +55,7 @@ type Manager struct {
sharedSecret string
webDAVHost string
endPoint string
mountID string
}
// ShareManagerConfig contains config for a Nextcloud-based ShareManager.
@ -61,6 +64,7 @@ type ShareManagerConfig struct {
SharedSecret string `mapstructure:"shared_secret"`
WebDAVHost string `mapstructure:"webdav_host"`
MockHTTP bool `mapstructure:"mock_http"`
MountID string `mapstructure:"mount_id" docs:";The Reva mount id to identify the storage provider proxying the EFSS. Note that only one EFSS can be proxied by a given Reva process."`
}
// Action describes a REST request to forward to the Nextcloud backend.
@ -78,14 +82,20 @@ type GranteeAltMap struct {
// ShareAltMap is an alternative map to JSON-unmarshal a Share.
type ShareAltMap struct {
ID *ocm.ShareId `json:"id"`
RemoteShareID string `json:"remote_share_id"`
Permissions *ocm.SharePermissions `json:"permissions"`
Grantee *GranteeAltMap `json:"grantee"`
Owner *userpb.UserId `json:"owner"`
Creator *userpb.UserId `json:"creator"`
Ctime *typespb.Timestamp `json:"ctime"`
Mtime *typespb.Timestamp `json:"mtime"`
ID *ocm.ShareId `json:"id"`
ResourceID struct {
OpaqueID string `json:"opaque_id"`
} `json:"resource_id"`
RemoteShareID string `json:"remote_share_id"`
Permissions int `json:"permissions"`
Grantee struct {
ID *userpb.UserId `json:"id"`
} `json:"grantee"`
Owner *userpb.User `json:"owner"`
Creator *userpb.User `json:"creator"`
Ctime *typespb.Timestamp `json:"ctime"`
Mtime *typespb.Timestamp `json:"mtime"`
Token string `json:"token"`
}
// ReceivedShareAltMap is an alternative map to JSON-unmarshal a ReceivedShare.
@ -126,6 +136,7 @@ func NewShareManager(c *ShareManagerConfig) (*Manager, error) {
sharedSecret: c.SharedSecret,
client: client,
webDAVHost: c.WebDAVHost,
mountID: c.MountID,
}, nil
}
@ -150,31 +161,57 @@ func (sm *Manager) StoreShare(ctx context.Context, share *ocm.Share) (*ocm.Share
return share, nil
}
func (sm *Manager) efssShareToOcm(resp *ShareAltMap) *ocm.Share {
// Parse the JSON struct returned by the PHP SM app into an OCM share object
return &ocm.Share{
Id: resp.ID,
ResourceId: &provider.ResourceId{
OpaqueId: resp.ResourceID.OpaqueID,
StorageId: sm.mountID,
},
Name: "", // FIXME missing from SM app
Token: resp.Token,
Grantee: &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
Id: &provider.Grantee_UserId{
UserId: resp.Grantee.ID,
},
},
Owner: &userpb.UserId{
OpaqueId: resp.Owner.Id.OpaqueId,
Idp: resp.Owner.Id.Idp,
},
Creator: &userpb.UserId{
OpaqueId: resp.Creator.Id.OpaqueId,
Idp: resp.Creator.Id.Idp,
},
Ctime: resp.Ctime,
Mtime: resp.Mtime,
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(conversions.Permissions(resp.Permissions)).CS3ResourcePermissions()),
// FIXME share.NewWebAppAccessMethod() missing from SM app
// FIXME share.NewDataTxAccessMethod()
},
}
}
// GetShare gets the information for a share by the given ref.
func (sm *Manager) GetShare(ctx context.Context, user *userpb.User, ref *ocm.ShareReference) (*ocm.Share, error) {
data, err := json.Marshal(ref)
if err != nil {
return nil, err
}
_, body, err := sm.do(ctx, Action{"GetShare", string(data)}, getUsername(user))
_, body, err := sm.do(ctx, Action{"GetSentShareByToken", string(data)}, getUsername(user))
if err != nil {
return nil, err
}
altResult := &ShareAltMap{}
altResult := ShareAltMap{}
if err := json.Unmarshal(body, &altResult); err != nil {
return nil, err
}
return &ocm.Share{
Id: altResult.ID,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
}, nil
return sm.efssShareToOcm(&altResult), nil
}
// DeleteShare deletes the share pointed by ref.
@ -207,20 +244,11 @@ func (sm *Manager) UpdateShare(ctx context.Context, user *userpb.User, ref *ocm.
return nil, err
}
altResult := &ShareAltMap{}
altResult := ShareAltMap{}
if err := json.Unmarshal(body, &altResult); err != nil {
return nil, err
}
return &ocm.Share{
Id: altResult.ID,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
}, nil
return sm.efssShareToOcm(&altResult), nil
}
// ListShares returns the shares created by the user. If md is provided is not nil,
@ -243,16 +271,7 @@ func (sm *Manager) ListShares(ctx context.Context, user *userpb.User, filters []
var lst = make([]*ocm.Share, 0, len(respArr))
for _, altResult := range respArr {
lst = append(lst, &ocm.Share{
Id: altResult.ID,
Grantee: &provider.Grantee{
Id: altResult.Grantee.ID,
},
Owner: altResult.Owner,
Creator: altResult.Creator,
Ctime: altResult.Ctime,
Mtime: altResult.Mtime,
})
lst = append(lst, sm.efssShareToOcm(&altResult))
}
return lst, nil
}
@ -274,9 +293,30 @@ func (sm *Manager) StoreReceivedShare(ctx context.Context, share *ocm.ReceivedSh
return share, nil
}
func efssReceivedShareToOcm(altResultShare *ReceivedShareAltMap) *ocm.ReceivedShare {
// Parse the JSON struct returned by the PHP SM app into an OCM received share object
return &ocm.ReceivedShare{
Id: altResultShare.Share.ID,
Name: "", // FIXME missing on SM app
RemoteShareId: altResultShare.Share.RemoteShareID, // sic, see https://github.com/cs3org/reva/pull/3852#discussion_r1189681465
Grantee: &provider.Grantee{
Id: &provider.Grantee_UserId{
UserId: altResultShare.Share.Grantee.ID,
},
},
Owner: altResultShare.Share.Owner.Id,
Creator: altResultShare.Share.Creator.Id,
Ctime: altResultShare.Share.Ctime,
Mtime: altResultShare.Share.Mtime,
ShareType: ocm.ShareType_SHARE_TYPE_USER,
// ResourceType: provider.ResourceType_RESOURCE_TYPE_FILE or CONTAINER, missing info on SM app
// Protocols: []*ocm.Protocol{} FIXME SM app does not persist multi protocols yet
State: altResultShare.State,
}
}
// ListReceivedShares returns the list of shares the user has access.
func (sm *Manager) ListReceivedShares(ctx context.Context, user *userpb.User) ([]*ocm.ReceivedShare, error) {
log := appctx.GetLogger(ctx)
_, respBody, err := sm.do(ctx, Action{"ListReceivedShares", ""}, getUsername(user))
if err != nil {
return nil, err
@ -289,23 +329,9 @@ func (sm *Manager) ListReceivedShares(ctx context.Context, user *userpb.User) ([
res := make([]*ocm.ReceivedShare, 0, len(respArr))
for _, share := range respArr {
altResultShare := share.Share
log.Info().Msgf("Unpacking share object %+v\n", altResultShare)
if altResultShare == nil {
continue
if share.Share != nil {
res = append(res, efssReceivedShareToOcm(&share))
}
res = append(res, &ocm.ReceivedShare{
Id: altResultShare.ID,
RemoteShareId: altResultShare.RemoteShareID, // sic, see https://github.com/cs3org/reva/pull/3852#discussion_r1189681465
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
State: share.State,
})
}
return res, nil
}
@ -328,22 +354,9 @@ func (sm *Manager) GetReceivedShare(ctx context.Context, user *userpb.User, ref
}
altResultShare := altResult.Share
if altResultShare == nil {
return &ocm.ReceivedShare{
State: altResult.State,
}, nil
return nil, errtypes.NotFound("Received share not found from EFSS API")
}
return &ocm.ReceivedShare{
Id: altResultShare.ID,
RemoteShareId: altResultShare.RemoteShareID, // sic, see https://github.com/cs3org/reva/pull/3852#discussion_r1189681465
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
State: altResult.State,
}, nil
return efssReceivedShareToOcm(&altResult), nil
}
// UpdateReceivedShare updates the received share with share state.
@ -374,22 +387,9 @@ func (sm *Manager) UpdateReceivedShare(ctx context.Context, user *userpb.User, s
}
altResultShare := altResult.Share
if altResultShare == nil {
return &ocm.ReceivedShare{
State: altResult.State,
}, nil
return nil, errtypes.NotFound("Received share not found from EFSS API")
}
return &ocm.ReceivedShare{
Id: altResultShare.ID,
RemoteShareId: altResultShare.RemoteShareID, // sic, see https://github.com/cs3org/reva/pull/3852#discussion_r1189681465
Grantee: &provider.Grantee{
Id: altResultShare.Grantee.ID,
},
Owner: altResultShare.Owner,
Creator: altResultShare.Creator,
Ctime: altResultShare.Ctime,
Mtime: altResultShare.Mtime,
State: altResult.State,
}, nil
return efssReceivedShareToOcm(&altResult), nil
}
func getUsername(user *userpb.User) string {
@ -400,14 +400,14 @@ func getUsername(user *userpb.User) string {
return user.Id.OpaqueId
}
return "empty-username"
return "nobody"
}
func (sm *Manager) do(ctx context.Context, a Action, username string) (int, []byte, error) {
url := sm.endPoint + "~" + username + "/api/ocm/" + a.verb
log := appctx.GetLogger(ctx)
log.Info().Msgf("am.do %s %s", url, a.argS)
log.Info().Msgf("sm.do %s %s", url, a.argS)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(a.argS))
if err != nil {
return 0, nil, err
@ -428,10 +428,10 @@ func (sm *Manager) do(ctx context.Context, a Action, username string) (int, []by
// curl -i -H 'application/json' -H 'X-Reva-Secret: shared-secret-1' -d '{"md":{"opaque_id":"fileid-/other/q/as"},"g":{"grantee":{"type":1,"Id":{"UserId":{"idp":"revanc2.docker","opaque_id":"marie"}}},"permissions":{"permissions":{"get_path":true,"initiate_file_download":true,"list_container":true,"list_file_versions":true,"stat":true}}},"provider_domain":"cern.ch","resource_type":"file","provider_id":2,"owner_opaque_id":"einstein","owner_display_name":"Albert Einstein","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}' https://nc1.docker/index.php/apps/sciencemesh/~/api/ocm/addSentShare
log.Info().Msgf("am.do response %d %s", resp.StatusCode, body)
log.Info().Int("status", resp.StatusCode).Msgf("sent request to EFSS API, response: %s", body)
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode))
return 0, nil, fmt.Errorf("Unexpected response from EFSS API: " + strconv.Itoa(resp.StatusCode))
}
return resp.StatusCode, body, nil
}

View File

@ -48,10 +48,11 @@ var responses = map[string]Response{
`POST /apps/sciencemesh/~tester/api/ocm/GetShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/Unshare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, ``, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/UpdateShare {"ref":{"Spec":{"Id":{"opaque_id":"some-share-id"}}},"p":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/ListShares [{"type":4,"Term":{"Creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}]`: {200, `[{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}]`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/ListReceivedShares `: {200, `[{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}]`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/GetReceivedShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"share":{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/UpdateReceivedShare {"received_share":{"id":{},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"state":2},"field_mask":{"paths":["state"]}}`: {200, `{"share":{"id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/ListShares [{"type":4,"Term":{"Creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}]`: {200, `[{"id":{},"resource_id":{},"permissions":1,"grantee":{"type":1,"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"owner":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"creator":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"token":"some-token"}]`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/ListReceivedShares `: {200, `[{"share":{"id":{},"resource_id":{},"permissions":1,"grantee":{"type":1,"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"owner":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"creator":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"token":"some-token"},"state":2}]`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/GetReceivedShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"share":{"id":{},"resource_id":{},"permissions":1,"grantee":{"type":1,"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"owner":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"creator":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"token":"some-token"},"state":2}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/UpdateReceivedShare {"received_share":{"id":{},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"share_type":1,"state":2},"field_mask":{"paths":["state"]}}`: {200, `{"share":{"id":{},"resource_id":{},"name":"","permissions":1,"grantee":{"type":1,"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"owner":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"creator":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}},"state":2}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/ocm/GetSentShareByToken {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"id":{},"resource_id":{},"permissions":1,"grantee":{"type":1,"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"owner":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"creator":{"id":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"}},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"token":"some-token"}`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/addReceivedShare {"md":{"opaque_id":"fileid-/some/path"},"g":{"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"permissions":{"permissions":{"get_path":true}}},"provider_domain":"cern.ch","resource_type":"file","provider_id":2,"owner_opaque_id":"einstein","owner_display_name":"Albert Einstein","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
`POST /index.php/apps/sciencemesh/~marie/api/ocm/GetShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
@ -80,15 +81,12 @@ func GetNextcloudServerMock(called *[]string) http.Handler {
}
if (response == Response{}) {
fmt.Printf("%s %s %s %s\n", r.Method, r.URL, buf.String(), serverState)
response = Response{500, fmt.Sprintf("{\"response not defined\": \"%s\"}", key), serverStateEmpty}
}
serverState = responses[key].newServerState
if serverState == `` {
serverState = serverStateError
response = Response{500, fmt.Sprintf("{\"response not defined\": \"%s\"}", key), serverStateError}
}
serverState = response.newServerState
w.WriteHeader(response.code)
// w.Header().Set("Etag", "mocker-etag")
_, err = w.Write([]byte(responses[key].body))
_, err = w.Write([]byte(response.body))
if err != nil {
panic(err)
}

View File

@ -26,8 +26,10 @@ import (
ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/pkg/auth/scope"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
masked_share "github.com/cs3org/reva/pkg/ocm/share"
"github.com/cs3org/reva/pkg/ocm/share/repository/nextcloud"
jwt "github.com/cs3org/reva/pkg/token/manager/jwt"
. "github.com/onsi/ginkgo"
@ -257,25 +259,28 @@ var _ = Describe("Nextcloud", func() {
})
Expect(err).ToNot(HaveOccurred())
Expect(*share).To(Equal(ocm.Share{
Id: &ocm.ShareId{},
Id: &ocm.ShareId{},
ResourceId: &provider.ResourceId{},
Name: "",
Grantee: &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
Id: &provider.Grantee_UserId{
UserId: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
},
Owner: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Creator: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
AccessMethods: []*ocm.AccessMethod{
masked_share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(conversions.Permissions(1)).CS3ResourcePermissions()),
},
Ctime: &types.Timestamp{
Seconds: 1234567890,
@ -291,8 +296,10 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
Token: "some-token",
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/GetShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`)
checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/GetSentShareByToken {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`)
})
})
@ -390,24 +397,28 @@ var _ = Describe("Nextcloud", func() {
Expect(len(shares)).To(Equal(1))
Expect(*shares[0]).To(Equal(ocm.Share{
Id: &ocm.ShareId{},
ResourceId: &provider.ResourceId{
StorageId: "",
OpaqueId: "",
SpaceId: "",
},
Name: "",
Grantee: &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
Id: &provider.Grantee_UserId{
UserId: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
},
Owner: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Creator: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Ctime: &types.Timestamp{
Seconds: 1234567890,
@ -423,6 +434,11 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
ShareType: ocm.ShareType_SHARE_TYPE_USER,
AccessMethods: []*ocm.AccessMethod{
masked_share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(conversions.Permissions(1)).CS3ResourcePermissions()),
},
Token: "some-token",
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/ListShares [{"type":4,"Term":{"Creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}]`)
})
@ -439,25 +455,23 @@ var _ = Describe("Nextcloud", func() {
Expect(len(receivedShares)).To(Equal(1))
Expect(*receivedShares[0]).To(Equal(ocm.ReceivedShare{
Id: &ocm.ShareId{},
Name: "",
RemoteShareId: "",
Grantee: &provider.Grantee{
Id: &provider.Grantee_UserId{
UserId: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
},
Owner: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Creator: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Ctime: &types.Timestamp{
Seconds: 1234567890,
@ -473,7 +487,8 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
ShareType: ocm.ShareType_SHARE_TYPE_USER,
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/ListReceivedShares `)
})
@ -495,25 +510,23 @@ var _ = Describe("Nextcloud", func() {
Expect(err).ToNot(HaveOccurred())
Expect(*receivedShare).To(Equal(ocm.ReceivedShare{
Id: &ocm.ShareId{},
Name: "",
RemoteShareId: "",
Grantee: &provider.Grantee{
Id: &provider.Grantee_UserId{
UserId: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
},
Owner: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Creator: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Ctime: &types.Timestamp{
Seconds: 1234567890,
@ -529,7 +542,8 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
ShareType: ocm.ShareType_SHARE_TYPE_USER,
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/GetReceivedShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`)
})
@ -544,6 +558,7 @@ var _ = Describe("Nextcloud", func() {
receivedShare, err := am.UpdateReceivedShare(ctx, user,
&ocm.ReceivedShare{
Id: &ocm.ShareId{},
Name: "",
RemoteShareId: "",
Grantee: &provider.Grantee{
Id: &provider.Grantee_UserId{
@ -578,7 +593,8 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
ShareType: ocm.ShareType_SHARE_TYPE_USER,
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
},
&field_mask.FieldMask{
Paths: []string{"state"},
@ -586,25 +602,23 @@ var _ = Describe("Nextcloud", func() {
Expect(err).ToNot(HaveOccurred())
Expect(*receivedShare).To(Equal(ocm.ReceivedShare{
Id: &ocm.ShareId{},
Name: "",
RemoteShareId: "",
Grantee: &provider.Grantee{
Id: &provider.Grantee_UserId{
UserId: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
},
Owner: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Creator: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
Ctime: &types.Timestamp{
Seconds: 1234567890,
@ -620,9 +634,10 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
ShareType: ocm.ShareType_SHARE_TYPE_USER,
State: ocm.ShareState_SHARE_STATE_ACCEPTED,
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/UpdateReceivedShare {"received_share":{"id":{},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"state":2},"field_mask":{"paths":["state"]}}`)
checkCalled(called, `POST /apps/sciencemesh/~tester/api/ocm/UpdateReceivedShare {"received_share":{"id":{},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890},"share_type":1,"state":2},"field_mask":{"paths":["state"]}}`)
})
})

View File

@ -268,13 +268,14 @@ func (d *driver) unwrappedOpFromShareCreator(ctx context.Context, share *ocmv1be
func (d *driver) GetMD(ctx context.Context, ref *provider.Reference, _ []string) (*provider.ResourceInfo, error) {
share, rel, err := d.shareAndRelativePathFromRef(ctx, ref)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Error from ocmoutcoming::shareAndRelativePathFromRef")
}
var info *provider.ResourceInfo
if err := d.unwrappedOpFromShareCreator(ctx, share, rel, func(ctx context.Context, newRef *provider.Reference) error {
info, err = d.stat(ctx, newRef)
if err != nil {
// we do not wrap this as we'd mask the original error code
return err
}
return d.augmentResourceInfo(ctx, info, share)

View File

@ -19,23 +19,26 @@
package nextcloud
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"path/filepath"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/pkg/appctx"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/storage"
"github.com/cs3org/reva/pkg/storage/fs/registry"
"github.com/cs3org/reva/pkg/utils/cfg"
"github.com/cs3org/reva/pkg/utils/list"
"github.com/pkg/errors"
)
@ -58,6 +61,38 @@ type StorageDriver struct {
client *http.Client
}
// MDFromEFSS is returned by the EFSS to represent a resource.
type MDFromEFSS struct {
Type int `json:"type"`
ID struct {
OpaqueID string `json:"opaque_id"`
} `json:"id"`
Checksum struct {
Type int `json:"type"`
Sum string `json:"sum"`
} `json:"checksum"`
Etag string `json:"etag"`
MimeType string `json:"mime_type"`
Mtime struct {
Seconds int `json:"seconds"`
} `json:"mtime"`
Path string `json:"path"`
Permissions int `json:"permissions"`
Size int `json:"size"`
CanonicalMetadata struct {
Target any `json:"target"`
} `json:"canonical_metadata"`
ArbitraryMetadata struct {
Metadata struct {
Placeholder string `json:".placeholder"`
} `json:"metadata"`
} `json:"arbitrary_metadata"`
Owner struct {
OpaqueID string `json:"opaque_id"`
Idp string `json:"idp"`
} `json:"owner"`
}
// New returns an implementation to of the storage.FS interface that talks to
// a Nextcloud instance over http.
func New(ctx context.Context, m map[string]interface{}) (storage.FS, error) {
@ -95,12 +130,6 @@ func NewStorageDriver(c *StorageDriverConfig) (*StorageDriver, error) {
}, nil
}
// Action describes a REST request to forward to the Nextcloud backend.
type Action struct {
verb string
argS string
}
func getUser(ctx context.Context) (*user.User, error) {
u, ok := ctxpkg.ContextGetUser(ctx)
if !ok {
@ -115,154 +144,89 @@ func (nc *StorageDriver) SetHTTPClient(c *http.Client) {
nc.client = c
}
func (nc *StorageDriver) doUpload(ctx context.Context, filePath string, r io.ReadCloser) error {
// log := appctx.GetLogger(ctx)
// log.Error().Msgf("in doUpload! %s", filePath)
func (nc *StorageDriver) doRaw(ctx context.Context, req *http.Request) (io.ReadCloser, error) {
log := appctx.GetLogger(ctx)
log.Debug().Str("method", req.Method).Str("url", req.URL.String()).Msg("sending request to EFSS API")
resp, err := nc.client.Do(req)
if err != nil {
return nil, errors.Wrap(err, "error sending request")
}
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusNotFound {
body, _ := io.ReadAll(resp.Body)
defer resp.Body.Close()
return nil, fmt.Errorf("unexpected response code %d from EFSS API, body was %s", resp.StatusCode, body)
}
if resp.StatusCode == http.StatusNotFound {
return nil, errtypes.NotFound("")
}
return resp.Body, nil
}
func (nc *StorageDriver) prepareRequest(ctx context.Context, method, path string, body io.Reader) (*http.Request, error) {
user, err := getUser(ctx)
if err != nil {
// log.Error().Msg("error getting user!")
return nil, err
}
url, _ := url.JoinPath(nc.endPoint, "~"+user.Id.OpaqueId, "/api/storage", path)
req, err := http.NewRequestWithContext(ctx, method, url, body)
if err != nil {
return nil, errors.Wrap(err, "error creating request")
}
req.Header.Set("X-Reva-Secret", nc.sharedSecret)
return req, nil
}
// A convenient method that internally uses doRaw and automatically marshals and unmarshals
// the body request and the body response as json if not nil.
func (nc *StorageDriver) do(ctx context.Context, method, path string, bodyObj, targetObj any) error {
var body []byte
var err error
if bodyObj != nil {
body, err = json.Marshal(bodyObj)
if err != nil {
return errors.Wrap(err, "error marshalling body to json")
}
}
req, err := nc.prepareRequest(ctx, method, path, bytes.NewBuffer(body))
if err != nil {
return err
}
// log.Error().Msgf("got user! %+v", user)
// See https://github.com/pondersource/nc-sciencemesh/issues/5
// url := nc.endPoint + "~" + user.Username + "/files/" + filePath
url := nc.endPoint + "~" + user.Id.OpaqueId + "/api/storage/Upload/home" + filePath
// log.Error().Msgf("sending PUT to NC/OC! %s", url)
req, err := http.NewRequest(http.MethodPut, url, r)
if err != nil {
// log.Error().Msgf("error! %s", err.Error())
panic(err)
}
req.Header.Set("X-Reva-Secret", nc.sharedSecret)
// set the request header Content-Type for the upload
// FIXME: get the actual content type from somewhere
req.Header.Set("Content-Type", "text/plain")
// log.Error().Msg("client req")
resp, err := nc.client.Do(req)
if err != nil {
// log.Error().Msgf("error! %s", err.Error())
panic(err)
}
defer resp.Body.Close()
_, err = io.ReadAll(resp.Body)
return err
}
func (nc *StorageDriver) doDownload(ctx context.Context, filePath string) (io.ReadCloser, error) {
user, err := getUser(ctx)
if err != nil {
return nil, err
}
// See https://github.com/pondersource/nc-sciencemesh/issues/5
// url := nc.endPoint + "~" + user.Username + "/files/" + filePath
url := nc.endPoint + "~" + user.Username + "/api/storage/Download/" + filePath
req, err := http.NewRequest(http.MethodGet, url, strings.NewReader(""))
if err != nil {
panic(err)
}
resp, err := nc.client.Do(req)
if err != nil {
panic(err)
}
if resp.StatusCode != http.StatusOK {
panic("No 200 response code in download request")
}
return resp.Body, err
}
func (nc *StorageDriver) doDownloadRevision(ctx context.Context, filePath string, key string) (io.ReadCloser, error) {
user, err := getUser(ctx)
if err != nil {
return nil, err
}
// See https://github.com/pondersource/nc-sciencemesh/issues/5
url := nc.endPoint + "~" + user.Username + "/api/storage/DownloadRevision/" + url.QueryEscape(key) + "/" + filePath
req, err := http.NewRequest(http.MethodGet, url, strings.NewReader(""))
if err != nil {
panic(err)
}
req.Header.Set("X-Reva-Secret", nc.sharedSecret)
resp, err := nc.client.Do(req)
if err != nil {
panic(err)
}
if resp.StatusCode != http.StatusOK {
panic("No 200 response code in download request")
}
return resp.Body, err
}
func (nc *StorageDriver) do(ctx context.Context, a Action) (int, []byte, error) {
log := appctx.GetLogger(ctx)
user, err := getUser(ctx)
if err != nil {
return 0, nil, err
}
// See https://github.com/cs3org/reva/issues/2377
// for discussion of user.Username vs user.Id.OpaqueId
url := nc.endPoint + "~" + user.Id.OpaqueId + "/api/storage/" + a.verb
log.Info().Msgf("nc.do req %s %s", url, a.argS)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(a.argS))
if err != nil {
return 0, nil, err
}
req.Header.Set("X-Reva-Secret", nc.sharedSecret)
req.Header.Set("Content-Type", "application/json")
resp, err := nc.client.Do(req)
if err != nil {
return 0, nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
res, err := nc.doRaw(ctx, req)
if err != nil {
return 0, nil, err
return err
}
log.Info().Msgf("nc.do res %s %s", url, string(body))
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusNotFound {
return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode) + ":" + string(body))
defer res.Close()
if targetObj != nil {
if err := json.NewDecoder(res).Decode(targetObj); err != nil {
return errors.Wrapf(err, "response %s from EFSS API does not match target type %T", res, targetObj)
}
}
return resp.StatusCode, body, nil
return nil
}
// GetHome as defined in the storage.FS interface.
// GetHome should return the home path of the given user.
// As it is not implemented in the EFSS API, we return an empty string.
func (nc *StorageDriver) GetHome(ctx context.Context) (string, error) {
log := appctx.GetLogger(ctx)
log.Info().Msg("GetHome")
_, respBody, err := nc.do(ctx, Action{"GetHome", ""})
return string(respBody), err
return "", nil
}
// CreateHome as defined in the storage.FS interface.
func (nc *StorageDriver) CreateHome(ctx context.Context) error {
log := appctx.GetLogger(ctx)
log.Info().Msg("CreateHome")
_, _, err := nc.do(ctx, Action{"CreateHome", ""})
return err
return nc.do(ctx, http.MethodPost, "CreateHome", nil, nil)
}
// CreateDir as defined in the storage.FS interface.
func (nc *StorageDriver) CreateDir(ctx context.Context, ref *provider.Reference) error {
bodyStr, err := json.Marshal(ref)
if err != nil {
return err
}
log := appctx.GetLogger(ctx)
log.Info().Msgf("CreateDir %s", bodyStr)
_, _, err = nc.do(ctx, Action{"CreateDir", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "CreateDir", ref, nil)
}
// TouchFile as defined in the storage.FS interface.
@ -272,382 +236,230 @@ func (nc *StorageDriver) TouchFile(ctx context.Context, ref *provider.Reference)
// Delete as defined in the storage.FS interface.
func (nc *StorageDriver) Delete(ctx context.Context, ref *provider.Reference) error {
bodyStr, err := json.Marshal(ref)
if err != nil {
return err
}
log := appctx.GetLogger(ctx)
log.Info().Msgf("Delete %s", bodyStr)
return nc.do(ctx, http.MethodPost, "Delete", ref, nil)
}
_, _, err = nc.do(ctx, Action{"Delete", string(bodyStr)})
return err
type MoveRequest struct {
OldRef *provider.Reference `json:"oldRef"`
NewRef *provider.Reference `json:"newRef"`
}
// Move as defined in the storage.FS interface.
func (nc *StorageDriver) Move(ctx context.Context, oldRef, newRef *provider.Reference) error {
type paramsObj struct {
OldRef *provider.Reference `json:"oldRef"`
NewRef *provider.Reference `json:"newRef"`
}
bodyObj := &paramsObj{
OldRef: oldRef,
NewRef: newRef,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("Move %s", bodyStr)
return nc.do(ctx, http.MethodPost, "Move", MoveRequest{OldRef: oldRef, NewRef: newRef}, nil)
}
_, _, err := nc.do(ctx, Action{"Move", string(bodyStr)})
return err
func resInfoFromEFSS(respObj *MDFromEFSS) *provider.ResourceInfo {
// Parse the JSON struct returned by the PHP SM app into a ResourceInfo,
// translating the permissions from ownCloud DB value to CS3 and ignoring non relevant fields.
return &provider.ResourceInfo{
Id: &provider.ResourceId{
OpaqueId: respObj.ID.OpaqueID,
},
Type: provider.ResourceType(respObj.Type),
Checksum: &provider.ResourceChecksum{
Type: provider.ResourceChecksumType(respObj.Checksum.Type),
Sum: respObj.Checksum.Sum,
},
Etag: respObj.Etag,
MimeType: respObj.MimeType,
Mtime: &typesv1beta1.Timestamp{
Seconds: uint64(respObj.Mtime.Seconds),
},
Path: respObj.Path,
PermissionSet: conversions.RoleFromOCSPermissions(
conversions.Permissions(respObj.Permissions)).CS3ResourcePermissions(),
Size: uint64(respObj.Size),
Owner: &user.UserId{
Idp: respObj.Owner.Idp,
OpaqueId: respObj.Owner.OpaqueID,
Type: user.UserType_USER_TYPE_PRIMARY,
},
}
}
type GetMDRequest struct {
Ref *provider.Reference `json:"ref"`
MdKeys []string `json:"mdKeys"`
}
// GetMD as defined in the storage.FS interface.
func (nc *StorageDriver) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []string) (*provider.ResourceInfo, error) {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
MdKeys []string `json:"mdKeys"`
// MetaData provider.ResourceInfo `json:"metaData"`
}
bodyObj := &paramsObj{
Ref: ref,
MdKeys: mdKeys,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("GetMD %s", bodyStr)
status, body, err := nc.do(ctx, Action{"GetMD", string(bodyStr)})
var target MDFromEFSS
err := nc.do(ctx, http.MethodPost, "GetMD", GetMDRequest{Ref: ref, MdKeys: mdKeys}, &target)
if err != nil {
return nil, err
}
if status == 404 {
return nil, errtypes.NotFound("")
}
var respObj provider.ResourceInfo
err = json.Unmarshal(body, &respObj)
if err != nil {
return nil, err
}
return &respObj, nil
return resInfoFromEFSS(&target), nil
}
// ListFolder as defined in the storage.FS interface.
func (nc *StorageDriver) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys []string) ([]*provider.ResourceInfo, error) {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
MdKeys []string `json:"mdKeys"`
}
bodyObj := &paramsObj{
Ref: ref,
MdKeys: mdKeys,
}
bodyStr, err := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("ListFolder %s", bodyStr)
var l []*MDFromEFSS
err := nc.do(ctx, http.MethodPost, "ListFolder", GetMDRequest{Ref: ref, MdKeys: mdKeys}, &l)
if err != nil {
return nil, err
}
status, body, err := nc.do(ctx, Action{"ListFolder", string(bodyStr)})
if err != nil {
return nil, err
}
if status == 404 {
return nil, errtypes.NotFound("")
}
var respMapArr []provider.ResourceInfo
err = json.Unmarshal(body, &respMapArr)
if err != nil {
return nil, err
}
var pointers = make([]*provider.ResourceInfo, len(respMapArr))
for i := 0; i < len(respMapArr); i++ {
pointers[i] = &respMapArr[i]
}
return pointers, err
return list.Map(l, resInfoFromEFSS), nil
}
type InitiateUploadRequest struct {
Ref *provider.Reference `json:"ref"`
UploadLength int64 `json:"uploadLength"`
Metadata map[string]string `json:"metadata"`
}
// InitiateUpload as defined in the storage.FS interface.
func (nc *StorageDriver) InitiateUpload(ctx context.Context, ref *provider.Reference, uploadLength int64, metadata map[string]string) (map[string]string, error) {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
UploadLength int64 `json:"uploadLength"`
Metadata map[string]string `json:"metadata"`
}
bodyObj := &paramsObj{
Ref: ref,
UploadLength: uploadLength,
Metadata: metadata,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("InitiateUpload %s", bodyStr)
_, respBody, err := nc.do(ctx, Action{"InitiateUpload", string(bodyStr)})
if err != nil {
return nil, err
}
respMap := make(map[string]string)
err = json.Unmarshal(respBody, &respMap)
if err != nil {
return nil, err
}
return respMap, err
var res map[string]string
err := nc.do(ctx, http.MethodPost, "InitiateUpload", InitiateUploadRequest{Ref: ref, UploadLength: uploadLength, Metadata: metadata}, &res)
return res, err
}
// Upload as defined in the storage.FS interface.
func (nc *StorageDriver) Upload(ctx context.Context, ref *provider.Reference, r io.ReadCloser) error {
return nc.doUpload(ctx, ref.Path, r)
req, err := nc.prepareRequest(ctx, http.MethodPut, filepath.Join("/Upload/home", ref.Path), r)
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/octet-stream")
b, err := nc.doRaw(ctx, req)
if err != nil {
return err
}
defer b.Close()
_, _ = io.ReadAll(b)
return nil
}
// Download as defined in the storage.FS interface.
func (nc *StorageDriver) Download(ctx context.Context, ref *provider.Reference) (io.ReadCloser, error) {
return nc.doDownload(ctx, ref.Path)
req, err := nc.prepareRequest(ctx, http.MethodGet, filepath.Join("/Download", ref.Path), nil)
if err != nil {
return nil, err
}
return nc.doRaw(ctx, req)
}
// ListRevisions as defined in the storage.FS interface.
func (nc *StorageDriver) ListRevisions(ctx context.Context, ref *provider.Reference) ([]*provider.FileVersion, error) {
bodyStr, _ := json.Marshal(ref)
log := appctx.GetLogger(ctx)
log.Info().Msgf("ListRevisions %s", bodyStr)
_, respBody, err := nc.do(ctx, Action{"ListRevisions", string(bodyStr)})
if err != nil {
return nil, err
}
var respMapArr []provider.FileVersion
err = json.Unmarshal(respBody, &respMapArr)
if err != nil {
return nil, err
}
revs := make([]*provider.FileVersion, len(respMapArr))
for i := 0; i < len(respMapArr); i++ {
revs[i] = &respMapArr[i]
}
return revs, err
var versions []*provider.FileVersion
err := nc.do(ctx, http.MethodPost, "ListRevisions", ref, &versions)
return versions, err
}
// DownloadRevision as defined in the storage.FS interface.
func (nc *StorageDriver) DownloadRevision(ctx context.Context, ref *provider.Reference, key string) (io.ReadCloser, error) {
log := appctx.GetLogger(ctx)
log.Info().Msgf("DownloadRevision %s %s", ref.Path, key)
req, err := nc.prepareRequest(ctx, http.MethodGet, filepath.Join("/DownloadRevision/", key, ref.Path), nil)
if err != nil {
return nil, err
}
return nc.doRaw(ctx, req)
}
readCloser, err := nc.doDownloadRevision(ctx, ref.Path, key)
return readCloser, err
type RestoreRevisionRequest struct {
Ref *provider.Reference `json:"ref"`
Key string `json:"key"`
}
// RestoreRevision as defined in the storage.FS interface.
func (nc *StorageDriver) RestoreRevision(ctx context.Context, ref *provider.Reference, key string) error {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
Key string `json:"key"`
}
bodyObj := &paramsObj{
Ref: ref,
Key: key,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("RestoreRevision %s", bodyStr)
return nc.do(ctx, http.MethodPost, "RestoreRevision", RestoreRevisionRequest{Ref: ref, Key: key}, nil)
}
_, _, err := nc.do(ctx, Action{"RestoreRevision", string(bodyStr)})
return err
type ListRecycleRequest struct {
Key string `json:"key"`
Path string `json:"path"`
}
// ListRecycle as defined in the storage.FS interface.
func (nc *StorageDriver) ListRecycle(ctx context.Context, basePath, key string, relativePath string) ([]*provider.RecycleItem, error) {
log := appctx.GetLogger(ctx)
log.Info().Msg("ListRecycle")
type paramsObj struct {
Key string `json:"key"`
Path string `json:"path"`
}
bodyObj := &paramsObj{
Key: key,
Path: relativePath,
}
bodyStr, _ := json.Marshal(bodyObj)
_, respBody, err := nc.do(ctx, Action{"ListRecycle", string(bodyStr)})
if err != nil {
return nil, err
}
var respMapArr []provider.RecycleItem
err = json.Unmarshal(respBody, &respMapArr)
if err != nil {
return nil, err
}
items := make([]*provider.RecycleItem, len(respMapArr))
for i := 0; i < len(respMapArr); i++ {
items[i] = &respMapArr[i]
}
func (nc *StorageDriver) ListRecycle(ctx context.Context, basePath, key, relativePath string) ([]*provider.RecycleItem, error) {
var items []*provider.RecycleItem
err := nc.do(ctx, http.MethodPost, "ListRecycle", ListRecycleRequest{Key: key, Path: relativePath}, &items)
return items, err
}
type RestoreRecycleItemRequest struct {
Key string `json:"key"`
Path string `json:"path"`
RestoreRef *provider.Reference `json:"restoreRef"`
}
// RestoreRecycleItem as defined in the storage.FS interface.
func (nc *StorageDriver) RestoreRecycleItem(ctx context.Context, basePath, key, relativePath string, restoreRef *provider.Reference) error {
type paramsObj struct {
Key string `json:"key"`
Path string `json:"path"`
RestoreRef *provider.Reference `json:"restoreRef"`
}
bodyObj := &paramsObj{
Key: key,
Path: relativePath,
RestoreRef: restoreRef,
}
bodyStr, _ := json.Marshal(bodyObj)
return nc.do(ctx, http.MethodPost, "RestoreRecycleItem", RestoreRecycleItemRequest{Key: key, Path: relativePath, RestoreRef: restoreRef}, nil)
}
log := appctx.GetLogger(ctx)
log.Info().Msgf("RestoreRecycleItem %s", bodyStr)
_, _, err := nc.do(ctx, Action{"RestoreRecycleItem", string(bodyStr)})
return err
type PurgeRecycleItemRequest struct {
Key string `json:"key"`
Path string `json:"path"`
}
// PurgeRecycleItem as defined in the storage.FS interface.
func (nc *StorageDriver) PurgeRecycleItem(ctx context.Context, basePath, key, relativePath string) error {
type paramsObj struct {
Key string `json:"key"`
Path string `json:"path"`
}
bodyObj := &paramsObj{
Key: key,
Path: relativePath,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("PurgeRecycleItem %s", bodyStr)
_, _, err := nc.do(ctx, Action{"PurgeRecycleItem", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "PurgeRecycleItem", PurgeRecycleItemRequest{Key: key, Path: relativePath}, nil)
}
// EmptyRecycle as defined in the storage.FS interface.
func (nc *StorageDriver) EmptyRecycle(ctx context.Context) error {
log := appctx.GetLogger(ctx)
log.Info().Msg("EmptyRecycle")
_, _, err := nc.do(ctx, Action{"EmptyRecycle", ""})
return err
return nc.do(ctx, http.MethodPost, "EmptyRecycle", nil, nil)
}
// GetPathByID as defined in the storage.FS interface.
func (nc *StorageDriver) GetPathByID(ctx context.Context, id *provider.ResourceId) (string, error) {
bodyStr, _ := json.Marshal(id)
_, respBody, err := nc.do(ctx, Action{"GetPathByID", string(bodyStr)})
return string(respBody), err
d, _ := json.Marshal(id)
req, err := nc.prepareRequest(ctx, http.MethodPost, "GetPathByID", bytes.NewBuffer(d))
if err != nil {
return "", err
}
body, err := nc.doRaw(ctx, req)
if err != nil {
return "", err
}
defer body.Close()
b, err := io.ReadAll(body)
if err != nil {
return "", err
}
return string(b), nil
}
type GrantRequest struct {
Ref *provider.Reference `json:"ref"`
G *provider.Grant `json:"g"`
}
// AddGrant as defined in the storage.FS interface.
func (nc *StorageDriver) AddGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
G *provider.Grant `json:"g"`
}
bodyObj := &paramsObj{
Ref: ref,
G: g,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("AddGrant %s", bodyStr)
_, _, err := nc.do(ctx, Action{"AddGrant", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "AddGrant", GrantRequest{Ref: ref, G: g}, nil)
}
// DenyGrant as defined in the storage.FS interface.
func (nc *StorageDriver) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
G *provider.Grantee `json:"g"`
}
bodyObj := &paramsObj{
Ref: ref,
G: g,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("DenyGrant %s", bodyStr)
_, _, err := nc.do(ctx, Action{"DenyGrant", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "DenyGrant", GrantRequest{Ref: ref, G: &provider.Grant{Grantee: g}}, nil)
}
// RemoveGrant as defined in the storage.FS interface.
func (nc *StorageDriver) RemoveGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
G *provider.Grant `json:"g"`
}
bodyObj := &paramsObj{
Ref: ref,
G: g,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("RemoveGrant %s", bodyStr)
_, _, err := nc.do(ctx, Action{"RemoveGrant", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "RemoveGrant", GrantRequest{Ref: ref, G: g}, nil)
}
// UpdateGrant as defined in the storage.FS interface.
func (nc *StorageDriver) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
G *provider.Grant `json:"g"`
}
bodyObj := &paramsObj{
Ref: ref,
G: g,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("UpdateGrant %s", bodyStr)
_, _, err := nc.do(ctx, Action{"UpdateGrant", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "UpdateGrant", GrantRequest{Ref: ref, G: g}, nil)
}
// ListGrants as defined in the storage.FS interface.
func (nc *StorageDriver) ListGrants(ctx context.Context, ref *provider.Reference) ([]*provider.Grant, error) {
bodyStr, _ := json.Marshal(ref)
log := appctx.GetLogger(ctx)
log.Info().Msgf("ListGrants %s", bodyStr)
_, respBody, err := nc.do(ctx, Action{"ListGrants", string(bodyStr)})
var respMapArr []map[string]any
err := nc.do(ctx, http.MethodPost, "ListGrants", ref, &respMapArr)
if err != nil {
return nil, err
}
// To avoid this error:
// json: cannot unmarshal object into Go struct field Grantee.grantee.Id of type providerv1beta1.isGrantee_Id
// To test:
// bodyStr, _ := json.Marshal(provider.Grant{
// Grantee: &provider.Grantee{
// Type: provider.GranteeType_GRANTEE_TYPE_USER,
// Id: &provider.Grantee_UserId{
// UserId: &user.UserId{
// Idp: "some-idp",
// OpaqueId: "some-opaque-id",
// Type: user.UserType_USER_TYPE_PRIMARY,
// },
// },
// },
// Permissions: &provider.ResourcePermissions{},
// })
// JSON example:
// [{"grantee":{"Id":{"UserId":{"idp":"some-idp","opaque_id":"some-opaque-id","type":1}}},"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true}}]
var respMapArr []map[string]interface{}
err = json.Unmarshal(respBody, &respMapArr)
if err != nil {
return nil, err
}
grants := make([]*provider.Grant, len(respMapArr))
for i := 0; i < len(respMapArr); i++ {
granteeMap := respMapArr[i]["grantee"].(map[string]interface{})
@ -689,86 +501,55 @@ func (nc *StorageDriver) ListGrants(ctx context.Context, ref *provider.Reference
},
}
}
return grants, err
return grants, nil
}
// GetQuota as defined in the storage.FS interface.
func (nc *StorageDriver) GetQuota(ctx context.Context, ref *provider.Reference) (uint64, uint64, error) {
log := appctx.GetLogger(ctx)
log.Info().Msg("GetQuota")
_, respBody, err := nc.do(ctx, Action{"GetQuota", ""})
func (nc *StorageDriver) GetQuota(ctx context.Context, _ *provider.Reference) (uint64, uint64, error) {
var quotaRes struct {
TotalBytes uint64 `json:"totalBytes"`
UsedBytes uint64 `json:"usedBytes"`
}
err := nc.do(ctx, http.MethodPost, "GetQuota", nil, &quotaRes)
if err != nil {
return 0, 0, err
}
return quotaRes.TotalBytes, quotaRes.UsedBytes, nil
}
var respMap map[string]interface{}
err = json.Unmarshal(respBody, &respMap)
if err != nil {
return 0, 0, err
}
return uint64(respMap["totalBytes"].(float64)), uint64(respMap["usedBytes"].(float64)), err
type CreateReferenceRequest struct {
Path string `json:"path"`
URL string `json:"url"`
}
// CreateReference as defined in the storage.FS interface.
func (nc *StorageDriver) CreateReference(ctx context.Context, path string, targetURI *url.URL) error {
type paramsObj struct {
Path string `json:"path"`
URL string `json:"url"`
}
bodyObj := &paramsObj{
Path: path,
URL: targetURI.String(),
}
bodyStr, _ := json.Marshal(bodyObj)
_, _, err := nc.do(ctx, Action{"CreateReference", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "CreateReference", CreateReferenceRequest{Path: path, URL: targetURI.String()}, nil)
}
// Shutdown as defined in the storage.FS interface.
// Shutdown as defined in the storage.FS interface. Obviously we don't shutdown the EFSS...
func (nc *StorageDriver) Shutdown(ctx context.Context) error {
log := appctx.GetLogger(ctx)
log.Info().Msg("Shutdown")
return nil
}
_, _, err := nc.do(ctx, Action{"Shutdown", ""})
return err
type SetArbitraryMetadataRequest struct {
Ref *provider.Reference `json:"ref"`
Md *provider.ArbitraryMetadata `json:"md"`
}
// SetArbitraryMetadata as defined in the storage.FS interface.
func (nc *StorageDriver) SetArbitraryMetadata(ctx context.Context, ref *provider.Reference, md *provider.ArbitraryMetadata) error {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
Md *provider.ArbitraryMetadata `json:"md"`
}
bodyObj := &paramsObj{
Ref: ref,
Md: md,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("SetArbitraryMetadata %s", bodyStr)
return nc.do(ctx, http.MethodPost, "SetArbitraryMetadata", SetArbitraryMetadataRequest{Ref: ref, Md: md}, nil)
}
_, _, err := nc.do(ctx, Action{"SetArbitraryMetadata", string(bodyStr)})
return err
type UnsetArbitraryMetadataRequest struct {
Ref *provider.Reference `json:"ref"`
Keys []string `json:"keys"`
}
// UnsetArbitraryMetadata as defined in the storage.FS interface.
func (nc *StorageDriver) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Reference, keys []string) error {
type paramsObj struct {
Ref *provider.Reference `json:"ref"`
Keys []string `json:"keys"`
}
bodyObj := &paramsObj{
Ref: ref,
Keys: keys,
}
bodyStr, _ := json.Marshal(bodyObj)
log := appctx.GetLogger(ctx)
log.Info().Msgf("UnsetArbitraryMetadata %s", bodyStr)
_, _, err := nc.do(ctx, Action{"UnsetArbitraryMetadata", string(bodyStr)})
return err
return nc.do(ctx, http.MethodPost, "UnsetArbitraryMetadata", UnsetArbitraryMetadataRequest{Ref: ref, Keys: keys}, nil)
}
// GetLock returns an existing lock on the given reference.
@ -793,51 +574,15 @@ func (nc *StorageDriver) Unlock(ctx context.Context, ref *provider.Reference, lo
// ListStorageSpaces as defined in the storage.FS interface.
func (nc *StorageDriver) ListStorageSpaces(ctx context.Context, f []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) {
bodyStr, _ := json.Marshal(f)
_, respBody, err := nc.do(ctx, Action{"ListStorageSpaces", string(bodyStr)})
if err != nil {
return nil, err
}
// https://github.com/cs3org/go-cs3apis/blob/970eec3/cs3/storage/provider/v1beta1/resources.pb.go#L1341-L1366
var respMapArr []provider.StorageSpace
err = json.Unmarshal(respBody, &respMapArr)
if err != nil {
return nil, err
}
var spaces = make([]*provider.StorageSpace, len(respMapArr))
for i := 0; i < len(respMapArr); i++ {
spaces[i] = &respMapArr[i]
}
return spaces, err
return nil, errtypes.NotSupported("unimplemented")
}
// CreateStorageSpace creates a storage space.
func (nc *StorageDriver) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) {
bodyStr, _ := json.Marshal(req)
_, respBody, err := nc.do(ctx, Action{"CreateStorageSpace", string(bodyStr)})
if err != nil {
return nil, err
}
var respObj provider.CreateStorageSpaceResponse
err = json.Unmarshal(respBody, &respObj)
if err != nil {
return nil, err
}
return &respObj, nil
return nil, errtypes.NotSupported("unimplemented")
}
// UpdateStorageSpace updates a storage space.
func (nc *StorageDriver) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) {
bodyStr, _ := json.Marshal(req)
_, respBody, err := nc.do(ctx, Action{"UpdateStorageSpace", string(bodyStr)})
if err != nil {
return nil, err
}
var respObj provider.UpdateStorageSpaceResponse
err = json.Unmarshal(respBody, &respObj)
if err != nil {
return nil, err
}
return &respObj, nil
return nil, errtypes.NotSupported("unimplemented")
}

View File

@ -74,42 +74,42 @@ var responses = map[string]Response{
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/EmptyRecycle `: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/"},"mdKeys":null} EMPTY`: {404, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/"},"mdKeys":null} HOME`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateHome},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/"},"mdKeys":null} HOME`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateHome},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/newdir"},"mdKeys":null} EMPTY`: {404, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/newdir"},"mdKeys":null} HOME`: {404, ``, serverStateHome},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/newdir"},"mdKeys":null} SUBDIR`: {404, ``, serverStateSubdir},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/newdir"},"mdKeys":null} NEWDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/newdir","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateNewdir},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/newdir"},"mdKeys":null} SUBDIR-NEWDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/newdir","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateSubdirNewdir},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/newdir"},"mdKeys":null} NEWDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/newdir","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateNewdir},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/newdir"},"mdKeys":null} SUBDIR-NEWDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/newdir","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateSubdirNewdir},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/new_subdir"},"mdKeys":null}`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/new_subdir","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/new_subdir"},"mdKeys":null}`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/new_subdir","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} EMPTY`: {404, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} HOME`: {404, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} NEWDIR`: {404, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} RECYCLE`: {404, ``, serverStateRecycle},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} SUBDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} SUBDIR-NEWDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} METADATA`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"foo":"bar"}}}`, serverStateMetadata},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} SUBDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} SUBDIR-NEWDIR`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} METADATA`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"foo":"bar"}}}`, serverStateMetadata},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdirRestored"},"mdKeys":null} EMPTY`: {404, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdirRestored"},"mdKeys":null} RECYCLE`: {404, ``, serverStateRecycle},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdirRestored"},"mdKeys":null} SUBDIR`: {404, ``, serverStateSubdir},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdirRestored"},"mdKeys":null} FILE-RESTORED`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdirRestored","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateFileRestored},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} FILE-RESTORED`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdirRestored","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateFileRestored},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdirRestored"},"mdKeys":null} FILE-RESTORED`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdirRestored","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateFileRestored},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/subdir"},"mdKeys":null} FILE-RESTORED`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdirRestored","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateFileRestored},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/versionedFile"},"mdKeys":null} EMPTY`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/versionedFile","permission_set":{},"size":2,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/versionedFile"},"mdKeys":null} FILE-RESTORED`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/versionedFile","permission_set":{},"size":1,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateFileRestored},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/versionedFile"},"mdKeys":null} EMPTY`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/versionedFile","permissions": 0,"size":2,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetMD {"ref":{"path":"/versionedFile"},"mdKeys":null} FILE-RESTORED`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/versionedFile","permissions": 0,"size":1,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateFileRestored},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/GetPathByID {"storage_id":"00000000-0000-0000-0000-000000000000","opaque_id":"fileid-/some/path"} EMPTY`: {200, "/subdir", serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/InitiateUpload {"ref":{"path":"/file"},"uploadLength":0,"metadata":{}}`: {200, `{"simple": "yes","tus": "yes"}`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListFolder {"ref":{"path":"/"},"mdKeys":null}`: {200, `[{"opaque":{},"type":2,"id":{"opaque_id":"fileid-/subdir"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permission_set":{},"size":12345,"canonical_metadata":{},"owner":{"opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListFolder {"ref":{"path":"/"},"mdKeys":null}`: {200, `[{"opaque":{},"type":2,"id":{"opaque_id":"fileid-/subdir"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permissions": 0,"size":12345,"canonical_metadata":{},"owner":{"opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListFolder {"ref":{"path":"/Shares"},"mdKeys":null} EMPTY`: {404, ``, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListFolder {"ref":{"path":"/Shares"},"mdKeys":null} SUBDIR`: {404, ``, serverStateSubdir},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListFolder {"ref":{"path":"/Shares"},"mdKeys":null} REFERENCE`: {200, `[{"opaque":{},"type":2,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permission_set":{},"size":12345,"canonical_metadata":{},"owner":{"opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateReference},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListFolder {"ref":{"path":"/Shares"},"mdKeys":null} REFERENCE`: {200, `[{"opaque":{},"type":2,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/subdir","permissions": 0,"size":12345,"canonical_metadata":{},"owner":{"opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c"},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateReference},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListGrants {"path":"/subdir"} SUBDIR`: {200, `[]`, serverStateEmpty},
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/ListGrants {"path":"/subdir"} GRANT-ADDED`: {200, `[{"grantee":{"type":1,"Id":{"UserId":{"idp":"some-idp","opaque_id":"some-opaque-id","type":1}}},"permissions":{"add_grant":true,"create_container":true,"delete":false,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}}]`, serverStateEmpty},
@ -140,25 +140,23 @@ var responses = map[string]Response{
`POST /apps/sciencemesh/~f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c/api/storage/UpdateGrant {"ref":{"path":"/subdir"},"g":{"grantee":{"type":1,"Id":{"UserId":{"opaque_id":"4c510ada-c86b-4815-8820-42cdf82c3d51"}}},"permissions":{"delete":true,"move":true,"stat":true}}}`: {200, ``, serverStateGrantUpdated},
`POST /apps/sciencemesh/~tester/api/storage/GetHome `: {200, `yes we are`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/storage/CreateHome `: {201, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/CreateDir {"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"}`: {201, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/Delete {"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/Move {"oldRef":{"resource_id":{"storage_id":"storage-id-1","opaque_id":"opaque-id-1"},"path":"/some/old/path"},"newRef":{"resource_id":{"storage_id":"storage-id-2","opaque_id":"opaque-id-2"},"path":"/some/new/path"}}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/GetMD {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"},"mdKeys":["val1","val2","val3"]}`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/some/path","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/ListFolder {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some"},"mdKeys":["val1","val2","val3"]}`: {200, `[{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/some/path","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateEmpty},
// `POST /apps/sciencemesh/~tester/api/storage/ListFolder {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some"},"mdKeys":["val1","val2","val3"]}`: {200, `[{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/path","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/InitiateUpload {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"},"uploadLength":12345,"metadata":{"key1":"val1","key2":"val2","key3":"val3"}}`: {200, `{ "not":"sure", "what": "should be", "returned": "here" }`, serverStateEmpty},
`PUT /apps/sciencemesh/~tester/api/storage/Upload/home/some/file/path.txt shiny!`: {200, ``, serverStateEmpty},
`GET /apps/sciencemesh/~tester/api/storage/Download/some/file/path.txt `: {200, `the contents of the file`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/ListRevisions {"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"}`: {200, `[{"opaque":{"map":{"some":{"value":"ZGF0YQ=="}}},"key":"version-12","size":12345,"mtime":1234567890,"etag":"deadb00f"},{"opaque":{"map":{"different":{"value":"c3R1ZmY="}}},"key":"asdf","size":12345,"mtime":1234567890,"etag":"deadbeef"}]`, serverStateEmpty},
`GET /apps/sciencemesh/~tester/api/storage/DownloadRevision/some%2Frevision/some/file/path.txt `: {200, `the contents of that revision`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/RestoreRevision {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"key":"asdf"}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/ListRecycle {"key":"asdf","path":"/some/file.txt"}`: {200, `[{"opaque":{},"key":"some-deleted-version","ref":{"resource_id":{},"path":"/some/file.txt"},"size":12345,"deletion_time":{"seconds":1234567890}}]`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/RestoreRecycleItem {"key":"asdf","path":"original/location/when/deleted.txt","restoreRef":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"}}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/PurgeRecycleItem {"key":"asdf","path":"original/location/when/deleted.txt"}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/EmptyRecycle `: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/GetPathByID {"storage_id":"storage-id","opaque_id":"opaque-id"}`: {200, `the/path/for/that/id.txt`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/GetMD {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"},"mdKeys":["val1","val2","val3"]}`: {200, `{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/some/path","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/ListFolder {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some"},"mdKeys":["val1","val2","val3"]}`: {200, `[{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/some/path","permissions": 0,"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}}]`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/InitiateUpload {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"},"uploadLength":12345,"metadata":{"key1":"val1","key2":"val2","key3":"val3"}}`: {200, `{ "not":"sure", "what": "should be", "returned": "here" }`, serverStateEmpty},
`PUT /apps/sciencemesh/~tester/api/storage/Upload/home/some/file/path.txt shiny!`: {200, ``, serverStateEmpty},
`GET /apps/sciencemesh/~tester/api/storage/Download/some/file/path.txt `: {200, `the contents of the file`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/ListRevisions {"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"/some/path"}`: {200, `[{"opaque":{"map":{"some":{"value":"ZGF0YQ=="}}},"key":"version-12","size":12345,"mtime":1234567890,"etag":"deadb00f"},{"opaque":{"map":{"different":{"value":"c3R1ZmY="}}},"key":"asdf","size":12345,"mtime":1234567890,"etag":"deadbeef"}]`, serverStateEmpty},
`GET /apps/sciencemesh/~tester/api/storage/DownloadRevision/some/revision/some/file/path.txt `: {200, `the contents of that revision`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/RestoreRevision {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"key":"asdf"}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/ListRecycle {"key":"asdf","path":"/some/file.txt"}`: {200, `[{"opaque":{},"key":"some-deleted-version","ref":{"resource_id":{},"path":"/some/file.txt"},"size":12345,"deletion_time":{"seconds":1234567890}}]`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/RestoreRecycleItem {"key":"asdf","path":"original/location/when/deleted.txt","restoreRef":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"}}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/PurgeRecycleItem {"key":"asdf","path":"original/location/when/deleted.txt"}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/EmptyRecycle `: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/GetPathByID {"storage_id":"storage-id","opaque_id":"opaque-id"}`: {200, `the/path/for/that/id.txt`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/AddGrant {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"g":{"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}}}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/DenyGrant {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"g":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/RemoveGrant {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"g":{"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}}}`: {200, ``, serverStateEmpty},
@ -166,7 +164,6 @@ var responses = map[string]Response{
`POST /apps/sciencemesh/~tester/api/storage/ListGrants {"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"}`: {200, `[{"grantee":{"type":1,"Id":{"UserId":{"idp":"some-idp","opaque_id":"some-opaque-id","type":1}}},"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}}]`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/GetQuota `: {200, `{"totalBytes":456,"usedBytes":123}`, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/CreateReference {"path":"some/file/path.txt","url":"http://bing.com/search?q=dotnet"}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/Shutdown `: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/SetArbitraryMetadata {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"md":{"metadata":{"arbi":"trary","meta":"data"}}}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/UnsetArbitraryMetadata {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"keys":["arbi"]}`: {200, ``, serverStateEmpty},
`POST /apps/sciencemesh/~tester/api/storage/ListStorageSpaces [{"type":3,"Term":{"Owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},{"type":2,"Term":{"Id":{"opaque_id":"opaque-id"}}},{"type":4,"Term":{"SpaceType":"home"}}]`: {200, ` [{"opaque":{"map":{"bar":{"value":"c2FtYQ=="},"foo":{"value":"c2FtYQ=="}}},"id":{"opaque_id":"some-opaque-storage-space-id"},"owner":{"id":{"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}},"root":{"storage_id":"some-storage-ud","opaque_id":"some-opaque-root-id"},"name":"My Storage Space","quota":{"quota_max_bytes":456,"quota_max_files":123},"space_type":"home","mtime":{"seconds":1234567890}}]`, serverStateEmpty},
@ -191,15 +188,12 @@ func GetNextcloudServerMock(called *[]string) http.Handler {
}
if (response == Response{}) {
fmt.Printf("server mock cannot serve '%s %s %s %s'\n", r.Method, r.URL, buf.String(), serverState)
response = Response{500, fmt.Sprintf("response not defined! %s", key), serverStateEmpty}
}
serverState = responses[key].newServerState
if serverState == `` {
serverState = serverStateError
response = Response{500, fmt.Sprintf("response not defined! %s", key), serverStateError}
}
serverState = response.newServerState
w.WriteHeader(response.code)
// w.Header().Set("Etag", "mocker-etag")
_, err = w.Write([]byte(responses[key].body))
_, err = w.Write([]byte(response.body))
if err != nil {
panic(err)
}

View File

@ -29,6 +29,7 @@ import (
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/internal/http/services/owncloud/ocs/conversions"
"github.com/cs3org/reva/pkg/auth/scope"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/storage/fs/nextcloud"
@ -120,18 +121,6 @@ var _ = Describe("Nextcloud", func() {
})
})
// GetHome(ctx context.Context) (string, error)
Describe("GetHome", func() {
It("calls the GetHome endpoint", func() {
nc, called, teardown := setUpNextcloudServer()
defer teardown()
home, err := nc.GetHome(ctx)
Expect(home).To(Equal("yes we are"))
Expect(err).ToNot(HaveOccurred())
checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/GetHome `)
})
})
// CreateHome(ctx context.Context) error
Describe("CreateHome", func() {
It("calls the CreateHome endpoint", func() {
@ -224,13 +213,8 @@ var _ = Describe("Nextcloud", func() {
result, err := nc.GetMD(ctx, ref, mdKeys)
Expect(err).ToNot(HaveOccurred())
Expect(*result).To(Equal(provider.ResourceInfo{
Opaque: &types.Opaque{
Map: nil,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Opaque: nil,
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Id: &provider.ResourceId{
StorageId: "",
OpaqueId: "fileid-/some/path",
@ -254,46 +238,17 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
Path: "/some/path",
PermissionSet: &provider.ResourcePermissions{
AddGrant: false,
CreateContainer: false,
Delete: false,
GetPath: false,
GetQuota: false,
InitiateFileDownload: false,
InitiateFileUpload: false,
ListGrants: false,
ListContainer: false,
ListFileVersions: false,
ListRecycle: false,
Move: false,
RemoveGrant: false,
PurgeRecycle: false,
RestoreFileVersion: false,
RestoreRecycleItem: false,
Stat: false,
UpdateGrant: false,
DenyGrant: false,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
Size: 12345,
Owner: nil,
Target: "",
CanonicalMetadata: &provider.CanonicalMetadata{
Target: nil,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
ArbitraryMetadata: &provider.ArbitraryMetadata{
Metadata: map[string]string{"some": "arbi", "trary": "meta", "da": "ta"},
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
Path: "/some/path",
PermissionSet: conversions.RoleFromOCSPermissions(conversions.Permissions(0)).CS3ResourcePermissions(),
Size: 12345,
Owner: &userpb.UserId{
Idp: "",
OpaqueId: "",
Type: 1,
},
Target: "",
CanonicalMetadata: nil,
ArbitraryMetadata: nil,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
@ -320,13 +275,8 @@ var _ = Describe("Nextcloud", func() {
Expect(err).NotTo(HaveOccurred())
Expect(len(results)).To(Equal(1))
Expect(*results[0]).To(Equal(provider.ResourceInfo{
Opaque: &types.Opaque{
Map: nil,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Opaque: nil,
Type: provider.ResourceType_RESOURCE_TYPE_FILE,
Id: &provider.ResourceId{
StorageId: "",
OpaqueId: "fileid-/some/path",
@ -350,46 +300,17 @@ var _ = Describe("Nextcloud", func() {
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
Path: "/some/path",
PermissionSet: &provider.ResourcePermissions{
AddGrant: false,
CreateContainer: false,
Delete: false,
GetPath: false,
GetQuota: false,
InitiateFileDownload: false,
InitiateFileUpload: false,
ListGrants: false,
ListContainer: false,
ListFileVersions: false,
ListRecycle: false,
Move: false,
RemoveGrant: false,
PurgeRecycle: false,
RestoreFileVersion: false,
RestoreRecycleItem: false,
Stat: false,
UpdateGrant: false,
DenyGrant: false,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
Size: 12345,
Owner: nil,
Target: "",
CanonicalMetadata: &provider.CanonicalMetadata{
Target: nil,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
},
ArbitraryMetadata: &provider.ArbitraryMetadata{
Metadata: map[string]string{"some": "arbi", "trary": "meta", "da": "ta"},
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
Path: "/some/path",
PermissionSet: conversions.RoleFromOCSPermissions(conversions.Permissions(0)).CS3ResourcePermissions(),
Size: 12345,
Owner: &userpb.UserId{
Idp: "",
OpaqueId: "",
Type: 1,
},
Target: "",
CanonicalMetadata: nil,
ArbitraryMetadata: nil,
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
@ -541,7 +462,7 @@ var _ = Describe("Nextcloud", func() {
key := "some/revision"
reader, err := nc.DownloadRevision(ctx, ref, key)
Expect(err).ToNot(HaveOccurred())
checkCalled(called, `GET /apps/sciencemesh/~tester/api/storage/DownloadRevision/some%2Frevision/some/file/path.txt `)
checkCalled(called, `GET /apps/sciencemesh/~tester/api/storage/DownloadRevision/some/revision/some/file/path.txt `)
defer reader.Close()
body, err := io.ReadAll(reader)
Expect(err).ToNot(HaveOccurred())
@ -714,32 +635,32 @@ var _ = Describe("Nextcloud", func() {
})
// DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error
Describe("DenyGrant", func() {
It("calls the DenyGrant endpoint", func() {
nc, called, teardown := setUpNextcloudServer()
defer teardown()
ref := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: "storage-id",
OpaqueId: "opaque-id",
},
Path: "some/file/path.txt",
}
// https://github.com/cs3org/go-cs3apis/blob/970eec3/cs3/storage/provider/v1beta1/resources.pb.go#L896-L915
grantee := &provider.Grantee{
Id: &provider.Grantee_UserId{
UserId: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
}
err := nc.DenyGrant(ctx, ref, grantee)
Expect(err).ToNot(HaveOccurred())
checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/DenyGrant {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"g":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}}`)
})
})
// Describe("DenyGrant", func() {
// It("calls the DenyGrant endpoint", func() {
// nc, called, teardown := setUpNextcloudServer()
// defer teardown()
// ref := &provider.Reference{
// ResourceId: &provider.ResourceId{
// StorageId: "storage-id",
// OpaqueId: "opaque-id",
// },
// Path: "some/file/path.txt",
// }
// // https://github.com/cs3org/go-cs3apis/blob/970eec3/cs3/storage/provider/v1beta1/resources.pb.go#L896-L915
// grantee := &provider.Grantee{
// Id: &provider.Grantee_UserId{
// UserId: &userpb.UserId{
// Idp: "0.0.0.0:19000",
// OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
// Type: userpb.UserType_USER_TYPE_PRIMARY,
// },
// },
// }
// err := nc.DenyGrant(ctx, ref, grantee)
// Expect(err).ToNot(HaveOccurred())
// checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/DenyGrant {"ref":{"resource_id":{"storage_id":"storage-id","opaque_id":"opaque-id"},"path":"some/file/path.txt"},"g":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}}}`)
// })
// })
// RemoveGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error
Describe("RemoveGrant", func() {
@ -894,17 +815,6 @@ var _ = Describe("Nextcloud", func() {
})
})
// Shutdown(ctx context.Context) error
Describe("Shutdown", func() {
It("calls the Shutdown endpoint", func() {
nc, called, teardown := setUpNextcloudServer()
defer teardown()
err := nc.Shutdown(ctx)
Expect(err).ToNot(HaveOccurred())
checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/Shutdown `)
})
})
// SetArbitraryMetadata(ctx context.Context, ref *provider.Reference, md *provider.ArbitraryMetadata) error
Describe("SetArbitraryMetadata", func() {
It("calls the SetArbitraryMetadata endpoint", func() {
@ -948,136 +858,136 @@ var _ = Describe("Nextcloud", func() {
})
})
// ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error)
Describe("ListStorageSpaces", func() {
It("calls the ListStorageSpaces endpoint", func() {
nc, called, teardown := setUpNextcloudServer()
defer teardown()
filter1 := &provider.ListStorageSpacesRequest_Filter{
Type: provider.ListStorageSpacesRequest_Filter_TYPE_OWNER,
Term: &provider.ListStorageSpacesRequest_Filter_Owner{
Owner: &userpb.UserId{
Idp: "0.0.0.0:19000",
OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
}
filter2 := &provider.ListStorageSpacesRequest_Filter{
Type: provider.ListStorageSpacesRequest_Filter_TYPE_ID,
Term: &provider.ListStorageSpacesRequest_Filter_Id{
Id: &provider.StorageSpaceId{
OpaqueId: "opaque-id",
},
},
}
filter3 := &provider.ListStorageSpacesRequest_Filter{
Type: provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE,
Term: &provider.ListStorageSpacesRequest_Filter_SpaceType{
SpaceType: string("home"),
},
}
filters := []*provider.ListStorageSpacesRequest_Filter{filter1, filter2, filter3}
spaces, err := nc.ListStorageSpaces(ctx, filters)
Expect(err).ToNot(HaveOccurred())
Expect(len(spaces)).To(Equal(1))
// https://github.com/cs3org/go-cs3apis/blob/970eec3/cs3/storage/provider/v1beta1/resources.pb.go#L1341-L1366
Expect(*spaces[0]).To(Equal(provider.StorageSpace{
Opaque: &types.Opaque{
Map: map[string](*types.OpaqueEntry){
"foo": &types.OpaqueEntry{Value: []byte("sama")},
"bar": &types.OpaqueEntry{Value: []byte("sama")},
},
},
Id: &provider.StorageSpaceId{OpaqueId: "some-opaque-storage-space-id"},
Owner: &userpb.User{
Id: &userpb.UserId{
Idp: "some-idp",
OpaqueId: "some-opaque-user-id",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
Root: &provider.ResourceId{
StorageId: "some-storage-ud",
OpaqueId: "some-opaque-root-id",
},
Name: "My Storage Space",
Quota: &provider.Quota{
QuotaMaxBytes: uint64(456),
QuotaMaxFiles: uint64(123),
},
SpaceType: "home",
Mtime: &types.Timestamp{
Seconds: uint64(1234567890),
},
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/ListStorageSpaces [{"type":3,"Term":{"Owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},{"type":2,"Term":{"Id":{"opaque_id":"opaque-id"}}},{"type":4,"Term":{"SpaceType":"home"}}]`)
})
})
// // ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error)
// Describe("ListStorageSpaces", func() {
// It("calls the ListStorageSpaces endpoint", func() {
// nc, called, teardown := setUpNextcloudServer()
// defer teardown()
// filter1 := &provider.ListStorageSpacesRequest_Filter{
// Type: provider.ListStorageSpacesRequest_Filter_TYPE_OWNER,
// Term: &provider.ListStorageSpacesRequest_Filter_Owner{
// Owner: &userpb.UserId{
// Idp: "0.0.0.0:19000",
// OpaqueId: "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
// Type: userpb.UserType_USER_TYPE_PRIMARY,
// },
// },
// }
// filter2 := &provider.ListStorageSpacesRequest_Filter{
// Type: provider.ListStorageSpacesRequest_Filter_TYPE_ID,
// Term: &provider.ListStorageSpacesRequest_Filter_Id{
// Id: &provider.StorageSpaceId{
// OpaqueId: "opaque-id",
// },
// },
// }
// filter3 := &provider.ListStorageSpacesRequest_Filter{
// Type: provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE,
// Term: &provider.ListStorageSpacesRequest_Filter_SpaceType{
// SpaceType: string("home"),
// },
// }
// filters := []*provider.ListStorageSpacesRequest_Filter{filter1, filter2, filter3}
// spaces, err := nc.ListStorageSpaces(ctx, filters)
// Expect(err).ToNot(HaveOccurred())
// Expect(len(spaces)).To(Equal(1))
// // https://github.com/cs3org/go-cs3apis/blob/970eec3/cs3/storage/provider/v1beta1/resources.pb.go#L1341-L1366
// Expect(*spaces[0]).To(Equal(provider.StorageSpace{
// Opaque: &types.Opaque{
// Map: map[string](*types.OpaqueEntry){
// "foo": &types.OpaqueEntry{Value: []byte("sama")},
// "bar": &types.OpaqueEntry{Value: []byte("sama")},
// },
// },
// Id: &provider.StorageSpaceId{OpaqueId: "some-opaque-storage-space-id"},
// Owner: &userpb.User{
// Id: &userpb.UserId{
// Idp: "some-idp",
// OpaqueId: "some-opaque-user-id",
// Type: userpb.UserType_USER_TYPE_PRIMARY,
// },
// },
// Root: &provider.ResourceId{
// StorageId: "some-storage-ud",
// OpaqueId: "some-opaque-root-id",
// },
// Name: "My Storage Space",
// Quota: &provider.Quota{
// QuotaMaxBytes: uint64(456),
// QuotaMaxFiles: uint64(123),
// },
// SpaceType: "home",
// Mtime: &types.Timestamp{
// Seconds: uint64(1234567890),
// },
// }))
// checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/ListStorageSpaces [{"type":3,"Term":{"Owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},{"type":2,"Term":{"Id":{"opaque_id":"opaque-id"}}},{"type":4,"Term":{"SpaceType":"home"}}]`)
// })
// })
// CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error)
Describe("CreateStorageSpace", func() {
It("calls the CreateStorageSpace endpoint", func() {
nc, called, teardown := setUpNextcloudServer()
defer teardown()
// https://github.com/cs3org/go-cs3apis/blob/03e4a408c1f3b2882916cf3fad4c71081a20711d/cs3/storage/provider/v1beta1/provider_api.pb.go#L3176-L3192
result, err := nc.CreateStorageSpace(ctx, &provider.CreateStorageSpaceRequest{
Opaque: &types.Opaque{
Map: map[string](*types.OpaqueEntry){
"foo": &types.OpaqueEntry{Value: []byte("sama")},
"bar": &types.OpaqueEntry{Value: []byte("sama")},
},
},
Owner: &userpb.User{
Id: &userpb.UserId{
Idp: "some-idp",
OpaqueId: "some-opaque-user-id",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
Name: "My Storage Space",
Quota: &provider.Quota{
QuotaMaxBytes: uint64(456),
QuotaMaxFiles: uint64(123),
},
Type: "home",
})
Expect(err).ToNot(HaveOccurred())
Expect(*result).To(Equal(provider.CreateStorageSpaceResponse{
Opaque: nil,
Status: nil,
StorageSpace: &provider.StorageSpace{
Opaque: &types.Opaque{
Map: map[string](*types.OpaqueEntry){
"bar": &types.OpaqueEntry{Value: []byte("sama")},
"foo": &types.OpaqueEntry{Value: []byte("sama")},
},
},
Id: &provider.StorageSpaceId{OpaqueId: "some-opaque-storage-space-id"},
Owner: &userpb.User{
Id: &userpb.UserId{
Idp: "some-idp",
OpaqueId: "some-opaque-user-id",
Type: userpb.UserType_USER_TYPE_PRIMARY,
},
},
Root: &provider.ResourceId{
StorageId: "some-storage-ud",
OpaqueId: "some-opaque-root-id",
},
Name: "My Storage Space",
Quota: &provider.Quota{
QuotaMaxBytes: uint64(456),
QuotaMaxFiles: uint64(123),
},
SpaceType: "home",
Mtime: &types.Timestamp{
Seconds: uint64(1234567890),
},
},
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/CreateStorageSpace {"opaque":{"map":{"bar":{"value":"c2FtYQ=="},"foo":{"value":"c2FtYQ=="}}},"owner":{"id":{"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}},"type":"home","name":"My Storage Space","quota":{"quota_max_bytes":456,"quota_max_files":123}}`)
})
})
// // CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error)
// Describe("CreateStorageSpace", func() {
// It("calls the CreateStorageSpace endpoint", func() {
// nc, called, teardown := setUpNextcloudServer()
// defer teardown()
// // https://github.com/cs3org/go-cs3apis/blob/03e4a408c1f3b2882916cf3fad4c71081a20711d/cs3/storage/provider/v1beta1/provider_api.pb.go#L3176-L3192
// result, err := nc.CreateStorageSpace(ctx, &provider.CreateStorageSpaceRequest{
// Opaque: &types.Opaque{
// Map: map[string](*types.OpaqueEntry){
// "foo": &types.OpaqueEntry{Value: []byte("sama")},
// "bar": &types.OpaqueEntry{Value: []byte("sama")},
// },
// },
// Owner: &userpb.User{
// Id: &userpb.UserId{
// Idp: "some-idp",
// OpaqueId: "some-opaque-user-id",
// Type: userpb.UserType_USER_TYPE_PRIMARY,
// },
// },
// Name: "My Storage Space",
// Quota: &provider.Quota{
// QuotaMaxBytes: uint64(456),
// QuotaMaxFiles: uint64(123),
// },
// Type: "home",
// })
// Expect(err).ToNot(HaveOccurred())
// Expect(*result).To(Equal(provider.CreateStorageSpaceResponse{
// Opaque: nil,
// Status: nil,
// StorageSpace: &provider.StorageSpace{
// Opaque: &types.Opaque{
// Map: map[string](*types.OpaqueEntry){
// "bar": &types.OpaqueEntry{Value: []byte("sama")},
// "foo": &types.OpaqueEntry{Value: []byte("sama")},
// },
// },
// Id: &provider.StorageSpaceId{OpaqueId: "some-opaque-storage-space-id"},
// Owner: &userpb.User{
// Id: &userpb.UserId{
// Idp: "some-idp",
// OpaqueId: "some-opaque-user-id",
// Type: userpb.UserType_USER_TYPE_PRIMARY,
// },
// },
// Root: &provider.ResourceId{
// StorageId: "some-storage-ud",
// OpaqueId: "some-opaque-root-id",
// },
// Name: "My Storage Space",
// Quota: &provider.Quota{
// QuotaMaxBytes: uint64(456),
// QuotaMaxFiles: uint64(123),
// },
// SpaceType: "home",
// Mtime: &types.Timestamp{
// Seconds: uint64(1234567890),
// },
// },
// }))
// checkCalled(called, `POST /apps/sciencemesh/~tester/api/storage/CreateStorageSpace {"opaque":{"map":{"bar":{"value":"c2FtYQ=="},"foo":{"value":"c2FtYQ=="}}},"owner":{"id":{"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}},"type":"home","name":"My Storage Space","quota":{"quota_max_bytes":456,"quota_max_files":123}}`)
// })
// })
})

View File

@ -28,13 +28,13 @@ import (
"strings"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
ctxpkg "github.com/cs3org/reva/pkg/ctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/user"
"github.com/cs3org/reva/pkg/user/manager/registry"
"github.com/cs3org/reva/pkg/utils/cfg"
"github.com/pkg/errors"
// "github.com/cs3org/reva/pkg/errtypes".
)
func init() {
@ -106,29 +106,30 @@ func (um *Manager) SetHTTPClient(c *http.Client) {
func getUser(ctx context.Context) (*userpb.User, error) {
u, ok := ctxpkg.ContextGetUser(ctx)
if !ok {
err := errors.Wrap(errtypes.UserRequired(""), "nextcloud storage driver: error getting user from ctx")
err := errors.Wrap(errtypes.UserRequired(""), "nextcloud user manager: error getting user from ctx")
return nil, err
}
return u, nil
}
func (um *Manager) do(ctx context.Context, a Action, username string) (int, []byte, error) {
log := appctx.GetLogger(ctx)
url := um.endPoint + "~" + username + "/api/user/" + a.verb
log.Info().Msgf("um.do req %s %s", url, a.argS)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(a.argS))
if err != nil {
panic(err)
return 0, nil, err
}
req.Header.Set("X-Reva-Secret", um.sharedSecret)
req.Header.Set("Content-Type", "application/json")
fmt.Println(url)
resp, err := um.client.Do(req)
if err != nil {
panic(err)
return 0, nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
log.Info().Msgf("um.do res %s %s", url, string(body))
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
return 0, nil, fmt.Errorf("Unexpected response code from EFSS API: " + strconv.Itoa(resp.StatusCode))
}
@ -161,17 +162,16 @@ func (um *Manager) GetUserByClaim(ctx context.Context, claim, value string, skip
Claim string `json:"claim"`
Value string `json:"value"`
}
log := appctx.GetLogger(ctx)
log.Debug().Msgf("NC-based user manager GetUserByClaim - claim '%s', value '%s'", claim, value)
bodyObj := &paramsObj{
Claim: claim,
Value: value,
}
user, err := getUser(ctx)
if err != nil {
return nil, err
}
bodyStr, _ := json.Marshal(bodyObj)
_, respBody, err := um.do(ctx, Action{"GetUserByClaim", string(bodyStr)}, user.Username)
_, respBody, err := um.do(ctx, Action{"GetUserByClaim", string(bodyStr)}, value)
if err != nil {
return nil, err
}

View File

@ -44,7 +44,7 @@ var serverState = serverStateEmpty
var responses = map[string]Response{
`POST /apps/sciencemesh/~unauthenticated/api/user/GetUser {"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}`: {200, `{"id":{"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/user/GetUserByClaim {"claim":"claim-string","value":"value-string"}`: {200, `{"id":{"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/user/GetUserByClaim {"claim":"username","value":"tester"}`: {200, `{"id":{"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/user/GetUserGroups {"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}`: {200, `["wine-lovers"]`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/user/FindUsers some-query`: {200, `[{"id":{"idp":"some-idp","opaque_id":"some-opaque-user-id","type":1}}]`, serverStateHome},
}

View File

@ -156,7 +156,7 @@ var _ = Describe("Nextcloud", func() {
um, called, teardown := setUpNextcloudServer()
defer teardown()
user, err := um.GetUserByClaim(ctx, "claim-string", "value-string", false)
user, err := um.GetUserByClaim(ctx, "username", "tester", false)
Expect(err).ToNot(HaveOccurred())
Expect(user).To(Equal(&userpb.User{
Id: &userpb.UserId{
@ -173,7 +173,7 @@ var _ = Describe("Nextcloud", func() {
UidNumber: 0,
GidNumber: 0,
}))
checkCalled(called, `POST /apps/sciencemesh/~tester/api/user/GetUserByClaim {"claim":"claim-string","value":"value-string"}`)
checkCalled(called, `POST /apps/sciencemesh/~tester/api/user/GetUserByClaim {"claim":"username","value":"tester"}`)
})
})

View File

@ -428,40 +428,42 @@ var _ = Describe("storage providers", func() {
})
}
assertMetadata := func() {
It("sets and unsets metadata", func() {
statRes, err := serviceClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
Expect(err).ToNot(HaveOccurred())
Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(BeEmpty())
/* FIXME: related to https://github.com/cs3org/reva/issues/4158
assertMetadata := func() {
It("sets and unsets metadata", func() {
statRes, err := serviceClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
Expect(err).ToNot(HaveOccurred())
Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(BeEmpty())
By("setting arbitrary metadata")
samRes, err := serviceClient.SetArbitraryMetadata(ctx, &storagep.SetArbitraryMetadataRequest{
Ref: subdirRef,
ArbitraryMetadata: &storagep.ArbitraryMetadata{Metadata: map[string]string{"foo": "bar"}},
By("setting arbitrary metadata")
samRes, err := serviceClient.SetArbitraryMetadata(ctx, &storagep.SetArbitraryMetadataRequest{
Ref: subdirRef,
ArbitraryMetadata: &storagep.ArbitraryMetadata{Metadata: map[string]string{"foo": "bar"}},
})
Expect(err).ToNot(HaveOccurred())
Expect(samRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
statRes, err = serviceClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
Expect(err).ToNot(HaveOccurred())
Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(Equal("bar"))
By("unsetting arbitrary metadata")
uamRes, err := serviceClient.UnsetArbitraryMetadata(ctx, &storagep.UnsetArbitraryMetadataRequest{
Ref: subdirRef,
ArbitraryMetadataKeys: []string{"foo"},
})
Expect(err).ToNot(HaveOccurred())
Expect(uamRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
statRes, err = serviceClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
Expect(err).ToNot(HaveOccurred())
Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(BeEmpty())
})
Expect(err).ToNot(HaveOccurred())
Expect(samRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
statRes, err = serviceClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
Expect(err).ToNot(HaveOccurred())
Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(Equal("bar"))
By("unsetting arbitrary metadata")
uamRes, err := serviceClient.UnsetArbitraryMetadata(ctx, &storagep.UnsetArbitraryMetadataRequest{
Ref: subdirRef,
ArbitraryMetadataKeys: []string{"foo"},
})
Expect(err).ToNot(HaveOccurred())
Expect(uamRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
statRes, err = serviceClient.Stat(ctx, &storagep.StatRequest{Ref: subdirRef})
Expect(err).ToNot(HaveOccurred())
Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(statRes.Info.ArbitraryMetadata.Metadata["foo"]).To(BeEmpty())
})
}
}
*/
Describe("nextcloud", func() {
BeforeEach(func() {
@ -493,7 +495,7 @@ var _ = Describe("storage providers", func() {
assertDownloads()
assertRecycle()
assertReferences()
assertMetadata()
// assertMetadata()
})
Context("with an existing file /versioned_file", func() {
@ -551,7 +553,7 @@ var _ = Describe("storage providers", func() {
assertDownloads()
assertRecycle()
assertReferences()
assertMetadata()
// assertMetadata()
})
Context("with an existing file /versioned_file", func() {
@ -617,7 +619,7 @@ var _ = Describe("storage providers", func() {
assertDownloads()
assertRecycle()
assertReferences()
assertMetadata()
// assertMetadata()
})
Context("with an existing file /versioned_file", func() {

View File

@ -0,0 +1,62 @@
## ScienceMesh Development Setup
These scripts will create a Docker testnet which simulates the [ScienceMesh](https://sciencemesh.io).
It is useful for all kinds of ScienceMesh-related development and (manual) testing scenarios.
Prerequisites: bash, git, Docker.
```
git clone https://github.com/cs3org/reva
cd reva
cd examples/sciencemesh
./init-sciencemesh.sh # This will prepare the Nextcloud and ownCloud-10 images
./init-reva.sh # This will build reva and revad in the current repo and handle a few other prerequisites
./nrro.sh
./einstein.sh nextcloud1 # for owncloud1 / owncloud2, make sure to log in via the OC-10 GUI once before trying to access through reva-cli!
./maria2.sh
./clean.sh # Careful! This will kill and remove all your Docker containers on the current host system! Also unrelated ones if present.
./orro.sh
```
## Reva-to-reva
To initialize your development environment and build reva on the host, do:
```
./init-reva.sh # This will build reva and revad in the current repo and handle a few other prerequisites
# passing sleep as the main container command will allow us
# to run revad interactively later:
REVA_CMD="sleep 30000" ./scripts/testing-reva.sh
```
### Running the ocmd tutorial
After you've started the Docker testnet with container as above, you do:
* `docker exec -it revad1.docker bash` and then:
```
cd /etc/revad/ocmd
/reva/cmd/revad/revad -dev-dir server-1
```
* `docker exec -it revad2.docker bash` and then:
```
cd /etc/revad/ocmd
/reva/cmd/revad/revad -dev-dir server-2
```
* `docker exec -it revad1.docker bash` again for `/reva/cmd/reva/reva -insecure -host localhost:19000` etc.
* `docker exec -it revad2.docker bash` again for `/reva/cmd/reva/reva -insecure -host localhost:17000` etc. (notice the port number!)
* follow the rest of https://reva.link/docs/tutorials/share-tutorial/
### Running the datatx tutorial
After you've started the Docker testnet with container as above, you do:
* `docker exec -it revad1.docker bash` and then:
```
cd /etc/revad/datatx
/reva/cmd/revad/revad -dev-dir server-1
```
* `docker exec -it revad2.docker bash` and then:
```
cd /etc/revad/datatx
/reva/cmd/revad/revad -dev-dir server-2
```
* `docker exec -it revad1.docker bash` again for `/reva/cmd/reva/reva -insecure -host localhost:19000` etc.
* `docker exec -it revad2.docker bash` again for `/reva/cmd/reva/reva -insecure -host localhost:17000` etc. (notice the port number!)
* get einstein to generate an invite, and marie to accept it, following the usual way as described in https://reva.link/docs/tutorials/share-tutorial/#4-invitation-workflow
* follow the rest of https://reva.link/docs/tutorials/datatx-tutorial/#3-create-a-datatx-protocol-type-ocm-share

View File

@ -0,0 +1,9 @@
#!/bin/bash
set -e
git config --global --add safe.directory /reva
# go mod tidy
go mod vendor
make revad
make reva

10
tests/sciencemesh/clean.sh Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e
running=$(docker ps -q)
([ -z "$running" ] && echo "no running containers!") || docker kill $running
existing=$(docker ps -qa)
([ -z "$existing" ] && echo "no existing containers!") || docker rm $existing
docker network remove testnet || true
docker network create testnet

3
tests/sciencemesh/einstein.sh Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
docker exec -it "reva${1}.docker" /reva/cmd/reva/reva -insecure -host localhost:19000

18
tests/sciencemesh/init-reva.sh Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -e
ENV_ROOT=$(pwd)
export ENV_ROOT=${ENV_ROOT}
[ ! -d "./scripts" ] && echo "Directory ./scripts DOES NOT exist inside $ENV_ROOT, are you running this from the repo root?" && exit 1
docker run --rm -it \
-v "${ENV_ROOT}/../..:/reva" \
-v "${ENV_ROOT}/build-reva.sh:/build-reva.sh" \
--workdir /reva \
--entrypoint /bin/bash \
pondersource/dev-stock-revad \
/build-reva.sh
docker network inspect testnet >/dev/null 2>&1 || docker network create testnet
[ ! -d "temp" ] && mkdir --parents temp

View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -e
# repositories and branches.
REPO_NEXTCLOUD_APP=https://github.com/sciencemesh/nc-sciencemesh
BRANCH_NEXTCLOUD_APP=nextcloud
REPO_OWNCLOUD_APP=https://github.com/sciencemesh/nc-sciencemesh
BRANCH_OWNCLOUD_APP=owncloud
# Nextcloud Sciencemesh source code.
[ ! -d "nextcloud-sciencemesh" ] && \
git clone \
--branch ${BRANCH_NEXTCLOUD_APP} \
${REPO_NEXTCLOUD_APP} \
nextcloud-sciencemesh \
&& \
docker run -it \
-v "$(pwd)/nextcloud-sciencemesh:/var/www/html/apps/sciencemesh" \
--workdir /var/www/html/apps/sciencemesh \
pondersource/dev-stock-nextcloud-sciencemesh \
make composer
# ownCloud Sciencemesh source code.
[ ! -d "owncloud-sciencemesh" ] && \
git clone \
--branch ${BRANCH_OWNCLOUD_APP} \
${REPO_OWNCLOUD_APP} \
owncloud-sciencemesh \
&& \
docker run -it \
-v "$(pwd)/owncloud-sciencemesh:/var/www/html/apps/sciencemesh" \
--workdir /var/www/html/apps/sciencemesh \
pondersource/dev-stock-owncloud-sciencemesh \
composer install

8
tests/sciencemesh/maria1.sh Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
docker exec -it \
maria1.docker \
mariadb \
-u root \
-peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek \
efss

8
tests/sciencemesh/maria2.sh Executable file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
docker exec -it \
maria2.docker \
mariadb \
-u root \
-peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek \
efss

7
tests/sciencemesh/nrrn.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
export EFSS1=nextcloud
export EFSS2=nextcloud
"./scripts/testing-sciencemesh.sh"

7
tests/sciencemesh/nrro.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
export EFSS1=nextcloud
export EFSS2=owncloud
"./scripts/testing-sciencemesh.sh"

7
tests/sciencemesh/orrn.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
export EFSS1=owncloud
export EFSS2=nextcloud
"./scripts/testing-sciencemesh.sh"

7
tests/sciencemesh/orro.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
export EFSS1=owncloud
export EFSS2=owncloud
"./scripts/testing-sciencemesh.sh"

1
tests/sciencemesh/revad Symbolic link
View File

@ -0,0 +1 @@
../../examples/sciencemesh

View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
php console.php maintenance:install --admin-user "$USER" --admin-pass "$PASS" --database "mysql" \
--database-name "efss" --database-user "root" --database-host "$DBHOST" \
--database-pass "eilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek"
php console.php app:disable firstrunwizard
sed -i "8 i\ 1 => 'nextcloud1.docker'," /var/www/html/config/config.php
sed -i "9 i\ 2 => 'nextcloud2.docker'," /var/www/html/config/config.php
sed -i "3 i\ 'allow_local_remote_servers' => true," config/config.php
php console.php app:enable sciencemesh

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
php console.php maintenance:install --admin-user "${USER}" --admin-pass "${PASS}" --database "mysql" \
--database-name "efss" --database-user "root" --database-host "$DBHOST" \
--database-pass "eilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek"
php console.php app:disable firstrunwizard
sed -i "8 i\ 1 => 'owncloud1.docker'," /var/www/html/config/config.php
sed -i "9 i\ 2 => 'owncloud2.docker'," /var/www/html/config/config.php
php console.php app:enable sciencemesh
sed -i "3 i\ 'sharing.managerFactory' => 'OCA\\\\ScienceMesh\\\\ScienceMeshProviderFactory'," /var/www/html/config/config.php
sed -i "4 i\ 'sharing.remoteShareesSearch' => 'OCA\\\\ScienceMesh\\\\Plugins\\\\ScienceMeshSearchPlugin'," /var/www/html/config/config.php

View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
# see https://github.com/golang/go/issues/22846#issuecomment-380809416
echo "hosts: files dns" > /etc/nsswitch.conf
echo "127.0.0.1 ${HOST}.docker" >> /etc/hosts
# create log file.
touch /var/log/revad.log
# run revad.
reva-run.sh
# This will exec the CMD from your Dockerfile, i.e. "npm start"
exec "$@"

View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
# kill running revad.
REVAD_PID=$(pgrep -f "revad" | tail -1) && kill -9 "${REVAD_PID}"

View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
# create new dir and copy configs there.
mkdir -p /revad/configs
cp /etc/revad/sciencemesh*.toml /revad/configs/
cp /etc/revad/providers.testnet.json /revad/configs/providers.testnet.json
# substitute placeholders with correct names.
sed -i "s/your.revad.ssl/${HOST}/g" /revad/configs/sciencemesh*.toml
sed -i "s/your.revad.com/${HOST}.docker/g" /revad/configs/sciencemesh*.toml
sed -i "s/your.efss.com/${HOST//reva/}.docker/g" /revad/configs/sciencemesh*.toml
cp /etc/revad/tls/*.crt /usr/local/share/ca-certificates/
update-ca-certificates
# run revad.
revad --dev-dir "/revad/configs" &

View File

@ -0,0 +1,313 @@
/* jshint ignore:start */
const https = require('https');
const fs = require('fs');
const url = require('url');
const fetch = require('node-fetch');
const { isNativeError } = require('util/types');
const SERVER_NAME = process.env.HOST || 'stub2';
const SERVER_HOST = `${SERVER_NAME}.docker`;
const SERVER_ROOT = `https://${SERVER_HOST}`;
const USER = `einstein`;
const PROVIDER_ID = SERVER_HOST;
const MESH_PROVIDER = SERVER_HOST;
// const HTTPS_OPTIONS = {
// key: fs.readFileSync(`/etc/letsencrypt/live/${SERVER_HOST}/privkey.pem`),
// cert: fs.readFileSync(`/etc/letsencrypt/live/${SERVER_HOST}/cert.pem`),
// ca: fs.readFileSync(`/etc/letsencrypt/live/${SERVER_HOST}/chain.pem`)
// }
const HTTPS_OPTIONS = {
key: fs.readFileSync(`/tls/${SERVER_NAME}.key`),
cert: fs.readFileSync(`/tls/${SERVER_NAME}.crt`)
}
function sendHTML(res, text) {
res.end(`<!DOCTYPE html><html><head></head><body>${text}</body></html>`);
}
// singleton global, naively assume only one share exists at a time:
let mostRecentShareIn = {};
async function getServerConfig(otherUser) {
console.log('getServerConfig', otherUser);
let otherServer = otherUser.split('@').splice(1).join('@').replace('\/', '/');
console.log(otherServer);
if (otherServer.startsWith('http://')) {
// support http:// for testing
} else if (!otherServer.startsWith('https://')) {
otherServer = `https://${otherServer}`;
}
if (!otherServer.endsWith('/')) {
otherServer = `${otherServer}/`;
}
console.log('fetching', `${otherServer}ocm-provider/`);
const configResult = await fetch(`${otherServer}ocm-provider/`);
// const text = await configResult.text();
// console.log({ text });
// JSON.parse(text);
return { config: await configResult.json(), otherServer };
}
async function notifyProvider(obj, notif) {
console.log('notifyProvider', obj, notif);
// FIXME: reva sets no `sharedBy` and no `sender`
// and sets `owner` to a user opaqueId only (e.g. obj.owner: '4c510ada-c86b-4815-8820-42cdf82c3d51').
// what we ultimately need when a share comes from reva is obj.meshProvider, e.g.: 'revad1.docker'.
const { config } = await getServerConfig(obj.sharedBy || obj.sender || /* obj.owner || */ `${obj.owner}@${obj.meshProvider}`);
if (config.endPoint.substr(-1) == '/') {
config.endPoint = config.endPoint.substring(0, config.endPoint.length - 1);
}
const postRes = await fetch(`${config.endPoint}/notifications`, {
method: 'POST',
body: JSON.stringify(notif)
});
console.log('notification sent!', postRes.status, await postRes.text());
}
async function forwardInvite(invite) {
console.log('forwardInvite', invite);
const { config, otherServer } = await getServerConfig(invite);
console.log('discovered', config, otherServer);
if (!config.endPoint) {
config.endPoint = process.env.FORCE_ENDPOINT;
}
const inviteSpec = {
invite: {
token: invite.split('@')[0],
userId: 'marie',
recipientProvider: 'stub2.docker',
name: 'Marie Curie',
email: 'marie@cesnet.cz',
}
}
let endPoint = config.endPoint || config.endpoint;
if (endPoint.substr(-1) == '/') {
endPoint = endPoint.substring(0, endPoint.length - 1);
}
console.log('posting', `${endPoint}/invites/accept`, JSON.stringify(inviteSpec, null, 2))
const postRes = await fetch(`${endPoint}/invites/accept`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(inviteSpec, null, 2),
});
console.log('invite forwarded', postRes.status, await postRes.text());
}
async function createShare(consumer) {
console.log('createShare', consumer);
const { config, otherServer } = await getServerConfig(consumer);
console.log(config);
if (!config.endPoint) {
config.endPoint = process.env.FORCE_ENDPOINT;
}
const shareSpec = {
shareWith: 'marie', // consumer,
name: 'Test share from stub',
providerId: PROVIDER_ID,
meshProvider: MESH_PROVIDER,
owner: USER,
ownerDisplayName: USER,
sender: `${USER}@${SERVER_HOST}`,
senderDisplayName: USER,
shareType: 'user',
resourceType: 'file',
// see https://github.com/cs3org/ocm-test-suite/issues/25#issuecomment-852151913
protocol: JSON.stringify({ name: 'webdav', options: { token: 'shareMe' } }) // sic.
}
console.log(shareSpec, shareSpec.protocol);
if (config.endPoint.endsWith('/')) {
config.endPoint = config.endPoint.substring(0, config.endPoint.length - 1);
}
const postRes = await fetch(`${config.endPoint}/shares`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(shareSpec, null, 2),
});
console.log('outgoing share created!', postRes.status, await postRes.text());
return otherServer;
}
const server = https.createServer(HTTPS_OPTIONS, async (req, res) => {
console.log(req.method, req.url, req.headers);
let bodyIn = '';
req.on('data', (chunk) => {
console.log('CHUNK', chunk.toString());
bodyIn += chunk.toString();
});
req.on('end', async () => {
try {
if (req.url === '/ocm-provider/') {
console.log('yes /ocm-provider/');
res.end(JSON.stringify({
enabled: true,
apiVersion: '1.0-proposal1',
endPoint: `${SERVER_ROOT}/ocm`,
resourceTypes: [
{
name: 'file',
shareTypes: [ 'user', 'group' ],
protocols: { webdav: '/webdav/' }
}
]
}));
} else if (req.url === '/ocm/shares') {
console.log('yes /ocm/shares');
try {
mostRecentShareIn = JSON.parse(bodyIn);
} catch (e) {
res.writeHead(400);
sendHTML(res, 'Cannot parse JSON');
}
// {
// shareWith: "admin@https:\/\/stub1.pdsinterop.net",
// shareType: "user",
// name: "Reasons to use Nextcloud.pdf",
// resourceType: "file",
// description:"",
// providerId:202,
// owner: "alice@https:\/\/nc1.pdsinterop.net\/",
// ownerDisplayName: "alice",
// sharedBy: "alice@https:\/\/nc1.pdsinterop.net\/",
// sharedByDisplayName":"alice",
// "protocol":{
// "name":"webdav",
// "options":{
// "sharedSecret":"lvns5N9ZXm1T1zx",
// "permissions":"{http:\/\/open-cloud-mesh.org\/ns}share-permissions"
// }
// }
// }
// obj.id = obj.providerId;
res.writeHead(201, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({
"recipientDisplayName": "Marie Curie"
}, null, 2));
} else if (req.url.startsWith('/publicLink')) {
console.log('yes publicLink');
const urlObj = new URL(req.url, SERVER_ROOT);
if (urlObj.search.startsWith('?saveTo=')) {
console.log('creating share', urlObj.search);
const otherServerRoot = await createShare(decodeURIComponent(urlObj.search).substring('?saveTo='.length));
res.writeHead(301, {
location: otherServerRoot
});
sendHTML(res, `Redirecting you to ${otherServerRoot}`);
} else {
sendHTML(res, 'yes publicLink, saveTo?');
}
} else if (req.url.startsWith('/forwardInvite')) {
console.log('yes forwardInvite');
const urlObj = new URL(req.url, SERVER_ROOT);
await forwardInvite(decodeURIComponent(urlObj.search).substring('?'.length));
sendHTML(res, 'yes forwardInvite');
} else if (req.url.startsWith('/shareWith')) {
console.log('yes shareWith');
const urlObj = new URL(req.url, SERVER_ROOT);
await createShare(decodeURIComponent(urlObj.search).substring('?'.length));
sendHTML(res, 'yes shareWith');
} else if (req.url.startsWith('/acceptShare')) {
console.log('yes acceptShare');
try {
console.log('Creating notif to accept share, obj =', mostRecentShareIn);
const notif = {
type: 'SHARE_ACCEPTED',
resourceType: mostRecentShareIn.resourceType,
providerId: mostRecentShareIn.providerId,
notification: {
sharedSecret: (
mostRecentShareIn.protocol ?
(
mostRecentShareIn.protocol.options ?
mostRecentShareIn.protocol.options.sharedSecret :
undefined
) :
undefined
),
message: 'Recipient accepted the share'
}
};
notifyProvider(mostRecentShareIn, notif);
} catch (e) {
console.error(e);
sendHTML(res, `no acceptShare - fail`);
}
sendHTML(res, 'yes acceptShare');
} else if (req.url.startsWith('/deleteAcceptedShare')) {
console.log('yes deleteAcceptedShare');
const notif = {
type: 'SHARE_DECLINED',
message: 'I don\'t want to use this share anymore.',
id: mostRecentShareIn.id,
createdAt: new Date()
};
// When unshared from the provider side:
// {
// "notificationType":"SHARE_UNSHARED",
// "resourceType":"file",
// "providerId":"89",
// "notification":{
// "sharedSecret":"N7epqXHRKXWbg8f",
// "message":"File was unshared"
// }
// }
console.log('deleting share', mostRecentShareIn);
try {
notifyProvider(mostRecentShareIn, notif);
} catch (e) {
sendHTML(res, `no deleteAcceptedShare - fail ${provider}ocm-provider/`);
}
sendHTML(res, 'yes deleteAcceptedShare');
} else if (req.url == '/') {
console.log('yes a/', mostRecentShareIn);
sendHTML(res, 'yes /' + JSON.stringify(mostRecentShareIn, null, 2));
} else if (req.url.startsWith('/meshdir?')) {
const queryObject = url.parse(req.url, true).query;
console.log(queryObject);
const config = {
nextcloud1: "https://nextcloud1.docker/index.php/apps/sciencemesh/accept",
owncloud1: "https://owncloud1.docker/index.php/apps/sciencemesh/accept",
nextcloud2: "https://nextcloud2.docker/index.php/apps/sciencemesh/accept",
owncloud2: "https://owncloud2.docker/index.php/apps/sciencemesh/accept",
stub2: "https://stub.docker/ocm/invites/forward",
revad2: undefined
};
const items = [];
const scriptLines = [];
Object.keys(config).forEach(key => {
if (typeof config[key] === "string") {
items.push(` <li><a id="${key}">${key}</a></li>`);
scriptLines.push(` document.getElementById("${key}").setAttribute("href", "${config[key]}"+window.location.search);`);
} else {
const params = new URLSearchParams(req.url.split('?')[1]);
console.log(params);
const token = params.get('token');
const providerDomain = params.get('providerDomain');
items.push(` <li>${key}: Please run <tt>ocm-invite-forward -idp ${providerDomain} -token ${token}</tt> in Reva's CLI tool.</li>`);
}
})
console.log('meshdir', mostRecentShareIn);
sendHTML(res, `Welcome to the meshdir stub. Please click a server to continue to:\n<ul>${items.join('\n')}</ul>\n<script>\n${scriptLines.join('\n')}\n</script>\n`);
} else {
console.log('not recognized');
sendHTML(res, 'OK');
}
} catch (e) {
console.error(e);
}
});
});
server.listen(443);
/* jshint ignore:end */

View File

@ -0,0 +1,43 @@
#!/usr/bin/env bash
ENV_ROOT=$(pwd)
export ENV_ROOT=${ENV_ROOT}
[ ! -d "./scripts" ] && echo "Directory ./scripts DOES NOT exist inside $ENV_ROOT, are you running this from the repo root?" && exit 1
docker network inspect testnet >/dev/null 2>&1 || docker network create testnet
# make sure scripts are executable.
chmod +x "${ENV_ROOT}/scripts/reva-run.sh"
chmod +x "${ENV_ROOT}/scripts/reva-kill.sh"
chmod +x "${ENV_ROOT}/scripts/reva-entrypoint.sh"
# rclone
docker run --detach --name=rclone.docker --network=testnet rclone/rclone rcd \ \
-vv --rc-user=rcloneuser --rc-pass=eilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek \
--rc-addr=0.0.0.0:5572 --server-side-across-configs=true \
--log-file=/dev/stdout
# revad1
docker run --detach --network=testnet \
--name="revad1.docker" \
-e HOST="revad1" \
-v "${ENV_ROOT}/../..:/reva" \
-v "${ENV_ROOT}/revad:/etc/revad" \
-v "${ENV_ROOT}/tls:/etc/revad/tls" \
-v "${ENV_ROOT}/scripts/reva-run.sh:/usr/bin/reva-run.sh" \
-v "${ENV_ROOT}/scripts/reva-kill.sh:/usr/bin/reva-kill.sh" \
-v "${ENV_ROOT}/scripts/reva-entrypoint.sh:/entrypoint.sh" \
pondersource/dev-stock-revad "${REVA_CMD}"
# revad2
docker run --detach --network=testnet \
--name="revad2.docker" \
-e HOST="revad2" \
-v "${ENV_ROOT}/../..:/reva" \
-v "${ENV_ROOT}/revad:/etc/revad" \
-v "${ENV_ROOT}/tls:/etc/revad/tls" \
-v "${ENV_ROOT}/scripts/reva-run.sh:/usr/bin/reva-run.sh" \
-v "${ENV_ROOT}/scripts/reva-kill.sh:/usr/bin/reva-kill.sh" \
-v "${ENV_ROOT}/scripts/reva-entrypoint.sh:/entrypoint.sh" \
pondersource/dev-stock-revad "${REVA_CMD}"

View File

@ -0,0 +1,177 @@
#!/usr/bin/env bash
ENV_ROOT=$(pwd)
export ENV_ROOT=${ENV_ROOT}
[ ! -d "./scripts" ] && echo "Directory ./scripts DOES NOT exist inside $ENV_ROOT, are you running this from the repo root?" && exit 1
[ ! -d "./nextcloud-sciencemesh" ] && echo "Directory ./nextcloud-sciencemesh DOES NOT exist inside $ENV_ROOT, did you run ./scripts/init-sciencemesh.sh?" && exit 1
[ ! -d "./nextcloud-sciencemesh/vendor" ] && echo "Directory ./nextcloud-sciencemesh/vendor DOES NOT exist inside $ENV_ROOT. Try: rmdir ./nextcloud-sciencemesh ; ./scripts/init-sciencemesh.sh" && exit 1
[ ! -d "./owncloud-sciencemesh" ] && echo "Directory ./owncloud-sciencemesh DOES NOT exist inside $ENV_ROOT, did you run ./scripts/init-sciencemesh.sh?" && exit 1
[ ! -d "./owncloud-sciencemesh/vendor" ] && echo "Directory ./owncloud-sciencemesh/vendor DOES NOT exist inside $ENV_ROOT. Try: rmdir ./owncloud-sciencemesh ; ./scripts/init-sciencemesh.sh" && exit 1
function waitForPort {
x=$(docker exec -it "${1}" ss -tulpn | grep -c "${2}")
until [ "${x}" -ne 0 ]
do
echo Waiting for "${1}" to open port "${2}", this usually takes about 10 seconds ... "${x}"
sleep 1
x=$(docker exec -it "${1}" ss -tulpn | grep -c "${2}")
done
echo "${1}" port "${2}" is open
}
function waitForCollabora {
x=$(docker logs collabora.docker | grep -c "Ready")
until [ "${x}" -ne 0 ]
do
echo Waiting for Collabora to be ready, this usually takes about 10 seconds ... "${x}"
sleep 1
x=$(docker logs collabora.docker | grep -c "Ready")
done
echo "Collabora is ready"
}
# create temp dirctory if it doesn't exist.
[ ! -d "${ENV_ROOT}/temp" ] && mkdir --parents "${ENV_ROOT}/temp"
# copy init files.
cp --force ./scripts/init-owncloud-sciencemesh.sh ./temp/owncloud.sh
cp --force ./scripts/init-nextcloud-sciencemesh.sh ./temp/nextcloud.sh
# TLS dirs for mounting
cp --recursive --force ./tls "./temp/${EFSS1}-1-tls"
cp --recursive --force ./tls "./temp/${EFSS2}-2-tls"
# make sure scripts are executable.
chmod +x "${ENV_ROOT}/scripts/reva-run.sh"
chmod +x "${ENV_ROOT}/scripts/reva-kill.sh"
chmod +x "${ENV_ROOT}/scripts/reva-entrypoint.sh"
docker run --detach --name=meshdir.docker --network=testnet -v "${ENV_ROOT}/scripts/stub.js:/ocm-stub/stub.js" pondersource/dev-stock-ocmstub
docker run --detach --name=firefox --network=testnet -p 5800:5800 --shm-size 2g jlesage/firefox:latest
docker run --detach --name=firefox-legacy --network=testnet -p 5900:5800 --shm-size 2g jlesage/firefox:v1.18.0
docker run --detach --name=collabora.docker --network=testnet -p 9980:9980 -t -e "extra_params=--o:ssl.enable=false" collabora/code:latest
docker run --detach --name=wopi.docker --network=testnet -p 8880:8880 -t cs3org/wopiserver:latest
#docker run --detach --name=rclone.docker --network=testnet rclone/rclone rcd -vv --rc-user=rcloneuser --rc-pass=eilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek --rc-addr=0.0.0.0:5572 --server-side-across-configs=true --log-file=/dev/stdout
# EFSS1
docker run --detach --network=testnet \
--name=maria1.docker \
-e MARIADB_ROOT_PASSWORD=eilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek \
mariadb \
--transaction-isolation=READ-COMMITTED \
--binlog-format=ROW \
--innodb-file-per-table=1 \
--skip-innodb-read-only-compressed
docker run --detach --network=testnet \
--name="${EFSS1}1.docker" \
--add-host "host.docker.internal:host-gateway" \
-e HOST="${EFSS1}1" \
-e DBHOST="maria1.docker" \
-e USER="einstein" \
-e PASS="relativity" \
-v "${ENV_ROOT}/temp/${EFSS1}.sh:/${EFSS1}-init.sh" \
-v "${ENV_ROOT}/$EFSS1-sciencemesh:/var/www/html/apps/sciencemesh" \
-v "${ENV_ROOT}/temp/${EFSS1}-1-tls:/tls" \
"pondersource/dev-stock-${EFSS1}-sciencemesh"
# EFSS2
docker run --detach --network=testnet \
--name=maria2.docker \
-e MARIADB_ROOT_PASSWORD=eilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek \
mariadb \
--transaction-isolation=READ-COMMITTED \
--binlog-format=ROW \
--innodb-file-per-table=1 \
--skip-innodb-read-only-compressed
docker run --detach --network=testnet \
--name="${EFSS2}2.docker" \
--add-host "host.docker.internal:host-gateway" \
-e HOST="${EFSS2}2" \
-e DBHOST="maria2.docker" \
-e USER="marie" \
-e PASS="radioactivity" \
-v "${ENV_ROOT}/temp/${EFSS2}.sh:/${EFSS2}-init.sh" \
-v "${ENV_ROOT}/${EFSS2}-sciencemesh:/var/www/html/apps/sciencemesh" \
-v "${ENV_ROOT}/temp/${EFSS2}-2-tls:/tls" \
"pondersource/dev-stock-${EFSS2}-sciencemesh"
# EFSS1
waitForPort maria1.docker 3306
waitForPort "${EFSS1}1.docker" 443
docker exec "${EFSS1}1.docker" bash -c "cp /tls/*.crt /usr/local/share/ca-certificates/"
docker exec "${EFSS1}1.docker" update-ca-certificates
docker exec "${EFSS1}1.docker" bash -c "cat /etc/ssl/certs/ca-certificates.crt >> /var/www/html/resources/config/ca-bundle.crt"
docker exec -u www-data "${EFSS1}1.docker" sh "/${EFSS1}-init.sh"
# run db injections.
docker exec maria1.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'iopUrl', 'https://reva${EFSS1}1.docker/');"
docker exec maria1.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'revaSharedSecret', 'shared-secret-1');"
docker exec maria1.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'meshDirectoryUrl', 'https://meshdir.docker/meshdir');"
docker exec maria1.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'inviteManagerApikey', 'invite-manager-endpoint');"
# EFSS2
waitForPort maria2.docker 3306
waitForPort "${EFSS2}2.docker" 443
docker exec "${EFSS2}2.docker" bash -c "cp /tls/*.crt /usr/local/share/ca-certificates/"
docker exec "${EFSS2}2.docker" update-ca-certificates
docker exec "${EFSS2}2.docker" bash -c "cat /etc/ssl/certs/ca-certificates.crt >> /var/www/html/resources/config/ca-bundle.crt"
docker exec -u www-data "${EFSS2}2.docker" sh "/${EFSS2}-init.sh"
docker exec maria2.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'iopUrl', 'https://reva${EFSS2}2.docker/');"
docker exec maria2.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'revaSharedSecret', 'shared-secret-1');"
docker exec maria2.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'meshDirectoryUrl', 'https://meshdir.docker/meshdir');"
docker exec maria2.docker mariadb -u root -peilohtho9oTahsuongeeTh7reedahPo1Ohwi3aek efss \
-e "insert into oc_appconfig (appid, configkey, configvalue) values ('sciencemesh', 'inviteManagerApikey', 'invite-manager-endpoint');"
# reva
waitForCollabora
docker run --detach --network=testnet \
--name="reva${EFSS1}1.docker" \
-e HOST="reva${EFSS1}1" \
-p 8080:80 \
-v "${ENV_ROOT}/../..:/reva" \
-v "${ENV_ROOT}/revad:/etc/revad" \
-v "${ENV_ROOT}/tls:/etc/revad/tls" \
-v "${ENV_ROOT}/scripts/reva-run.sh:/usr/bin/reva-run.sh" \
-v "${ENV_ROOT}/scripts/reva-kill.sh:/usr/bin/reva-kill.sh" \
-v "${ENV_ROOT}/scripts/reva-entrypoint.sh:/entrypoint.sh" \
pondersource/dev-stock-revad
docker run --detach --network=testnet \
--name="reva${EFSS2}2.docker" \
-e HOST="reva${EFSS2}2" \
-p 8180:80 \
-v "${ENV_ROOT}/../..:/reva" \
-v "${ENV_ROOT}/revad:/etc/revad" \
-v "${ENV_ROOT}/tls:/etc/revad/tls" \
-v "${ENV_ROOT}/scripts/reva-run.sh:/usr/bin/reva-run.sh" \
-v "${ENV_ROOT}/scripts/reva-kill.sh:/usr/bin/reva-kill.sh" \
-v "${ENV_ROOT}/scripts/reva-entrypoint.sh:/entrypoint.sh" \
pondersource/dev-stock-revad
# instructions.
echo "Now browse to http://ocmhost:5800 and inside there to https://${EFSS1}1.docker"
echo "Log in as einstein / relativity"
echo "Go to the ScienceMesh app and generate a token"
echo "Click it to go to the meshdir server, and choose ${EFSS2}2 there."
echo "Log in on https://${EFSS2}2.docker as marie / radioactivity"

View File

@ -0,0 +1,3 @@
subjectAltName = @alt_names
[alt_names]
DNS.1 = meshdir.docker

View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDWzCCAkGgAwIBAgIUERmzeeG0Iep3EN1KQKvrSV434tMwDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkxMFoXDTMzMDcwNzEwNDkxMFowWzELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEXMBUG
A1UEAwwObWVzaGRpci5kb2NrZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC4AKVrdKu2sAyEfQpSiGVSAfHWPk2yGcokvn7PHKtuR242NNPJXTHLV4cB
+WxFLhnQaG6J+jxOqRVWr6pz4PV+8POXRQUem2BfGKs2DuDUqhTaG3vW1xGqsJ0q
fFL3cXAjWTj25sNfEaCahSDpNMXHuA5NNhDv3FGan6NjbO/n4z9Ut+HRiEcHphWN
oZ6LJvHiw8eoT2SoNYkYNBs08yg8lKGBLCqp++OxuL/F54Fbfr8LQLtGXV7Izf+r
KSSy41XfvjX6o72/UQN+8/tCSs6WKJkRQMjrk1MvPJNG+oreeOiD2MNI/U0FJ3F0
0qLBCODVWFu1giXNPAkdh6dT1697AgMBAAGjHTAbMBkGA1UdEQQSMBCCDm1lc2hk
aXIuZG9ja2VyMA0GCSqGSIb3DQEBCwUAA4IBAwABCXyLDMh7G4J/TjGo2erURmGh
ebac1UMoFLIcDU0P12NRVo2siJXPZrdNCU3GJNaQa54d5fAxORIbCeBK/PRDTpFy
TbBGmhaJko6dbhV3q7qqELMVymFemznsc29M10QfF0YzMQDhzkGhEooc/8G2iGbC
3D8cTvM8/w24Sd5409qSB3DU1x7OAOKERb4GG6/IJhtZcXqH5tlvux3XYdPm+Uwa
cG5HbFN0gVn+28EiHAwGI1kVp07jcd3sIJLCFvtjF4UlPLUHGjbydywi3lP7Ym/D
aKFEna7fNL3tYT557al2o1urKi/1j1azpWr0WTMBMhr7Y0uIdWfPCd/cw0c7snw=
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICoDCCAYgCAQAwWzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDES
MBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEXMBUGA1UEAwwObWVzaGRp
ci5kb2NrZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4AKVrdKu2
sAyEfQpSiGVSAfHWPk2yGcokvn7PHKtuR242NNPJXTHLV4cB+WxFLhnQaG6J+jxO
qRVWr6pz4PV+8POXRQUem2BfGKs2DuDUqhTaG3vW1xGqsJ0qfFL3cXAjWTj25sNf
EaCahSDpNMXHuA5NNhDv3FGan6NjbO/n4z9Ut+HRiEcHphWNoZ6LJvHiw8eoT2So
NYkYNBs08yg8lKGBLCqp++OxuL/F54Fbfr8LQLtGXV7Izf+rKSSy41XfvjX6o72/
UQN+8/tCSs6WKJkRQMjrk1MvPJNG+oreeOiD2MNI/U0FJ3F00qLBCODVWFu1giXN
PAkdh6dT1697AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEASEEb0vGne5375uZD
ntMGf8lJykXaNiaKoG4Zlrg6kqzxl2KxiUcpacohtMOBOujMSaLE61gBiN1/ypS9
6XmjhvCNtC49x4BK1UDxoYyi8RKquHPaeHjoVpbZi87mhbepVygzqPlOr8rhfnS+
k8gXRuxurxLCTlxmTXhkXwgT6rs9/Q8usKTbvmx6qRhh8w+1AP/OwTlfS5sCSMW6
lwIuCnV9LaZ9baD/oFJqMmXa1gQEWdzEOmu5A4n6eyqpsQu1lURshVmO5Pzn8MWL
ZmUTxpWxYaOnil7XQ+pinXyLHOWoDDzHfDSXc/Pfmg6VWr2Ggt5D6o4pdpD/klbY
TBj3Cw==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4AKVrdKu2sAyE
fQpSiGVSAfHWPk2yGcokvn7PHKtuR242NNPJXTHLV4cB+WxFLhnQaG6J+jxOqRVW
r6pz4PV+8POXRQUem2BfGKs2DuDUqhTaG3vW1xGqsJ0qfFL3cXAjWTj25sNfEaCa
hSDpNMXHuA5NNhDv3FGan6NjbO/n4z9Ut+HRiEcHphWNoZ6LJvHiw8eoT2SoNYkY
NBs08yg8lKGBLCqp++OxuL/F54Fbfr8LQLtGXV7Izf+rKSSy41XfvjX6o72/UQN+
8/tCSs6WKJkRQMjrk1MvPJNG+oreeOiD2MNI/U0FJ3F00qLBCODVWFu1giXNPAkd
h6dT1697AgMBAAECggEASAsYuaYIxZLQk99Rd1coNJ/GTJhAW4d1ekWL6RPUm20k
Xdz5P1JZ+L/ggIlkNwIB4XPCNAviKPpS/InzN0PRW06EUaoYgw9bAGDsSFIy/ZFK
cMtqBYhXxnk4UDY1VeT4fx6kCyf3PvXr6BRP+n9LIROTpe+RWhjtapkuo/M3S5co
c2oqrOAK+s+N/idaEAC+l9urE66h+EVSRPETVKx5DapJZnxLwPWR1zu6/GSi/xKI
zJ6pxw16CGJAXR18+OzwCqonqpE93+4lcMR313l4cxWSmo+cRUTDYnJasAZ+o9Fm
gxzjRMIhmBiVoJd6I+RQS9xTqycTPPHamOrLgNZAYQKBgQDZ/WSJtJmZzDAXMpGm
SPeCpimXqDA77zb/7pqAL/BoCAz2HW4aDsAJDSBnEncMccxTXV7dMbc+QLecmkn9
lk8+4egbzIRI+nv+OX+9aboFjrqJL8RqeZqMU9fDfp/ZOQbvyvi9Y6GIQwtmMIbX
wVd7ceVzHS8bQDt8btNjJB/oNwKBgQDYFiHW3ZLadS4nZwVaPEBJ/3uhOLtgXPoe
6K3Bbprv1QpVJN9xueifA8GgpqxIVxrv257XMxrh8I9LzodWdN9YAM6yQasBMCPx
IR7Bf3syVi9kXIkH61EpwMx6Mw1ojfCciHl6w/uSDgeide2+/kWRH80aFZA73/8o
Sj7lsQmI3QKBgQCX4n0NkZ9AUMvlLd/by5VhG6N5Pr+00t0wf7B4xm4sHgfh5+mS
EFrvM40zI+N88UFbiIATgJNbtb35SGtrXDKE7uRJkjtNmfGQ1cFSWXs6ahNAiN7D
DU2IntaEKRL5SEm0BGlBlEy1Y3lqzz70z4rDwT0M8vWieCO6dIGm30G4CwKBgCFi
QfYdI0wG4IuL2gLX3iLQirwctK4tjyLpVbbVrLAy3LbMzIyYaTzv6qE0PteqRWob
Jw4eQh/391uB29zaj4rcDRLzHEVBt7vQHx1L4a+kKww5U55al554v959NqwZibvV
RddWoe4tprZNu95PEFZccGaAQFlPwO7rkY4Q7OUtAoGAY/F6lMOhgrIhG7QpsoZC
zKaM6eJT8Dcbo11TwnWGMR41VXg+FvJCj6RJRJMiRDMX6Est17WrUQw5/NtDvRIo
PxCT+Q2h8+Xc38TjZU9glRexVqT2ey4bVbMkM84KvwnZ3wDvGJEmIhxLaCvvltbU
NKeXw/IVhhMUwOz5gXiGfdM=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,3 @@
subjectAltName = @alt_names
[alt_names]
DNS.1 = nextcloud1.docker

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDYTCCAkegAwIBAgIUERmzeeG0Iep3EN1KQKvrSV434scwDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkwOVoXDTMzMDcwNzEwNDkwOVowXjELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEaMBgG
A1UEAwwRbmV4dGNsb3VkMS5kb2NrZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQC8oFJUEeFvJz4LjMaot0xaInTwQoxzoFIAQAG4FLndpopMU/6mL3+T
4tycagqbxAYqidK/V1tLUOOY1Tr+8WHDy0HaAH+B/sNy8KtSAVTMiwCQMWNQm9Mh
TTdzXTe/L2B/bqX0nL5JtUlqfixk5owfvsj213jaYO9A1Vmxq2kMGtq3bTwQlv3j
Vg050UtMhoPYYRcA2lzQD+5M9yEHRbvK8xzCeX2dTnrryL92OuI8Xa53IfA4e5A9
LqA9ewrvF9udqWzCOLdrUeprwb/3bzsW6Tx3XRwAWnr7atd1tn1azK+JbmKzRSn8
msNHSwRBsmjaSuT18NqoZD37/D7QXGkFAgMBAAGjIDAeMBwGA1UdEQQVMBOCEW5l
eHRjbG91ZDEuZG9ja2VyMA0GCSqGSIb3DQEBCwUAA4IBAwABwxddoHnHra8UMbMm
jhqyCFpZfUHyM2HZUNP6NuzhoLEBCwCf483GvpTaXdQtkskdWxt18K8UCsql/cwb
P4FnztHbBOAL4DvjWIngcAb0ldbw/b2527ylvTBrVY5eVXwfNIjTMdWNUCgQVDOq
YqX+IqG8qwgPLTOooQhnEwy6Eiozw1Giw5WJgE6V9/gilLs/b6zGg5veOGbEVbjk
8cT5KSfYkbdQYckZlgJjmi1pql7UyDK+4xuEXaN6mUkgMGGHbwjIQzzRIbyfgl51
kXYSQehNgJFzPVdMKfnSCLWuQKgGhbpRZ6OgvvMOc/IIC2xs3n4hJHGL1//tVY0p
9cLQlXY=
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICozCCAYsCAQAwXjELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDES
MBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEaMBgGA1UEAwwRbmV4dGNs
b3VkMS5kb2NrZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8oFJU
EeFvJz4LjMaot0xaInTwQoxzoFIAQAG4FLndpopMU/6mL3+T4tycagqbxAYqidK/
V1tLUOOY1Tr+8WHDy0HaAH+B/sNy8KtSAVTMiwCQMWNQm9MhTTdzXTe/L2B/bqX0
nL5JtUlqfixk5owfvsj213jaYO9A1Vmxq2kMGtq3bTwQlv3jVg050UtMhoPYYRcA
2lzQD+5M9yEHRbvK8xzCeX2dTnrryL92OuI8Xa53IfA4e5A9LqA9ewrvF9udqWzC
OLdrUeprwb/3bzsW6Tx3XRwAWnr7atd1tn1azK+JbmKzRSn8msNHSwRBsmjaSuT1
8NqoZD37/D7QXGkFAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAc9+B629TGeO4
+DHw6cSC3m3DKjsqWRSoD0wCLpQqiLUzESpoSHZwSCuyrN9sc8Mc2lff0nfyx1ii
JlyjXwNjrAkahd6IZR96kg90t92C93ieG1Dy0z6XjN5Jc9lmMFn9sRBBQ350kV6O
1O/SvnK2hkvgX0OJ5+3evH/4WgQFfEYeHI0vgxwbdXqn+9HtRnme3Uue7m0pQNae
3Ul+gvpeizH5CA0C7Jf+UbO91SjfaiG7oYG+ae19S1CLG7W4pfIaUTTR8e1Sn1qI
XqHmjqiIeDKkht7nehcpU4FSdcMYLvPgv4zTYkYsd9+Ww3bILJL/VTHwTgRRsSlK
nN3b6BOpsg==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8oFJUEeFvJz4L
jMaot0xaInTwQoxzoFIAQAG4FLndpopMU/6mL3+T4tycagqbxAYqidK/V1tLUOOY
1Tr+8WHDy0HaAH+B/sNy8KtSAVTMiwCQMWNQm9MhTTdzXTe/L2B/bqX0nL5JtUlq
fixk5owfvsj213jaYO9A1Vmxq2kMGtq3bTwQlv3jVg050UtMhoPYYRcA2lzQD+5M
9yEHRbvK8xzCeX2dTnrryL92OuI8Xa53IfA4e5A9LqA9ewrvF9udqWzCOLdrUepr
wb/3bzsW6Tx3XRwAWnr7atd1tn1azK+JbmKzRSn8msNHSwRBsmjaSuT18NqoZD37
/D7QXGkFAgMBAAECggEBAI6FXG9lKz5/GiRD8/6asLgR/OVkgxcCdbL2qdXa4y0U
nr5ZYLlUfkLRUPtmLCnRjQ8rH++vI63eqnlZ87+ZxtLXiyQa6Dzir+7y5Z+KnfYG
uSA6EN5hPr+UxmcGcg6kz3a5te8DV8v9jEFIoGaExC9gShwoZooqX9xO1/yklTSs
8aocXIrS2UO5QJbRixckVBcolDymlwERrSpVce/mJsoNTozFD4beoZNj/PnwMZJ7
zEczr3V8stYEC4pKsozgUsugUcbdFLa7w/Z10s+aHx3aHa4uUmcE71BQgzG+9y2b
ZZe85WauGh8TJJJK6g3ayS7xcOoFN8RhCDDxfvEvhekCgYEA3f4DRzxjORJELGvQ
HdguD914UCeA4kfQRLtEVKzRggad0owBYOt03ngH18VHW+eIOIzPfz4r76GH8mcZ
CvE/mZK0GCpCqcDO0LqgGBB4OZWAJLq2QV7ElPxPccDe6mHN0Ahhzl+KlpbPXGGO
vJME53rTgJ2p8DiAUfxdtYdWAlcCgYEA2YXHBTi0/l1F7SuryFwkslS8pnAo5PCH
921EwxUAgB30+6lwI3+jx85p/4juQQgIszlzpiDDc2OQa4cA/8bSpS4LoDjiJtVz
Ru1Eo4VqYfGcPDQTM1FnoGy6qW4Q8bZNPdkG4v5WBK7w8ncahju/eGjp4kjsAqzj
6JjNnQfPbgMCgYEAqptwa4v2ecMXD8if/n/JDrpXn8psW/tzDY+aeTUEItjw7AJb
gOAURnGbHXHpYLF1WHinc5QVcioDcAFaFrXH+j/sFvJLn2ilyXbUWQo3S5IhFJlG
PsEVdabfa34eE6Ws5ie6+z8kJI2sucPkTfrzdu9Hov4Iv6y8ucWpQzzKlisCgYAi
zBfOagfqORmam0Xbw4HLVWroZUDlfuUBW+WIH6/4ztIGAFEEHMMij469ZjZXCOX7
ZdFuXgdmSiMsUGiEglXoPrl1ZCQpejP6wLIeRpWCHZiUuO/pYbhmHX6u5ACp6jPp
FPLZFT7FeQbqgssndh9nL8FahbfbpbS/3NHnsPwp6QKBgG5j1HQFyvpjzl5yjNdY
lw6/0DdvbPjQPhQ+36/shkQNXx3CoK7G2hREP709hbFACOlYfhIKxjc3G+TRq8Bx
bqeM+U8GxNf+lOYHMPBhVolMFzTFUJM7wtwPxgil38P42YOFua5OnHiAzB6meSg/
A1zUqdUa8OsGESkuQ9tYditZ
-----END PRIVATE KEY-----

View File

@ -0,0 +1,3 @@
subjectAltName = @alt_names
[alt_names]
DNS.1 = nextcloud2.docker

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDYTCCAkegAwIBAgIUERmzeeG0Iep3EN1KQKvrSV434sgwDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkxMFoXDTMzMDcwNzEwNDkxMFowXjELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEaMBgG
A1UEAwwRbmV4dGNsb3VkMi5kb2NrZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDgisCqms2zIKNcQhr71C1jNdWoRH/mT5cfPQocAbQpEduQtCJhELOu
H87G/JU+JFj0AdE7HPnk/5KFik5NeT1a1nwTN79Ac3dbtjPqIUEKJdqadNFlLxjk
9c2Trp+89p89J4Wo2br08b0aXyluoB8DVITRQMd7itFwsNWQ+dJdbH34NLeSuqg7
gydPDRgRlExQdwGZsO7YrXSQMfSogUQrSabbyiBFiXDhAMhStyJdHEqE/QrpKqEf
T4jm6bKTL+XYTRPSNy/he7q1/TRvTRE458jY2EXAJgeIEnfWFposPUfBoAoTuicm
evzq7pKO99o22qlmGxl3MT1SRcr+2o4hAgMBAAGjIDAeMBwGA1UdEQQVMBOCEW5l
eHRjbG91ZDIuZG9ja2VyMA0GCSqGSIb3DQEBCwUAA4IBAwACzOXAJ75E5nyMFnUr
RfGF2EQg+K9dACf0Ul3QlETOmZWuBp8/LhuMuspcYoxBy71XtW6fap1LYmvqyv6N
Uoi8sIztAsaPdzUOj+GtwVY34VjhFrXu5tP0RVHVBRdVON+iDIhtCAWfmgyi7ke3
Lv7SkPMKUx7o8u6m+FFAY4TrIC3J/xDVZ9wXFXnuNAG0Im15k0QYJrJnUnhAsJ1d
IPSdvykwRujosRzRgmtMmbw/HRpjc2xSDa1Di2Of0XC9ZppHNayV6YbVyp+5/diV
6bXV5M1wXJom5LokjyZvSz/bNzKlFIE458DkplPmJ//u+d6KNQcUGZ/9zNfTNj0K
Sfod1e0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICozCCAYsCAQAwXjELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDES
MBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEaMBgGA1UEAwwRbmV4dGNs
b3VkMi5kb2NrZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDgisCq
ms2zIKNcQhr71C1jNdWoRH/mT5cfPQocAbQpEduQtCJhELOuH87G/JU+JFj0AdE7
HPnk/5KFik5NeT1a1nwTN79Ac3dbtjPqIUEKJdqadNFlLxjk9c2Trp+89p89J4Wo
2br08b0aXyluoB8DVITRQMd7itFwsNWQ+dJdbH34NLeSuqg7gydPDRgRlExQdwGZ
sO7YrXSQMfSogUQrSabbyiBFiXDhAMhStyJdHEqE/QrpKqEfT4jm6bKTL+XYTRPS
Ny/he7q1/TRvTRE458jY2EXAJgeIEnfWFposPUfBoAoTuicmevzq7pKO99o22qlm
Gxl3MT1SRcr+2o4hAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAmfCXxYAeZRqU
X0g9pEHELe3rZWptrkX/h+PsWCzn3Of/KdHgHQkjjr8K2k/s3ZNq1QW2P0Gl1W4X
TZ819t+PvauzCPvxJIz/Xs5orqjBhkFf/eZ9RQgwYAwBTOinZtInEqr1cF30YHU2
ZrgJjUoeUfFfx/NsRnS8x+tNncsb6FjPhJOEvJP7I6hPVbRnVna5UPuO/W9ZqobL
W9xHDxGFrHSZpqxedTY3nbCQ9GRur4c8NjBC/UpTTq9//5xViCBqjmdopibzLxLp
BLKAjqeHbtHEbpp8kP6ZbOdlFwID7MZRBYRLehDqRayrLjlMrMiZUdbUWwzYb9W5
S+lPECxAjQ==
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgisCqms2zIKNc
Qhr71C1jNdWoRH/mT5cfPQocAbQpEduQtCJhELOuH87G/JU+JFj0AdE7HPnk/5KF
ik5NeT1a1nwTN79Ac3dbtjPqIUEKJdqadNFlLxjk9c2Trp+89p89J4Wo2br08b0a
XyluoB8DVITRQMd7itFwsNWQ+dJdbH34NLeSuqg7gydPDRgRlExQdwGZsO7YrXSQ
MfSogUQrSabbyiBFiXDhAMhStyJdHEqE/QrpKqEfT4jm6bKTL+XYTRPSNy/he7q1
/TRvTRE458jY2EXAJgeIEnfWFposPUfBoAoTuicmevzq7pKO99o22qlmGxl3MT1S
Rcr+2o4hAgMBAAECggEANcfmB7bWR+4sUn+e2OxkBpwxVYE6pR4xExFap4Sc8y1M
yqbqiRcoAi+qJiz/TggEqkT5KVByZi/0lzmeMZ41XNl8lFnI3BYL45KLcquOWXDh
oBcUxEh4jPZ2y8WKiwcC8vHRaLTlu59e7L8YPF/rra+DtF7wqJ2CNpyUOooroaZU
zMk3ZKMhN2qntnkcWUlj3quET8oueumyKOACD9kr8JaNqYpGhZTppTDittL5Lhah
yJIietvKU7RA+A0fNKwfmey3o58RAivRHjYfinjo1ELpHJR3gi6YZyeyApXvOADq
FuvCjcDtlXlHdz8hR33y3hOY9mjrcAeyvKxNtrKlhQKBgQD2ZckH92m1vAYogxmH
plZ5DUG0Tb7sqwlX42WN6jTgGBe0Q1jgMyUq0bqkXaTFfnS6NyLZmB7FuiWEgujC
4cITh9OV4kZd/q/CrMqpQl9XUq0YJ9JqEyHDtywcNSygniH5ZBZ5JHrM2sbgZOIS
0slAdx5YwY+65JLkDpwtoOQF3wKBgQDpSuwhrFWITVthcmLXoheo9NZ/t/eU7Hv9
tiQDdRm5CB0E8QAdYp/H7OLi5/K9ZpuxZDaMf91XVZiUhfUK/1jovP0L1cURuy92
5umMngXscAsUHlkUqikx5YuUhosgMRhaSjKRJ43XedPEk+bRI4Lcz3+paWTmOwWB
hllJjkvr/wKBgEavgpF/f9r7+sRKf9tzc6E8lVnVZ+1bT83f1XV19/9Fyh8Tpv6C
jaoQCrw2hRuHIJN/V8cWpdVRhovSRlYKD/QsZh28kTVL6D4v9d/Cw7k4ZaHlYq69
mFUeSlA5TPkzBEoYVX4hYf080grzxgtiXwvYYGNT/BjAlAdKzbElU+T/AoGAHXef
N+mirCLJRhfCsGYDAw5aAavlE+SDDNry1ZT2+M4zjCo8z3ljoUckqXCO0qmhRNjZ
owmLlbp0GV6KQydZvZwRgmswBztTlXs5SM+1A9ZrL9FdgySzK2BJLyuHazuITe9N
T9RlMDBtNUlRQF1x7B4xi96KJiKSYXfs00OsB1UCgYEA8EvLJpNd7oprA/MqsvEb
Z/aGoJXGjd6ypO4mR362yv2fPiZ9wnqlJtpcse6Z1pG6zkh+x3SOj4UEf0pS6Y6S
/+bk4mzeQM2YDSzy7pVE23Eka4dsynBly1Vyj3CS6J/tHdSS6pyf0gJhyvSDNVwQ
YI5Tyo8sxlKorQ/02oR2U9g=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDijCCAnCgAwIBAgIUdExBWX2/nF+JyXNeKh1YrhK0F+swDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkwOVoXDTMzMDcwNzEwNDkwOVowUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0G
A1UEAwwGb2NtLWNhMIIBIzANBgkqhkiG9w0BAQEFAAOCARAAMIIBCwKCAQIDGliW
ukkvL3YUnx5xkAfeMhtRALKC6BXUfQcxt4eZzjFa5IQNAH1i3mfZUuqytG3BAF0s
TXTiMUgMtDRQdXRY9bnnrgiAvvX9kUScQEgy4keOkgzxWxHLEg6E4irvEqxkMtgP
APXE9N5V3VoWPRE0cWboNKyJEAQGQ6dKLWsyEnltmwCJCJnrn5RnMV3jaWaQU/Ow
q2NK1bJX8cgPQZcmwHH2+h/XKrqGTdLXz5tzGYxuWeRTAZmAwbZoGBpGVLGsy7EP
/gYazAmKR7FceCYJ+ZUcJwU9Pdv7Cx1rv+6qddROnBmY5dUBqKal4cVmLYZFl2ha
NCxFz36ktX18ozoLZJkCAwEAAaNTMFEwHQYDVR0OBBYEFF5OB1UGoNv1OGFWtEcM
XoPjITVsMB8GA1UdIwQYMBaAFF5OB1UGoNv1OGFWtEcMXoPjITVsMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEDAAK4YNTO5YJF8S0j3LW6lrVjYIDQ
b1vrfiqnJ9HnIOZgiQ+BEGP4d7HLeZ71j/nn/d3qQhTlnKq85RI3RoCRh5TVQz7J
Webik3ufBhNnwicTfMSfqlH6koBufGpAZB+BtmP5Zb0XE7O31UDPK2qdxQSEA0Qx
/RAucO8TSWdEtzVLpg7h/uhe/bkehKuKSXRQIgZxrWVpU0km3BRpgEO9Vrs8UyWp
3HqnvBv7mnpfOC6ZDJLQYENNjh1k6ASCiTIjnPBhIKCYX0XeNbJYpRjWXfR+pD9M
+uvwG2DPv07nv7iQ/GmoP/AklyYwaLVck67GIH3CJxhYWsnQV5F/m7QIB/Ogbw==
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEqAIBAAKCAQIDGliWukkvL3YUnx5xkAfeMhtRALKC6BXUfQcxt4eZzjFa5IQN
AH1i3mfZUuqytG3BAF0sTXTiMUgMtDRQdXRY9bnnrgiAvvX9kUScQEgy4keOkgzx
WxHLEg6E4irvEqxkMtgPAPXE9N5V3VoWPRE0cWboNKyJEAQGQ6dKLWsyEnltmwCJ
CJnrn5RnMV3jaWaQU/Owq2NK1bJX8cgPQZcmwHH2+h/XKrqGTdLXz5tzGYxuWeRT
AZmAwbZoGBpGVLGsy7EP/gYazAmKR7FceCYJ+ZUcJwU9Pdv7Cx1rv+6qddROnBmY
5dUBqKal4cVmLYZFl2haNCxFz36ktX18ozoLZJkCAwEAAQKCAQICHv1Vs2uZjKj7
+bU2zc0DD19q5L4iDAH4KatESf+wnKlSR4kY1i/f6MY2YZ67n+iymMwYH655fFST
Eo/8O/3XXcnB3E5Fq8O9nJK4+Jwh5Foj1CRyy90C4on4Ph45JJuhNrxIrVBTXUuq
iFAviXj8T1SYAIG8g60slwyBAUEYjlY6kU7mh5CvTpl8QGM7LnhbkOFccvc18+dt
7wlaXfvA/pVgbacBjqUWNgOoC1fxtupxgd5rZ48Q/9r1L1aAAtqNlvODp7kPWIh7
GKfrDat3AP2avooTIubmVxFjIy8EgfGzZWtamkkrX59kp1AAOrrpXo+MqJyOO9lN
ak/j/83x3s0CgYEc+TKGxIMKaIKxyq12GwwslDuHgq5gjqze/Lw+HSy+m6Iihsyc
nMbZ7DwoS9Zycka6XkJ7k3nacvzeuSRyFC+Kj706G0Rg2xEFAHw+SVxWPNccYw6t
m4wyhvTbTkmS/hSEzWBNfZcdh+DaV1AAEJkr+QrXz0TsTTr0NA0jbVqk6X8CgYEb
apbiAWUt6wXf+Wdql+rYFlg2wegGe61xYJKYRT6IG7lKy7r2Fh3uqX/if6wgm/Tz
RK4RnUyUMXqHfTyuHKoQQm0jOSkJbOZ3FqbsDuve1TDQiPfzlzbMaG8Fkx/vqVCW
7+cyxMm5iii//9oMqT4nGhgeM9JGmPht3FGzRuy+zecCgYEX5D4P95f/SzMKnRDw
5VjiodF86vwUT1KqBkrMBY7SFtBaHEI5muY26aCpse/CLA26vOOht3ix9EQk/RLa
p16UqfbmJXn7TGn6b+4EBsaHrl/L3rtJ2YyAVd0vwpzVA4O0Bw80ly23gkaehYVI
qGdGZXTVhOtW2FCW8x0qa5BlkM0CgYEXADeRaGZAPbpyC0VN0iH+I9DiL4+/UKdU
RRb3lLA/dDLho0Y5CpkWDzHxDfeUbAL2zJnUwUjr0w7e+Jyd3gJ3HaN+N4hMFgbL
xj9IL8SG8AjCCwcqX6RjnQH3hVT3te6ckqw+lYY/mL9TRQzkLmCsYWH2hLdW7yMM
2Bfa9hfMg+UCgYEYzwYm7QQ79eH3Lba5wRdsrQ7kgROm/zQt1SRYA6M0+s48KpBH
GPFZzZoeY9KGWxT/0ZHWA9II68u+kk6jCLM+F3byDaZ/72SodpRqqq2d4IclAlCB
da93j2EFKB7isiT1VUo6KRCwWobcano9xhE1d9JXILRjA6nlwu5fy0wAHlI=
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1 @@
1119B379E1B421EA7710DD4A40ABEB495E37E2D3

View File

@ -0,0 +1,3 @@
subjectAltName = @alt_names
[alt_names]
DNS.1 = owncloud1.docker

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDXzCCAkWgAwIBAgIUERmzeeG0Iep3EN1KQKvrSV434skwDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkxMFoXDTMzMDcwNzEwNDkxMFowXTELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEZMBcG
A1UEAwwQb3duY2xvdWQxLmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAL+KNRnhy+ni8FweGYznyRhJN3J9JReoJLrbsvVb6XhJVbw5Kfntz96L
5n34mHD4eNjsicFAT5De4tv+MEVEir865jwCNMsZpafwC+ek1aRXunLycrmJWWl7
/1ky3trE9qk2TXOAYZapEP9B7RqhCcWLnT8+FPA18IZqIPLNi1/0+/wscDeX2GHi
VR1gDggefic3WNUX9FirSTFPmE66Pj94ndRidRD/X7Hp2ObfSr9c6d2+CdeW8FCT
BAPbEew7Wwr4+3Hdhnmt5UXK262RR4zIv8iX4LGsl5rI2lf8xO3S4/HuK5d1Dqmz
b4fPHQ3fFzCQIY+/SSKYMjTgUxzW36sCAwEAAaMfMB0wGwYDVR0RBBQwEoIQb3du
Y2xvdWQxLmRvY2tlcjANBgkqhkiG9w0BAQsFAAOCAQMAAgmV5N4Iui6DG48ij17L
WDYMIF4luViT77U+jSqyA4URMQjjxv68N6fQGTVq4P17qWM2jPsQDCB3Zy3IZITV
jFPz33HWM/hUwWukDwbT9sGrkqiu+5hHr8Mt0P/tYEK9cVs6OBQPwxe6xSWYEw2g
hmIEfJcnZHXC88JG34WLmJpuH91q8vjIBUggcvPeXYh/jW9LvUWxMaRJBd+aRYjp
MaltHoKhQ/ccrsLvYBupfdJxh/DLdjE0HyGrVp47aHWvb7gO4zhrUHPK6NDE9Scf
58dtVX/Hb+hr3hwBXgjT0fwqgmwmItJqw6ZMAi3+OSZZOPzk62aQIGeF4/qhRiu0
RuSF
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICojCCAYoCAQAwXTELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDES
MBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEZMBcGA1UEAwwQb3duY2xv
dWQxLmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+KNRnh
y+ni8FweGYznyRhJN3J9JReoJLrbsvVb6XhJVbw5Kfntz96L5n34mHD4eNjsicFA
T5De4tv+MEVEir865jwCNMsZpafwC+ek1aRXunLycrmJWWl7/1ky3trE9qk2TXOA
YZapEP9B7RqhCcWLnT8+FPA18IZqIPLNi1/0+/wscDeX2GHiVR1gDggefic3WNUX
9FirSTFPmE66Pj94ndRidRD/X7Hp2ObfSr9c6d2+CdeW8FCTBAPbEew7Wwr4+3Hd
hnmt5UXK262RR4zIv8iX4LGsl5rI2lf8xO3S4/HuK5d1Dqmzb4fPHQ3fFzCQIY+/
SSKYMjTgUxzW36sCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQB3ioLfqOfrHsOA
/jBh+mMdq1yAkDZfnqR6nVa04B7j/1g93jwlOyyEk1Vp7cy1k5MCb2DiPLMUbF4G
lozw3LSv4aRA56sKUI1gL81DP11+k+HTUdgZ6e4nCNXdgvBXiyKyPUrtJuGrBFWP
eKs0HlVdVsjH3XYva6FooB1hzXG/Aov7ba0c3MCCPoDAljbFkoPgjwUCX4Lvlreu
Yv3DBnOBjErSYepLsdFOXPXp2i4LYipfG9jQHGmlpKnkPCBxp4ZEs0YlgrvntAEv
+XjPnLCzU4XuvB1v4UstMrp9WgvjKMjpf7pCoM4DgAr3B72BMOSfbJkk7Y7TSDnB
Y1kYIPfN
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC/ijUZ4cvp4vBc
HhmM58kYSTdyfSUXqCS627L1W+l4SVW8OSn57c/ei+Z9+Jhw+HjY7InBQE+Q3uLb
/jBFRIq/OuY8AjTLGaWn8AvnpNWkV7py8nK5iVlpe/9ZMt7axPapNk1zgGGWqRD/
Qe0aoQnFi50/PhTwNfCGaiDyzYtf9Pv8LHA3l9hh4lUdYA4IHn4nN1jVF/RYq0kx
T5hOuj4/eJ3UYnUQ/1+x6djm30q/XOndvgnXlvBQkwQD2xHsO1sK+Ptx3YZ5reVF
ytutkUeMyL/Il+CxrJeayNpX/MTt0uPx7iuXdQ6ps2+Hzx0N3xcwkCGPv0kimDI0
4FMc1t+rAgMBAAECggEBAKtEAUcrRxHTAejcYSxE9OLqVNHiZJBKoM0UNWh+zrvn
lum+k3IO2pe7sFVjO6uIAUa1+lb6EisPoPnkx3SoXQewur1dm6cfP6hyU7LFCOLy
Lp0pfLu5vGE9po0zl2E2TPfwvkBQwvHcKn6TjFcLN5mTxP8Pm9lN4cvOibeRYtZg
wwFHHWXyO0El97QfTKBXDyOnOUJFOhGVwCKrGViJHLfyVLGoZsc7wlZl7JlqHGOs
xEfQlz9g7kJ5Kj0j56lw/05y7j2GPUncgorLVbLHmQL0yePLriUuI60SALndsLNV
XlGEhzhj30nu1KevNpJT3HqKVlRJVDrDrF0FiIwvk0ECgYEA7jZev147DPV3cH7P
/Jwnt/l57sd7woxfzMRB5vghxviSpOGWHmn8xEy9xxc02N5rZlOUVDogkPGx5Ogh
06EaCd2Y2kFUeXb4ibAnhM/960nTpHhmshEHQYMcSUQBPgTcP179+5ve1+Q7n1Qg
fWUtCmYuCaJCFqE64z0zKiSFVE0CgYEAzdenLtoz7ylPfU000D5o2Wxx+Sl4kA9l
uZ6YxXzjg1RkiWjMTTfBzhiz+O43eQ2IdTnCZ6T5wWMcVtL34rRJyNgpGYioG6dY
Kj1mzks4yp5kpGFB++m9cn3o0/z1S34ZMzR1jIF2Tp20Wc1D5ctjmFkeiJvQsA76
O396q20m39cCgYA+LS7Z4GylW0TLti3vj4rGeHWdH7Br/VvcBLX25Xlbh/Iu2zrl
wWBalHVMjAAdQyDhWptyyKFLc+qtBvIdXQWA4bhN75NvCOCif7ow7mEmkuSNH2ge
vlcYgHJXpUp1t6sNV2wPyoWF8GqnkbvRPyFcf4MwvItngLnwKj86lsG+WQKBgQCb
v7TsKoZpS+StdqGjf9VtzjRexxZGSqA51trZcyni0RRRNE6BjtLB0sc6b2Th32+E
43NJYPbpcMicmXyeuLOrmINgopowcmqva05CgYAzL64PAtgeeDm0S7jDzf78ZClF
KUhYTAzsZz9zQ3FAiqiNOcF0tBEvZeXI5yg2VZy4eQKBgHXsBYX/5c9tDTt1HMfo
7z/gmrQ/hjEqgbL9V6nq/Juq0HmX7QG0B9MhdWZDP3w29B6y6gjR18qRyF+R6jmG
KcStodUt/ppibmlr41TNItkJO5o9fZhsyIttA+fzAQU2m97bTkFRlXmexMOrC8qy
mLG4E0YljaM08l3UaxizKXW2
-----END PRIVATE KEY-----

View File

@ -0,0 +1,3 @@
subjectAltName = @alt_names
[alt_names]
DNS.1 = owncloud2.docker

View File

@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDXzCCAkWgAwIBAgIUERmzeeG0Iep3EN1KQKvrSV434sowDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkxMFoXDTMzMDcwNzEwNDkxMFowXTELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEZMBcG
A1UEAwwQb3duY2xvdWQyLmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBANC0JLLhSH+FWksFb86U/Z/rVCz6b3cWRpHvGSGbCCsl8dOPXYe5nV44
Q4+Q6+/PDdcvXqvF4N9tjFgnqBhFpnvufNkyKjX9DwiztHa9jo9E4/LcVnoioQX3
DZUnQ7DqI/qZgF/9hvKnbYc5g/ULpocFHPvP4D/3i048NbIRP5BnFYI8KPZPo1FG
GokqqEYOWlVKxB5+fQqTnmQZcJISWqk62e0TkdF3LdQ4t57SpJR1mznLZkiAsMtE
FBgVLSo506mgJP/M30mQs9BWMmIxQTuzJ5bCMnRLyrvHsRT82Gw7bh9Fa1yMM9Ib
TtXJRl8vFeL2fteRsgUXNmfjaA8WU+sCAwEAAaMfMB0wGwYDVR0RBBQwEoIQb3du
Y2xvdWQyLmRvY2tlcjANBgkqhkiG9w0BAQsFAAOCAQMAAVzrx4tPJ/TWYiFGNuLx
IWIrrs6wPNjOjeOrvpAKSTWFD1b8mcmI0U075Bnl1Lnrdc+mtG9q/Rs90F1bIWLr
fOOXXkcXCvyoHQrlUmpuDp3q7PTtvIKriwMigFUNZ/V+5vFKqjOm+yLhVfxiuQxR
y2c9I5wfj411p2RV5xoz2/x3SjpRJ1MRPerHLJYnGsE0Kh0n/1SaaIR8YfI4kloL
MP+yzNhRrJ4ySOtvwqIoYbtOzuwzuQMdQSPebBepG+t9KTCa5kG5zsqBp+lyk2qe
+UjOwYD8gU1sV9+iSQQ3A6vpDZkWyXMUM/EPHGUq0/i1pAblkSGNSw79BpumA/MW
Dlur
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICojCCAYoCAQAwXTELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDES
MBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEZMBcGA1UEAwwQb3duY2xv
dWQyLmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANC0JLLh
SH+FWksFb86U/Z/rVCz6b3cWRpHvGSGbCCsl8dOPXYe5nV44Q4+Q6+/PDdcvXqvF
4N9tjFgnqBhFpnvufNkyKjX9DwiztHa9jo9E4/LcVnoioQX3DZUnQ7DqI/qZgF/9
hvKnbYc5g/ULpocFHPvP4D/3i048NbIRP5BnFYI8KPZPo1FGGokqqEYOWlVKxB5+
fQqTnmQZcJISWqk62e0TkdF3LdQ4t57SpJR1mznLZkiAsMtEFBgVLSo506mgJP/M
30mQs9BWMmIxQTuzJ5bCMnRLyrvHsRT82Gw7bh9Fa1yMM9IbTtXJRl8vFeL2fteR
sgUXNmfjaA8WU+sCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQALKFLkGIW1TkeN
SbFzDSH64SUpeNw/uvgZ5H6WYpK2mn67lOihhrqeBYe8d6RbtYw3gwzg0j9jVKEA
8Jn1SWYNqLTsZ2ikjem+ftRE7dcnsjQvMV3UvFAqUukptdXxt4vVmi64LrQyUbwv
XQ3xmePaHZTQPzse0lipIVRAI/Y2OiYtSHY9WiUJBKFlw8CxjS3+GZVZlL/mXEEo
+LyfBEG8YYiAppeQScHjAidjy9hFiDUVfjz/blihgYBUGso3calNXCGy62+NfoZZ
nwVef74b2pPqiVBVUIXS77jhqijOj5ZoKbhfmLIu8+j6G3gHGq7+s9U+LymdpxVR
bdcql7Gb
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQtCSy4Uh/hVpL
BW/OlP2f61Qs+m93FkaR7xkhmwgrJfHTj12HuZ1eOEOPkOvvzw3XL16rxeDfbYxY
J6gYRaZ77nzZMio1/Q8Is7R2vY6PROPy3FZ6IqEF9w2VJ0Ow6iP6mYBf/Ybyp22H
OYP1C6aHBRz7z+A/94tOPDWyET+QZxWCPCj2T6NRRhqJKqhGDlpVSsQefn0Kk55k
GXCSElqpOtntE5HRdy3UOLee0qSUdZs5y2ZIgLDLRBQYFS0qOdOpoCT/zN9JkLPQ
VjJiMUE7syeWwjJ0S8q7x7EU/NhsO24fRWtcjDPSG07VyUZfLxXi9n7XkbIFFzZn
42gPFlPrAgMBAAECggEAS8gtzzpYbd2JNNaLi7K0CX6U+SQSl2ZiR5lPQdGefLRx
hAV5y8/NYaoCdj4EPfasKufLc4oNpnOL03LK6c1Yr4WglelORH5YGCvQqpEYE9PL
BaOWTxEF8TmNGAzC2pmaaOOWJsTTXIcJEWIEFVWeqUZlCNapsfB8B/N69+alcxQj
cEXoLHJwmcOHSLhe+QrbO3ppzZmQeObE8zuatS19zMJV+XdIg5O5NXriKsDUONd0
6L4ESOLuoas6pfhTuiyC8g8bC8vbfn7wpEdob+XLeUZM2sv0pd8rxF/2H9QkJcRu
PUZpjXhGga+sIo8WQPqkA2n1QJ6yRohdqAgPsYEGaQKBgQDokzV07ZVamkaE7dAK
XGOj7VT//F4mBNZhbKZrrhVr8NepkUTMIrD/mHWHNDQBeb4RWK8MzUyiQCFkOcuM
Oe/iKAguXPL+qpQImi/oTGF1HZy1j26/IOlaFNayXiJsw1dQMmQIQBvDSWWLQ64p
dAQGg8LP2vsYYMKbdgMUxIHANwKBgQDluW2FKL8inqnFIarDw7c1wGyPWGfQI0x0
2kTARRLg3Jilhb0AMfNScQiMLCZmJ67yJrPstiyr5mptKG3+KLtRKv5wk0Ong/3J
PprD/5r75v1IKKT9H1dHCR5jDZ8ipgM3m2UYUzrVnQeAp9WAjitcgPLv0R38hhr2
tBDYaUkn7QKBgQCUeRXRVbLZKlAGoIMFekGp7uMqoIPCJahufZwodfP6+r/S4ohX
AXaZVU0CSVNB9eRe0oy90XowwlwOzc6h8IKxj/jZEEGYTnE+pKAc3lYBHCxkw/Jh
VbNi7Ja7O9kiMfpVmjW+Bp8ypnKK22Qd1pCTUB5X72YJBAx4jngdE+35NQKBgG96
U05qHo6zRhlWpCKJyE96SHQrZ31Wk9Sk0vYmzul1w1GXm8cLdlOMbKRxDFVIbpot
8+Qr53Onxf+gvfe3VmcmIQEKRat13uMY0UvJrzEMv96TcrUuz1C2eRuCUbYjr639
Z8qtIQDmSezCBVZ0J1Cldr6v0QhpH46WhRIvzYNlAoGBAOExOYfVbhXoV7k0J7Y9
9+2Xe0q9musBvCSyfjnW6A6iSaB0typADpNuTUJdlM5/fzhQ1xpxZQPtRQq7ntST
Fn1FaLLRrglJDJobfoKAW8sXVOb2C51kSv0ZQNIJqWj6YJn6SYptOFpGK9wHH1ip
SdrMchoYweS6q10WU8IMksFt
-----END PRIVATE KEY-----

View File

@ -0,0 +1,3 @@
subjectAltName = @alt_names
[alt_names]
DNS.1 = revad1.docker

View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDWTCCAj+gAwIBAgIUERmzeeG0Iep3EN1KQKvrSV434s0wDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkxMFoXDTMzMDcwNzEwNDkxMFowWjELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEWMBQG
A1UEAwwNcmV2YWQxLmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAMGy+TqE6JKqrMVjFpTKdnHAHITfwraWdJx+FBcN1dSdhk/XCCKO034SOiBI
Z2JQvw57O2xyhcjSDf96R189MgC9+ffmB5CDBrXlQ67AKtpy6z7U5i7+K4VoRGCp
4taoEpU0HJfvh5al33kj9CkMvpnbUl13jmn62P3kR9Mb5fMeFiyVPGZAK6/yDbh4
ZxCHbr0Nq2fgeSfUbV/woYYHrOU+4BNjzKTEhdP3SuNqJZA57mrllboWb5MB+v5H
ZnqrnLlzeRKcWpsPoR69MHA2FcemykosOviRZsdXw/l6P8d6TVHiH0hq74GxRrwC
bxYRN8ys7IrxaML2o+ycc5w0SbMCAwEAAaMcMBowGAYDVR0RBBEwD4INcmV2YWQx
LmRvY2tlcjANBgkqhkiG9w0BAQsFAAOCAQMAAXD2dwMAwVZ1B3Y8NxWwpryqdy/9
aQA/aOnXFGbN5odQoDRtVa7/s7h7fYE+iold16kwwHYYi3Cw+bBC7s/s396dSdD+
hI7ivCnK1rwPQTrkrgkg+Rvu3Dc9tckdByzpfUer9cTiy6ZO6Rnz6AM4BDfvgISA
Oj07/FyX6e0hieIUNPd6IK0FwoWYc/HTqS/mgFhdT4yvjRQDJQZaNH3eMAT657jq
liT2f+GxFPA0/m2iMhViSnIdy2SrJPFCfaf/y0V8rEbknFryDdWURICzy2ERcA8j
cLFbjILxOU+oiLHcBiLo6jQiZHHFNJ0sFe8j1VB13jkxaKjKJHcH+iFESC7q
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICnzCCAYcCAQAwWjELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDES
MBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEWMBQGA1UEAwwNcmV2YWQx
LmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMGy+TqE6JKq
rMVjFpTKdnHAHITfwraWdJx+FBcN1dSdhk/XCCKO034SOiBIZ2JQvw57O2xyhcjS
Df96R189MgC9+ffmB5CDBrXlQ67AKtpy6z7U5i7+K4VoRGCp4taoEpU0HJfvh5al
33kj9CkMvpnbUl13jmn62P3kR9Mb5fMeFiyVPGZAK6/yDbh4ZxCHbr0Nq2fgeSfU
bV/woYYHrOU+4BNjzKTEhdP3SuNqJZA57mrllboWb5MB+v5HZnqrnLlzeRKcWpsP
oR69MHA2FcemykosOviRZsdXw/l6P8d6TVHiH0hq74GxRrwCbxYRN8ys7IrxaML2
o+ycc5w0SbMCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQA+dUMWllSpnkAkeQKQ
GYzsVbEiFyKZVqn2KvLfYM13vBmPwskkyRcufbpw8fcLw094O4fwfZo+ndnRv1HE
H0g2ZZUjnrTg3zDUNTE7cBRuVcuBpqathnQvvD/afeLW/hTEGwzuLWCQsTQaS4eC
UiYFX5s78kW3SMAb1vT6NJZtrJIGaGE108RexIO1cfup+JfdNs5r8+4lPM5XqTl0
BZPcKa6FMWG55xgRU0Ag0IdLoi5ZjNsBPXe7iJKI4dQBpRh3TQDPUCpIQCxk0obE
msmrsIVSO4EMCMUqSvnKVTjCK1aWffX6NF2aXedbsEg1e0COjka0tgZQIr9mRm8S
5NVZ
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBsvk6hOiSqqzF
YxaUynZxwByE38K2lnScfhQXDdXUnYZP1wgijtN+EjogSGdiUL8OeztscoXI0g3/
ekdfPTIAvfn35geQgwa15UOuwCracus+1OYu/iuFaERgqeLWqBKVNByX74eWpd95
I/QpDL6Z21Jdd45p+tj95EfTG+XzHhYslTxmQCuv8g24eGcQh269Datn4Hkn1G1f
8KGGB6zlPuATY8ykxIXT90rjaiWQOe5q5ZW6Fm+TAfr+R2Z6q5y5c3kSnFqbD6Ee
vTBwNhXHpspKLDr4kWbHV8P5ej/Hek1R4h9Iau+BsUa8Am8WETfMrOyK8WjC9qPs
nHOcNEmzAgMBAAECggEARU7e8tt/xIshivdrqw3O1+Df04OlTmQDkcNjOOSQcKV0
27ibhpIIhwHKnqaJp5ow4uOhXaqUyEixDYsZYrCo5a8UdGlwp3raudcxIqRMMSIR
nsfbHVGBDRlD7jqbmidFjvG4kXz5zSPJFLWSteWDhdX+YMdYw/8oCaDXOmivHRA1
jqfDCjoXljwVZdKew2GPnxeFm0ZqVrSREV24LB0BT5Z7ZRNDjCfMo58A4eNub3iW
Uf8tfV6mlQxJ9UScyWy6ZNCd5CUR6hkSLrvNJ8qx9oXrAGgCQihx4wv7dFvj9LoH
Iy9spEj6XlPwt56vjjurPmvLg+MpmVGxbyyq2BbWcQKBgQDfrcIFtenbKL9huZrn
OnAs1HUEHvgNkfsv4lT0qTlNE4zp0kqkQOOyKqDHuzy0h4koUbqw4PMY+i1fUuww
1CRtz6reR5haRYym4L6/wU8hrVUBBru4IhAjRkmSa+qd32+MIpNPEZSqxCM66Iox
1JZShgYGTCNC5FXY5LnQe5KRtwKBgQDdsDhk7sTne5BuAsBd6B83PyHvoghjlPy4
8GarB8MSG0bmj4oeVMbFQe//ZxlJFxyGfYrhZHqm1s6Mlk1o+yklxReMLY/597ml
YHKYuwsXSRETicE5FPakH626E0cY9XK00E2odU6slsv0gzGYLt1IrwyfjSMbwWDx
ctjxXwOX5QKBgQCiGsNqcBQziKxqnqDswyVY2ACWI/uRmiJ46Ya4aYvlmC2fp5AA
yiY6kTpEhiXQkAmO9uxeFCkaCPWpB+e024orKz2iKjD3+z+cEXUsc2Rt+7iHLeIN
6GHZrq7TNvKpx6yH2ub3fr5HpC4EG1NMGc13sTnchoFnkSPGNL2VonjusQKBgF0+
+BmMTQpI8RE02xEkx6yHQ5D2CK1KR5rKk4Sw+R4ulv33tlLXudvSxk4ZYYtay0bO
m5H+n5B5nduIhPr5We9nHWZ666pqxo2HKeyQEDQ1KZecQ8fsx2l1Ya942FjpNNxV
GbUX0oXJz/QDEuM+Ixmld5vM082i41HrytCL9Ij5AoGBALMTXN3tBCsQ22HIjJx/
SpBh1Qmhnrw7O/cvTNMHNShtaqqyhaf0IGXFt03TDtXd+2L8qAV41FBPiF4OOzom
yrEiGkvqNQA6SsUCyVzj0gJY5fhJt4d2/ApKK7b0cNGT5x6UUrsDnYKYpQGqBaDa
D8lM81fHDkufr7SgGZ7S5pDI
-----END PRIVATE KEY-----

View File

@ -0,0 +1,3 @@
subjectAltName = @alt_names
[alt_names]
DNS.1 = revad2.docker

View File

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDWTCCAj+gAwIBAgIUERmzeeG0Iep3EN1KQKvrSV434s4wDQYJKoZIhvcNAQEL
BQAwUzELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDESMBAGA1UEBwwJ
QnVjaGFyZXN0MQswCQYDVQQKDAJJVDEPMA0GA1UEAwwGb2NtLWNhMB4XDTIzMDcx
MDEwNDkxMFoXDTMzMDcwNzEwNDkxMFowWjELMAkGA1UEBhMCUk8xEjAQBgNVBAgM
CUJ1Y2hhcmVzdDESMBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEWMBQG
A1UEAwwNcmV2YWQyLmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBANu4es4bAqkomh6UTc8WoEtQMr6xXIZC85UY7+eEylcQUrEZHSnnNBUiFkwE
iKiwy7nsEAJ43z82QTY6fap8MkK+bv6XADGuUSRLoIqucsF7VX/gS3i5atGjG+sj
JXacOy9UvCNMVVlqz2NGREu7/tBJbg14MRLLZzOxxnhRZ71zAZT+ynoTQlbQ08WS
MIyXE5QW1fVHtedHy9G0yelDvqpZ9xIL+Rp9PEkcZjw9FIzUk/8zrzc46501WDDN
DRiA5oPCFv+ifN0lKWv3B64BV6rNPwO0vmR6IIEFEs5pdKoj7giUtiO5sP1w5eHD
zS3edpPX5Exe7J0ZP8EpMT/Xfh8CAwEAAaMcMBowGAYDVR0RBBEwD4INcmV2YWQy
LmRvY2tlcjANBgkqhkiG9w0BAQsFAAOCAQMAAK1338ejrH/sCFO7l362hPHrylD2
EMEIBey+jn4woQMPvqOvxHywFjkgg4dSota2HUxYROsB2QBl6GME/IVQbJ9X/KTw
v9KZYV85L2HSZ68X5jrm5Ba64/JkuE1JHfbEKwUVdbd9ofxHygcHjoizTJq5jZ8R
9EpTEQDZy9pibX0fJpAKcV8fWcxD038KlRRMHFsY1MDJQDHWUhePUBiItxA8KL5e
gJdJfX0zo0UW+2+8/b2rRoTbV6TYumNvqsUreTisE3v8Oh/u4GaRTyBFwcia6euC
B25s1OwDL91jiVj0hD+6aTQif8QlRHA0e9AJp0bhMQQgm/FgCxaLX+ItlQda
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICnzCCAYcCAQAwWjELMAkGA1UEBhMCUk8xEjAQBgNVBAgMCUJ1Y2hhcmVzdDES
MBAGA1UEBwwJQnVjaGFyZXN0MQswCQYDVQQKDAJJVDEWMBQGA1UEAwwNcmV2YWQy
LmRvY2tlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANu4es4bAqko
mh6UTc8WoEtQMr6xXIZC85UY7+eEylcQUrEZHSnnNBUiFkwEiKiwy7nsEAJ43z82
QTY6fap8MkK+bv6XADGuUSRLoIqucsF7VX/gS3i5atGjG+sjJXacOy9UvCNMVVlq
z2NGREu7/tBJbg14MRLLZzOxxnhRZ71zAZT+ynoTQlbQ08WSMIyXE5QW1fVHtedH
y9G0yelDvqpZ9xIL+Rp9PEkcZjw9FIzUk/8zrzc46501WDDNDRiA5oPCFv+ifN0l
KWv3B64BV6rNPwO0vmR6IIEFEs5pdKoj7giUtiO5sP1w5eHDzS3edpPX5Exe7J0Z
P8EpMT/Xfh8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQC0TU7/hNtmDOXk4Hlu
iuuTfzv0o62I3tTFT7sl5aeM+tN5O/PCGx3JXdIp5gD4FoSPEiyxyzz+Nun4yg+N
3zGFEN8cJ9kUMp7v1G1jED6KGAqhmsGqn86Ex0yrXTTKQ2wkUm2Jz2b+QQ3dJG91
bgecdnNwGvBl/Qf6mK1eoxRYybnnvBwesrT7Fv2ZQPnW8d7LLX3v85VUYHeku5CO
cW9CzqWWjkDfo+2bv+ZnMNfHMo8dGfMrcyCjHgOkPb0ohwaVIjIC13981iAEEHzR
2TDTcxtZflxzGN/D5ZZxi8S1hx/gnjbcmDRWNBmpXwaPTEMvjIK0PNbccuuODapu
jvgH
-----END CERTIFICATE REQUEST-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDbuHrOGwKpKJoe
lE3PFqBLUDK+sVyGQvOVGO/nhMpXEFKxGR0p5zQVIhZMBIiosMu57BACeN8/NkE2
On2qfDJCvm7+lwAxrlEkS6CKrnLBe1V/4Et4uWrRoxvrIyV2nDsvVLwjTFVZas9j
RkRLu/7QSW4NeDESy2czscZ4UWe9cwGU/sp6E0JW0NPFkjCMlxOUFtX1R7XnR8vR
tMnpQ76qWfcSC/kafTxJHGY8PRSM1JP/M683OOudNVgwzQ0YgOaDwhb/onzdJSlr
9weuAVeqzT8DtL5keiCBBRLOaXSqI+4IlLYjubD9cOXhw80t3naT1+RMXuydGT/B
KTE/134fAgMBAAECggEBAJ05dSbmzRCerSoUlVkKp8k8qhMqdzrbzdFy9riEnQWP
+JwhjGzftLUqnynmVKPhXua7tPkP5TAmcqOLV0EXfh+khWhIRStHwWhndYnHKvao
epX2ugq5I2a/gMrRa41kXjWQPNBFXw2NELnJHjXTYJNK+CVLTFJWmpKzM4IFPmah
AZJXX/WUwf68wyAFJvDKTQBbj0lwJRIl38mYcNuSE8aOrpLHUqsujdsPxdrPzGs5
mvylZ19oFq9nMJJoTUka4/jxTCkqCyTG3ENCrRvZfhgbm/n22HAhckfnqlCBsVao
kaTQLRWGBrMRXYnpnb52gPrTI9SKau/aQUkQPfg3p4ECgYEA8hFZXwvRP71AV+9J
bn66qtKxkGGR94mQHa9PHxReADwNenJ6leAO4kBccnAt1fOeRToi3MJN7NzfL/vS
8lnPrSuDVo6hlr3Mh5nwKKmxualjsqZ2lbD5PXd+x1GGmgGS/EPCDOjv4MELwpGU
Dk8/ozlMBBVtMstWbN4hu76Io2MCgYEA6F3dkXDwkNx5rWCtKd8gSUELDJpDghZi
8p0RaZCqypyTpIfdsejvIdIWJ3InT76mKL3myd70TrdDul2K62XSFKPazewfRT6a
kd5vavJ1CGEseUsPavSxsq+YXNMHAPTDCJRWiZSlf+s1y49iGalRh+H93WC0EKs2
+5H3nJaWvRUCgYAT0tXl0bruJFp7mQ4DbX9t89k0wLjKc8qIk82/9tQH4uMbrvpZ
AcNWRf0MJiGqzsucUbl/KK5nAmOIs2/ABxjZzqFv2jhjduGkDTg8rEDwum1+uOEn
Oxn+LaYFPqjuPcjCve3LTtwuJMEIyxE75sOIY23VO8f4i+xk9//9NwpLjwKBgQDI
5zdFo6drKCTP4ZF2bWNF0sXR3KLXm7FrYKAIbLsuONhyXcIxK1tuG21qJ4mTqhuR
iDc9fNYwJMWbIXuV8VAE5nKsriWPQgR0cCRXDFBhsVq5eEtZRz1IaAfM4evhSL5D
8bUseOfqxJubZ1oDI+DJInzS5eRpsQ71zYuPyKeFzQKBgDq+pCMiKL94nO6ugVjX
54+EiLHqKTtr0GqcPESLsp6ioPyfM7uFXh987+s7kSfEDH8Et62LEZMJFIZNtSYx
caF9lv5J0zu0lihrd0hQlJkLQ+NVQjWLCe4wdU1AWxd8rvzH2nUNklVD+UXh85IP
VW1N5eP+0z0neJacrll7mq42
-----END PRIVATE KEY-----

Some files were not shown because too many files have changed in this diff Show More