Merge branch 'master' into toggle-unified-roles

This commit is contained in:
Florian Schade
2024-08-27 17:43:05 +02:00
232 changed files with 2859 additions and 4916 deletions

View File

@@ -154,6 +154,20 @@ config = {
"OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE": "%s" % dirs["ocmProviders"],
},
},
"apiWopi": {
"suites": [
"apiCollaboration",
],
"skip": False,
"collaborationServiceNeeded": True,
"extraCollaborationEnvironment": {
"COLLABORATION_APP_NAME": "FakeOffice",
"COLLABORATION_APP_ADDR": "http://fakeoffice:8080",
},
"extraServerEnvironment": {
"GATEWAY_GRPC_ADDR": "0.0.0.0:9142",
},
},
"cli": {
"suites": [
"cliCommands",
@@ -855,6 +869,8 @@ def localApiTestPipeline(ctx):
"antivirusNeeded": False,
"tikaNeeded": False,
"federationServer": False,
"collaborationServiceNeeded": False,
"extraCollaborationEnvironment": {},
}
if "localApiTests" in config:
@@ -880,9 +896,10 @@ def localApiTestPipeline(ctx):
(waitForClamavService() if params["antivirusNeeded"] else []) +
(waitForEmailService() if params["emailNeeded"] else []) +
(ocisServer(storage, params["accounts_hash_difficulty"], deploy_type = "federation", extra_server_environment = params["extraServerEnvironment"]) if params["federationServer"] else []) +
(collaborationService(params["extraCollaborationEnvironment"]) if params["collaborationServiceNeeded"] else []) +
localApiTests(suite, storage, params["extraEnvironment"]) +
logRequests(),
"services": emailService() if params["emailNeeded"] else [] + clamavService() if params["antivirusNeeded"] else [],
"services": emailService() if params["emailNeeded"] else [] + clamavService() if params["antivirusNeeded"] else [] + fakeOffice() if params["collaborationServiceNeeded"] else [],
"depends_on": getPipelineNames(buildOcisBinaryForTesting(ctx)),
"trigger": {
"ref": [
@@ -987,38 +1004,25 @@ def wopiValidatorTests(ctx, storage, wopiServerType, accounts_hash_difficulty =
"/app/wopiserver.py",
],
},
{
"name": "wait-for-wopi-server",
"image": OC_CI_WAIT_FOR,
"commands": [
"wait-for -it wopiserver:9300 -t 300",
],
},
]
else:
extra_server_environment = {
"OCIS_EXCLUDE_RUN_SERVICES": "app-provider",
}
wopiServer = [
{
"name": "wopiserver",
"image": OC_CI_GOLANG,
"detach": True,
"environment": {
"MICRO_REGISTRY": "nats-js-kv",
"MICRO_REGISTRY_ADDRESS": "ocis-server:9233",
"COLLABORATION_LOG_LEVEL": "debug",
"COLLABORATION_HTTP_ADDR": "0.0.0.0:9300",
"COLLABORATION_GRPC_ADDR": "0.0.0.0:9301",
# no proof keys available in the FakeOffice
"COLLABORATION_APP_PROOF_DISABLE": "true",
"COLLABORATION_APP_NAME": "FakeOffice",
"COLLABORATION_APP_ADDR": "http://fakeoffice:8080",
"COLLABORATION_APP_INSECURE": "true",
"COLLABORATION_WOPI_SRC": "http://wopiserver:9300",
"COLLABORATION_WOPI_SECRET": "some-wopi-secret",
"COLLABORATION_CS3API_DATAGATEWAY_INSECURE": "true",
"OCIS_JWT_SECRET": "some-ocis-jwt-secret",
},
"commands": [
"%s collaboration server" % ocis_bin,
],
},
]
extra_environment = {
"COLLABORATION_APP_NAME": "FakeOffice",
"COLLABORATION_APP_ADDR": "http://fakeoffice:8080",
}
wopiServer = collaborationService(extra_environment)
wopiTestCases = dirs["base"] + "/tests/config/drone/wopiValidatorCustomTestCases.xml"
for testgroup in testgroups:
@@ -1063,34 +1067,10 @@ def wopiValidatorTests(ctx, storage, wopiServerType, accounts_hash_difficulty =
},
"steps": skipIfUnchanged(ctx, "acceptance-tests") +
restoreBuildArtifactCache(ctx, "ocis-binary-amd64", "ocis/bin") +
[
{
"name": "fakeoffice",
"image": OC_CI_ALPINE,
"detach": True,
"environment": {},
"commands": [
"sh %s/tests/config/drone/serve-hosting-discovery.sh" % (dirs["base"]),
],
},
{
"name": "wait-for-fakeoffice",
"image": OC_CI_WAIT_FOR,
"commands": [
"wait-for -it fakeoffice:8080 -t 300",
],
},
] +
fakeOffice() +
ocisServer(storage, accounts_hash_difficulty, deploy_type = "wopi_validator", extra_server_environment = extra_server_environment) +
wopiServer +
[
{
"name": "wait-for-wopi-server",
"image": OC_CI_WAIT_FOR,
"commands": [
"wait-for -it wopiserver:9300 -t 300",
],
},
{
"name": "prepare-test-file",
"image": OC_CI_ALPINE,
@@ -2177,6 +2157,7 @@ def ocisServer(storage, accounts_hash_difficulty = 4, volumes = [], depends_on =
"commands": [
"%s init --insecure true" % ocis_bin,
"cat $OCIS_CONFIG_DIR/ocis.yaml",
"cp tests/config/drone/app-registry.yaml /root/.ocis/config/app-registry.yaml",
] + (wrapper_commands),
"volumes": volumes,
"depends_on": depends_on,
@@ -2895,6 +2876,63 @@ def waitForClamavService():
],
}]
def fakeOffice():
return [
{
"name": "fakeoffice",
"image": OC_CI_ALPINE,
"detach": True,
"environment": {},
"commands": [
"sh %s/tests/config/drone/serve-hosting-discovery.sh" % (dirs["base"]),
],
},
{
"name": "wait-for-fakeoffice",
"image": OC_CI_WAIT_FOR,
"commands": [
"wait-for -it fakeoffice:8080 -t 300",
],
},
]
def collaborationService(extra_environment = {}):
environment = {
"MICRO_REGISTRY": "nats-js-kv",
"MICRO_REGISTRY_ADDRESS": "ocis-server:9233",
"COLLABORATION_LOG_LEVEL": "debug",
"COLLABORATION_HTTP_ADDR": "0.0.0.0:9300",
"COLLABORATION_GRPC_ADDR": "0.0.0.0:9301",
"COLLABORATION_APP_PROOF_DISABLE": "true",
"COLLABORATION_APP_INSECURE": "true",
"COLLABORATION_WOPI_SRC": "http://wopiserver:9300",
"COLLABORATION_WOPI_SECRET": "some-wopi-secret",
"COLLABORATION_CS3API_DATAGATEWAY_INSECURE": "true",
"OCIS_JWT_SECRET": "some-ocis-jwt-secret",
}
for item in extra_environment:
environment[item] = extra_environment[item]
return [
{
"name": "wopiserver",
"image": OC_CI_GOLANG,
"detach": True,
"environment": environment,
"commands": [
"ocis/bin/ocis collaboration server",
],
},
{
"name": "wait-for-wopi-server",
"image": OC_CI_WAIT_FOR,
"commands": [
"wait-for -it wopiserver:9300 -t 300",
],
},
]
def tikaService():
return [{
"name": "tika",

View File

@@ -56,6 +56,16 @@ The following sections list the changes for unreleased.
* Bugfix - Set capability response `disable_self_password_change` correctly: [#9853](https://github.com/owncloud/ocis/pull/9853)
* Bugfix - Activity Translations: [#9856](https://github.com/owncloud/ocis/pull/9856)
* Bugfix - The user attributes `userType` and `memberOf` are readonly: [#9867](https://github.com/owncloud/ocis/pull/9867)
* Bugfix - Use key to get specific trash item: [#9879](https://github.com/owncloud/ocis/pull/9879)
* Bugfix - Fix response code when upload a file over locked: [#9894](https://github.com/owncloud/ocis/pull/9894)
* Bugfix - List OCM permissions as graph drive item permissions: [#9905](https://github.com/owncloud/ocis/pull/9905)
* Bugfix - Fix listing ocm shares: [#9925](https://github.com/owncloud/ocis/pull/9925)
* Change - Remove store service: [#9890](https://github.com/owncloud/ocis/pull/9890)
* Enhancement - We now set the configured protocol transport for service metadata: [#9490](https://github.com/owncloud/ocis/pull/9490)
* Enhancement - Improve revisions purge: [#9891](https://github.com/owncloud/ocis/pull/9891)
* Enhancement - Allow setting default locale of activitylog: [#9892](https://github.com/owncloud/ocis/pull/9892)
* Enhancement - Graph translation path: [#9902](https://github.com/owncloud/ocis/pull/9902)
* Enhancement - Bump reva: [#9920](https://github.com/owncloud/ocis/pull/9920)
## Details
@@ -81,6 +91,81 @@ The following sections list the changes for unreleased.
https://github.com/owncloud/ocis/issues/9858
https://github.com/owncloud/ocis/pull/9867
* Bugfix - Use key to get specific trash item: [#9879](https://github.com/owncloud/ocis/pull/9879)
The activitylog and clientlog services now only fetch the specific trash item
instead of getting all items in trash and filtering them on their side. This
reduces the load on the storage users service because it no longer has to
assemble a full trash listing.
https://github.com/owncloud/ocis/pull/9879
* Bugfix - Fix response code when upload a file over locked: [#9894](https://github.com/owncloud/ocis/pull/9894)
We fixed a bug where the response code was incorrect when uploading a file over
a locked file.
https://github.com/owncloud/ocis/issues/7638
https://github.com/owncloud/ocis/pull/9894
* Bugfix - List OCM permissions as graph drive item permissions: [#9905](https://github.com/owncloud/ocis/pull/9905)
The libre graph API now returns OCM shares when listing driveItem permissions.
https://github.com/owncloud/ocis/issues/9898
https://github.com/owncloud/ocis/pull/9905
* Bugfix - Fix listing ocm shares: [#9925](https://github.com/owncloud/ocis/pull/9925)
The libre graph API now returns an etag, the role and the creation time for ocm
shares. It also includes ocm shares in the sharedByMe endpoint.
https://github.com/owncloud/ocis/pull/9925
https://github.com/owncloud/ocis/pull/9920
* Change - Remove store service: [#9890](https://github.com/owncloud/ocis/pull/9890)
We have removed the unused store service.
https://github.com/owncloud/ocis/issues/1357
https://github.com/owncloud/ocis/pull/9890
* Enhancement - We now set the configured protocol transport for service metadata: [#9490](https://github.com/owncloud/ocis/pull/9490)
This allows configuring services to listan on `tcp` or `unix` sockets and
clients to use the `dns`, `kubernetes` or `unix` protocol URIs instead of
service names.
https://github.com/owncloud/ocis/pull/9490
https://github.com/cs3org/reva/pull/4744
* Enhancement - Improve revisions purge: [#9891](https://github.com/owncloud/ocis/pull/9891)
The `revisions purge` command would time out on big spaces. We have improved
performance by parallelizing the process.
https://github.com/owncloud/ocis/pull/9891
* Enhancement - Allow setting default locale of activitylog: [#9892](https://github.com/owncloud/ocis/pull/9892)
Allows setting the default locale via `OCIS_DEFAULT_LANGUAGE` envvar
https://github.com/owncloud/ocis/pull/9892
* Enhancement - Graph translation path: [#9902](https://github.com/owncloud/ocis/pull/9902)
Add `GRAPH_TRANSLATION_PATH` envvar like in other l10n services
https://github.com/owncloud/ocis/pull/9902
* Enhancement - Bump reva: [#9920](https://github.com/owncloud/ocis/pull/9920)
Bumps reva version
https://github.com/owncloud/ocis/pull/9920
https://github.com/owncloud/ocis/pull/9879
https://github.com/owncloud/ocis/pull/9860
# Changelog for [6.3.0] (2024-08-20)
The following sections list the changes for 6.3.0.

View File

@@ -57,7 +57,6 @@ OCIS_MODULES = \
services/storage-publiclink \
services/storage-shares \
services/storage-users \
services/store \
services/thumbnails \
services/userlog \
services/users \
@@ -221,7 +220,7 @@ go-coverage:
.PHONY: protobuf
protobuf:
@for mod in ./services/thumbnails ./services/store ./services/settings; do \
@for mod in ./services/thumbnails ./services/settings; do \
echo -n "% protobuf $$mod: "; $(MAKE) --no-print-directory -C $$mod protobuf || exit 1; \
done

View File

@@ -0,0 +1,7 @@
Enhancement: Bump reva
Bumps reva version
https://github.com/owncloud/ocis/pull/9920
https://github.com/owncloud/ocis/pull/9879
https://github.com/owncloud/ocis/pull/9860

View File

@@ -0,0 +1,5 @@
Enhancement: Allow setting default locale of activitylog
Allows setting the default locale via `OCIS_DEFAULT_LANGUAGE` envvar
https://github.com/owncloud/ocis/pull/9892

View File

@@ -0,0 +1,6 @@
Bugfix: Fix response code when upload a file over locked
We fixed a bug where the response code was incorrect when uploading a file over a locked file.
https://github.com/owncloud/ocis/pull/9894
https://github.com/owncloud/ocis/issues/7638

View File

@@ -0,0 +1,5 @@
Enhancement: Graph translation path
Add `GRAPH_TRANSLATION_PATH` envvar like in other l10n services
https://github.com/owncloud/ocis/pull/9902

View File

@@ -0,0 +1,5 @@
Enhancement: Improve revisions purge
The `revisions purge` command would time out on big spaces. We have improved performance by parallelizing the process.
https://github.com/owncloud/ocis/pull/9891

View File

@@ -0,0 +1,6 @@
Bugfix: List OCM permissions as graph drive item permissions
The libre graph API now returns OCM shares when listing driveItem permissions.
https://github.com/owncloud/ocis/pull/9905
https://github.com/owncloud/ocis/issues/9898

View File

@@ -0,0 +1,7 @@
Bugfix: fix listing ocm shares
The libre graph API now returns an etag, the role and the creation time for ocm shares.
It also includes ocm shares in the sharedByMe endpoint.
https://github.com/owncloud/ocis/pull/9925
https://github.com/owncloud/ocis/pull/9920

View File

@@ -0,0 +1,6 @@
Change: Remove store service
We have removed the unused store service.
https://github.com/owncloud/ocis/pull/9890
https://github.com/owncloud/ocis/issues/1357

View File

@@ -0,0 +1,6 @@
Enhancement: We now set the configured protocol transport for service metadata
This allows configuring services to listan on `tcp` or `unix` sockets and clients to use the `dns`, `kubernetes` or `unix` protocol URIs instead of service names.
https://github.com/owncloud/ocis/pull/9490
https://github.com/cs3org/reva/pull/4744

View File

@@ -0,0 +1,5 @@
Bugfix: Use key to get specific trash item
The activitylog and clientlog services now only fetch the specific trash item instead of getting all items in trash and filtering them on their side. This reduces the load on the storage users service because it no longer has to assemble a full trash listing.
https://github.com/owncloud/ocis/pull/9879

View File

@@ -274,6 +274,17 @@ ACTIVITYLOG_TRACING_TYPE:
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
ACTIVITYLOG_TRANSLATION_PATH:
name: OCIS_TRANSLATION_PATH;ACTIVITYLOG_TRANSLATION_PATH
defaultValue: ""
type: string
description: (optional) Set this to a path with custom translations to overwrite
the builtin translations. Note that file and folder naming rules apply, see the
documentation for more details.
introductionVersion: '%%NEXT%%'
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
ACTIVITYOG_SERVICE_ACCOUNT_SECRET:
name: OCIS_SERVICE_ACCOUNT_SECRET;ACTIVITYOG_SERVICE_ACCOUNT_SECRET
defaultValue: ""
@@ -7711,28 +7722,28 @@ OCIS_ASYNC_UPLOADS:
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_AUTH_PASSWORD:
name: OCIS_CACHE_AUTH_PASSWORD;PROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_AUTH_PASSWORD
name: OCIS_CACHE_AUTH_PASSWORD;FRONTEND_OCS_STAT_CACHE_AUTH_PASSWORD
defaultValue: ""
type: string
description: The password to authenticate with the store. Only applies when store
type 'nats-js-kv' is configured.
description: The password to use for authentication. Only applies when using the
'nats-js-kv' store type.
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_AUTH_USERNAME:
name: OCIS_CACHE_AUTH_USERNAME;PROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_AUTH_USERNAME
name: OCIS_CACHE_AUTH_USERNAME;FRONTEND_OCS_STAT_CACHE_AUTH_USERNAME
defaultValue: ""
type: string
description: The username to authenticate with the store. Only applies when store
type 'nats-js-kv' is configured.
description: The username to use for authentication. Only applies when using the
'nats-js-kv' store type.
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_DATABASE:
name: OCIS_CACHE_DATABASE
defaultValue: cache-userinfo
defaultValue: cache-stat
type: string
description: The database name the configured store should use.
introductionVersion: pre5.0
@@ -7740,61 +7751,60 @@ OCIS_CACHE_DATABASE:
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_DISABLE_PERSISTENCE:
name: OCIS_CACHE_DISABLE_PERSISTENCE;PROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_DISABLE_PERSISTENCE
defaultValue: "true"
name: OCIS_CACHE_DISABLE_PERSISTENCE;FRONTEND_OCS_STAT_CACHE_DISABLE_PERSISTENCE
defaultValue: "false"
type: bool
description: Disables persistence of the store. Only applies when store type 'nats-js-kv'
is configured. Defaults to true.
description: Disable persistence of the cache. Only applies when using the 'nats-js-kv'
store type. Defaults to false.
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_SIZE:
name: OCIS_CACHE_SIZE;PROXY_OIDC_USERINFO_CACHE_SIZE
name: OCIS_CACHE_SIZE;FRONTEND_OCS_STAT_CACHE_SIZE
defaultValue: "0"
type: int
description: The maximum quantity of items in the user info cache. Only applies
when store type 'ocmem' is configured. Defaults to 512 which is derived from the
ocmem package though not explicitly set as default.
description: Max number of entries to hold in the cache.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_STORE:
name: OCIS_CACHE_STORE;PROXY_PRESIGNEDURL_SIGNING_KEYS_STORE
defaultValue: nats-js-kv
name: OCIS_CACHE_STORE;FRONTEND_OCS_STAT_CACHE_STORE
defaultValue: memory
type: string
description: 'The type of the signing key store. Supported values are: ''redis-sentinel'',
''nats-js-kv'' and ''ocisstoreservice'' (deprecated). See the text description
for details.'
introductionVersion: "5.0"
description: 'The type of the cache store. Supported values are: ''memory'', ''redis-sentinel'',
''nats-js-kv'', ''noop''. See the text description for details.'
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_STORE_NODES:
name: OCIS_CACHE_STORE_NODES;PROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_NODES
name: OCIS_CACHE_STORE_NODES;FRONTEND_OCS_STAT_CACHE_STORE_NODES
defaultValue: '[127.0.0.1:9233]'
type: '[]string'
description: A list of nodes to access the configured store. Note that the behaviour
how nodes are used is dependent on the library of the configured store. See the
Environment Variable Types description for more details.
introductionVersion: "5.0"
description: A list of nodes to access the configured store. This has no effect
when 'memory' or 'ocmem' stores are configured. Note that the behaviour how nodes
are used is dependent on the library of the configured store. See the Environment
Variable Types description for more details.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_CACHE_TTL:
name: OCIS_CACHE_TTL;PROXY_PRESIGNEDURL_SIGNING_KEYS_STORE_TTL
defaultValue: 12h0m0s
name: OCIS_CACHE_TTL;FRONTEND_OCS_STAT_CACHE_TTL
defaultValue: 5m0s
type: Duration
description: Default time to live for signing keys. See the Environment Variable
Types description for more details.
introductionVersion: "5.0"
description: Default time to live for user info in the cache. Only applied when
access tokens has no expiration. See the Environment Variable Types description
for more details.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_CORS_ALLOW_CREDENTIALS:
name: OCIS_CORS_ALLOW_CREDENTIALS;USERLOG_CORS_ALLOW_CREDENTIALS
defaultValue: "true"
name: OCIS_CORS_ALLOW_CREDENTIALS;FRONTEND_CORS_ALLOW_CREDENTIALS
defaultValue: "false"
type: bool
description: 'Allow credentials for CORS.See following chapter for more details:
*Access-Control-Allow-Credentials* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials.'
@@ -7803,9 +7813,11 @@ OCIS_CORS_ALLOW_CREDENTIALS:
removalVersion: ""
deprecationInfo: ""
OCIS_CORS_ALLOW_HEADERS:
name: OCIS_CORS_ALLOW_HEADERS;USERLOG_CORS_ALLOW_HEADERS
defaultValue: '[Authorization Origin Content-Type Accept X-Requested-With X-Request-Id
Ocs-Apirequest]'
name: OCIS_CORS_ALLOW_HEADERS;FRONTEND_CORS_ALLOW_HEADERS
defaultValue: '[Origin Accept Content-Type Depth Authorization Ocs-Apirequest If-None-Match
If-Match Destination Overwrite X-Request-Id X-Requested-With Tus-Resumable Tus-Checksum-Algorithm
Upload-Concat Upload-Length Upload-Metadata Upload-Defer-Length Upload-Expires
Upload-Checksum Upload-Offset X-HTTP-Method-Override Cache-Control]'
type: '[]string'
description: 'A list of allowed CORS headers. See following chapter for more details:
*Access-Control-Request-Headers* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers.
@@ -7815,8 +7827,9 @@ OCIS_CORS_ALLOW_HEADERS:
removalVersion: ""
deprecationInfo: ""
OCIS_CORS_ALLOW_METHODS:
name: OCIS_CORS_ALLOW_METHODS;USERLOG_CORS_ALLOW_METHODS
defaultValue: '[GET]'
name: OCIS_CORS_ALLOW_METHODS;FRONTEND_CORS_ALLOW_METHODS
defaultValue: '[OPTIONS HEAD GET PUT POST PATCH DELETE MKCOL PROPFIND PROPPATCH
MOVE COPY REPORT SEARCH]'
type: '[]string'
description: 'A list of allowed CORS methods. See following chapter for more details:
*Access-Control-Request-Method* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Method.
@@ -7826,8 +7839,8 @@ OCIS_CORS_ALLOW_METHODS:
removalVersion: ""
deprecationInfo: ""
OCIS_CORS_ALLOW_ORIGINS:
name: OCIS_CORS_ALLOW_ORIGINS;USERLOG_CORS_ALLOW_ORIGINS
defaultValue: '[*]'
name: OCIS_CORS_ALLOW_ORIGINS;FRONTEND_CORS_ALLOW_ORIGINS
defaultValue: '[https://localhost:9200]'
type: '[]string'
description: 'A list of allowed CORS origins. See following chapter for more details:
*Access-Control-Allow-Origin* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin.
@@ -7933,7 +7946,7 @@ OCIS_DISABLE_VERSIONING:
removalVersion: ""
deprecationInfo: ""
OCIS_EDITION:
name: OCIS_EDITION;OCDAV_EDITION
name: OCIS_EDITION;FRONTEND_EDITION
defaultValue: Community
type: string
description: Edition of oCIS. Used for branding purposes.
@@ -7951,10 +7964,10 @@ OCIS_EMAIL_TEMPLATE_PATH:
removalVersion: ""
deprecationInfo: ""
OCIS_ENABLE_OCM:
name: OCIS_ENABLE_OCM;GRAPH_INCLUDE_OCM_SHAREES
name: OCIS_ENABLE_OCM;FRONTEND_OCS_INCLUDE_OCM_SHAREES
defaultValue: "false"
type: bool
description: Include OCM sharees when listing users.
description: Include OCM sharees when listing sharees.
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
@@ -7970,7 +7983,7 @@ OCIS_ENABLE_RESHARING:
removalVersion: ""
deprecationInfo: Resharing will be removed in the future.
OCIS_EVENTS_AUTH_PASSWORD:
name: OCIS_EVENTS_AUTH_PASSWORD;USERLOG_EVENTS_AUTH_PASSWORD
name: OCIS_EVENTS_AUTH_PASSWORD;FRONTEND_EVENTS_AUTH_PASSWORD
defaultValue: ""
type: string
description: The password to authenticate with the events broker. The events broker
@@ -7980,7 +7993,7 @@ OCIS_EVENTS_AUTH_PASSWORD:
removalVersion: ""
deprecationInfo: ""
OCIS_EVENTS_AUTH_USERNAME:
name: OCIS_EVENTS_AUTH_USERNAME;USERLOG_EVENTS_AUTH_USERNAME
name: OCIS_EVENTS_AUTH_USERNAME;FRONTEND_EVENTS_AUTH_USERNAME
defaultValue: ""
type: string
description: The username to authenticate with the events broker. The events broker
@@ -7990,18 +8003,18 @@ OCIS_EVENTS_AUTH_USERNAME:
removalVersion: ""
deprecationInfo: ""
OCIS_EVENTS_CLUSTER:
name: OCIS_EVENTS_CLUSTER;USERLOG_EVENTS_CLUSTER
name: OCIS_EVENTS_CLUSTER;FRONTEND_EVENTS_CLUSTER
defaultValue: ocis-cluster
type: string
description: The clusterID of the event system. The event system is the message
queuing service. It is used as message broker for the microservice architecture.
Mandatory when using NATS as event system.
introductionVersion: pre5.0
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_EVENTS_ENABLE_TLS:
name: OCIS_EVENTS_ENABLE_TLS;USERLOG_EVENTS_ENABLE_TLS
name: OCIS_EVENTS_ENABLE_TLS;NATS_EVENTS_ENABLE_TLS
defaultValue: "false"
type: bool
description: Enable TLS for the connection to the events broker. The events broker
@@ -8011,31 +8024,31 @@ OCIS_EVENTS_ENABLE_TLS:
removalVersion: ""
deprecationInfo: ""
OCIS_EVENTS_ENDPOINT:
name: OCIS_EVENTS_ENDPOINT;USERLOG_EVENTS_ENDPOINT
name: OCIS_EVENTS_ENDPOINT;FRONTEND_EVENTS_ENDPOINT
defaultValue: 127.0.0.1:9233
type: string
description: The address of the event system. The event system is the message queuing
service. It is used as message broker for the microservice architecture.
introductionVersion: pre5.0
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_EVENTS_TLS_ROOT_CA_CERTIFICATE:
name: OCIS_EVENTS_TLS_ROOT_CA_CERTIFICATE;USERLOG_EVENTS_TLS_ROOT_CA_CERTIFICATE
name: OCIS_EVENTS_TLS_ROOT_CA_CERTIFICATE;ANTIVIRUS_EVENTS_TLS_ROOT_CA_CERTIFICATE
defaultValue: ""
type: string
description: The root CA certificate used to validate the server's TLS certificate.
If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false.
If provided ANTIVIRUS_EVENTS_TLS_INSECURE will be seen as false.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_GATEWAY_GRPC_ADDR:
name: OCIS_GATEWAY_GRPC_ADDR;GATEWAY_GRPC_ADDR
name: OCIS_GATEWAY_GRPC_ADDR;STORAGE_USERS_GATEWAY_GRPC_ADDR
defaultValue: 127.0.0.1:9142
type: string
description: The bind address of the GRPC service.
introductionVersion: pre5.0
description: The bind address of the gateway GRPC address.
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
@@ -8094,16 +8107,17 @@ OCIS_HTTP_TLS_KEY:
removalVersion: ""
deprecationInfo: ""
OCIS_INSECURE:
name: OCIS_INSECURE;USERLOG_EVENTS_TLS_INSECURE
name: OCIS_INSECURE;NATS_TLS_SKIP_VERIFY_CLIENT_CERT
defaultValue: "false"
type: bool
description: Whether to verify the server TLS certificates.
description: Whether the NATS server should skip the client certificate verification
during the TLS handshake.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_JWT_SECRET:
name: OCIS_JWT_SECRET;USERLOG_JWT_SECRET
name: OCIS_JWT_SECRET;GROUPS_JWT_SECRET
defaultValue: ""
type: string
description: The secret to mint and validate jwt tokens.
@@ -8112,7 +8126,7 @@ OCIS_JWT_SECRET:
removalVersion: ""
deprecationInfo: ""
OCIS_KEYCLOAK_BASE_PATH:
name: OCIS_KEYCLOAK_BASE_PATH;INVITATIONS_KEYCLOAK_BASE_PATH
name: OCIS_KEYCLOAK_BASE_PATH;GRAPH_KEYCLOAK_BASE_PATH
defaultValue: ""
type: string
description: The URL to access keycloak.
@@ -8121,16 +8135,16 @@ OCIS_KEYCLOAK_BASE_PATH:
removalVersion: ""
deprecationInfo: ""
OCIS_KEYCLOAK_CLIENT_ID:
name: OCIS_KEYCLOAK_CLIENT_ID;INVITATIONS_KEYCLOAK_CLIENT_ID
name: OCIS_KEYCLOAK_CLIENT_ID;GRAPH_KEYCLOAK_CLIENT_ID
defaultValue: ""
type: string
description: The client ID to authenticate with keycloak.
description: The client id to authenticate with keycloak.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_KEYCLOAK_CLIENT_REALM:
name: OCIS_KEYCLOAK_CLIENT_REALM;INVITATIONS_KEYCLOAK_CLIENT_REALM
name: OCIS_KEYCLOAK_CLIENT_REALM;GRAPH_KEYCLOAK_CLIENT_REALM
defaultValue: ""
type: string
description: The realm the client is defined in.
@@ -8139,7 +8153,7 @@ OCIS_KEYCLOAK_CLIENT_REALM:
removalVersion: ""
deprecationInfo: ""
OCIS_KEYCLOAK_CLIENT_SECRET:
name: OCIS_KEYCLOAK_CLIENT_SECRET;INVITATIONS_KEYCLOAK_CLIENT_SECRET
name: OCIS_KEYCLOAK_CLIENT_SECRET;GRAPH_KEYCLOAK_CLIENT_SECRET
defaultValue: ""
type: string
description: The client secret to use in authentication.
@@ -8148,7 +8162,7 @@ OCIS_KEYCLOAK_CLIENT_SECRET:
removalVersion: ""
deprecationInfo: ""
OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY:
name: OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY;INVITATIONS_KEYCLOAK_INSECURE_SKIP_VERIFY
name: OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY;GRAPH_KEYCLOAK_INSECURE_SKIP_VERIFY
defaultValue: "false"
type: bool
description: Disable TLS certificate validation for Keycloak connections. Do not
@@ -8158,7 +8172,7 @@ OCIS_KEYCLOAK_INSECURE_SKIP_VERIFY:
removalVersion: ""
deprecationInfo: ""
OCIS_KEYCLOAK_USER_REALM:
name: OCIS_KEYCLOAK_USER_REALM;INVITATIONS_KEYCLOAK_USER_REALM
name: OCIS_KEYCLOAK_USER_REALM;GRAPH_KEYCLOAK_USER_REALM
defaultValue: ""
type: string
description: The realm users are defined.
@@ -8197,20 +8211,20 @@ OCIS_LDAP_CACERT:
removalVersion: ""
deprecationInfo: ""
OCIS_LDAP_DISABLE_USER_MECHANISM:
name: OCIS_LDAP_DISABLE_USER_MECHANISM;USERS_LDAP_DISABLE_USER_MECHANISM
name: OCIS_LDAP_DISABLE_USER_MECHANISM;GRAPH_DISABLE_USER_MECHANISM
defaultValue: attribute
type: string
description: An option to control the behavior for disabling users. Valid options
description: An option to control the behavior for disabling users. Supported options
are 'none', 'attribute' and 'group'. If set to 'group', disabling a user via API
will add the user to the configured group for disabled users, if set to 'attribute'
this will be done in the ldap user entry, if set to 'none' the disable request
is not processed.
is not processed. Default is 'attribute'.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_LDAP_DISABLED_USERS_GROUP_DN:
name: OCIS_LDAP_DISABLED_USERS_GROUP_DN;USERS_LDAP_DISABLED_USERS_GROUP_DN
name: OCIS_LDAP_DISABLED_USERS_GROUP_DN;GRAPH_DISABLED_USERS_GROUP_DN
defaultValue: cn=DisabledUsersGroup,ou=groups,o=libregraph-idm
type: string
description: The distinguished name of the group to which added users will be classified
@@ -8326,7 +8340,7 @@ OCIS_LDAP_INSECURE:
removalVersion: ""
deprecationInfo: ""
OCIS_LDAP_SERVER_WRITE_ENABLED:
name: OCIS_LDAP_SERVER_WRITE_ENABLED;GRAPH_LDAP_SERVER_WRITE_ENABLED
name: OCIS_LDAP_SERVER_WRITE_ENABLED;FRONTEND_LDAP_SERVER_WRITE_ENABLED
defaultValue: "true"
type: bool
description: Allow creating, modifying and deleting LDAP users via the GRAPH API.
@@ -8357,10 +8371,10 @@ OCIS_LDAP_USER_BASE_DN:
removalVersion: ""
deprecationInfo: ""
OCIS_LDAP_USER_ENABLED_ATTRIBUTE:
name: OCIS_LDAP_USER_ENABLED_ATTRIBUTE;USERS_LDAP_USER_ENABLED_ATTRIBUTE
name: OCIS_LDAP_USER_ENABLED_ATTRIBUTE;GRAPH_USER_ENABLED_ATTRIBUTE
defaultValue: ownCloudUserEnabled
type: string
description: LDAP attribute to use as a flag telling if the user is enabled or disabled.
description: LDAP Attribute to use as a flag telling if the user is enabled or disabled.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
@@ -8424,7 +8438,7 @@ OCIS_LDAP_USER_SCHEMA_MAIL:
removalVersion: ""
deprecationInfo: ""
OCIS_LDAP_USER_SCHEMA_USER_TYPE:
name: OCIS_LDAP_USER_SCHEMA_USER_TYPE;USERS_LDAP_USER_TYPE_ATTRIBUTE
name: OCIS_LDAP_USER_SCHEMA_USER_TYPE;GRAPH_LDAP_USER_TYPE_ATTRIBUTE
defaultValue: ownCloudUserType
type: string
description: LDAP Attribute to distinguish between 'Member' and 'Guest' users. Default
@@ -8453,7 +8467,7 @@ OCIS_LDAP_USER_SCOPE:
removalVersion: ""
deprecationInfo: ""
OCIS_LOG_COLOR:
name: OCIS_LOG_COLOR;USERLOG_LOG_COLOR
name: OCIS_LOG_COLOR;NATS_LOG_COLOR
defaultValue: "false"
type: bool
description: Activates colorized log output.
@@ -8462,7 +8476,7 @@ OCIS_LOG_COLOR:
removalVersion: ""
deprecationInfo: ""
OCIS_LOG_FILE:
name: OCIS_LOG_FILE;USERLOG_LOG_FILE
name: OCIS_LOG_FILE;NATS_LOG_FILE
defaultValue: ""
type: string
description: The path to the log file. Activates logging to this file if set.
@@ -8471,7 +8485,7 @@ OCIS_LOG_FILE:
removalVersion: ""
deprecationInfo: ""
OCIS_LOG_LEVEL:
name: OCIS_LOG_LEVEL;USERLOG_LOG_LEVEL
name: OCIS_LOG_LEVEL;NATS_LOG_LEVEL
defaultValue: ""
type: string
description: 'The log level. Valid values are: ''panic'', ''fatal'', ''error'',
@@ -8481,7 +8495,7 @@ OCIS_LOG_LEVEL:
removalVersion: ""
deprecationInfo: ""
OCIS_LOG_PRETTY:
name: OCIS_LOG_PRETTY;USERLOG_LOG_PRETTY
name: OCIS_LOG_PRETTY;NATS_LOG_PRETTY
defaultValue: "false"
type: bool
description: Activates pretty log output.
@@ -8490,11 +8504,11 @@ OCIS_LOG_PRETTY:
removalVersion: ""
deprecationInfo: ""
OCIS_MACHINE_AUTH_API_KEY:
name: OCIS_MACHINE_AUTH_API_KEY;PROXY_MACHINE_AUTH_API_KEY
name: OCIS_MACHINE_AUTH_API_KEY;FRONTEND_MACHINE_AUTH_API_KEY
defaultValue: ""
type: string
description: Machine auth API key used to validate internal requests necessary to
access resources from other services.
description: The machine auth API key used to validate internal requests necessary
to access resources from other services.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
@@ -8511,16 +8525,17 @@ OCIS_OIDC_CLIENT_ID:
removalVersion: ""
deprecationInfo: ""
OCIS_OIDC_ISSUER:
name: OCIS_URL;OCIS_OIDC_ISSUER;PROXY_OIDC_ISSUER
name: OCIS_URL;OCIS_OIDC_ISSUER;GROUPS_IDP_URL
defaultValue: https://localhost:9200
type: string
description: URL of the OIDC issuer. It defaults to URL of the builtin IDP.
description: The identity provider value to set in the group IDs of the CS3 group
objects for groups returned by this group provider.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST:
name: OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST;SHARING_PASSWORD_POLICY_BANNED_PASSWORDS_LIST
name: OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST;FRONTEND_PASSWORD_POLICY_BANNED_PASSWORDS_LIST
defaultValue: ""
type: string
description: Path to the 'banned passwords list' file. This only impacts public
@@ -8530,7 +8545,7 @@ OCIS_PASSWORD_POLICY_BANNED_PASSWORDS_LIST:
removalVersion: ""
deprecationInfo: ""
OCIS_PASSWORD_POLICY_DISABLED:
name: OCIS_PASSWORD_POLICY_DISABLED;SHARING_PASSWORD_POLICY_DISABLED
name: OCIS_PASSWORD_POLICY_DISABLED;FRONTEND_PASSWORD_POLICY_DISABLED
defaultValue: "false"
type: bool
description: Disable the password policy. Defaults to false if not set.
@@ -8539,7 +8554,7 @@ OCIS_PASSWORD_POLICY_DISABLED:
removalVersion: ""
deprecationInfo: ""
OCIS_PASSWORD_POLICY_MIN_CHARACTERS:
name: OCIS_PASSWORD_POLICY_MIN_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_CHARACTERS
name: OCIS_PASSWORD_POLICY_MIN_CHARACTERS;FRONTEND_PASSWORD_POLICY_MIN_CHARACTERS
defaultValue: "8"
type: int
description: Define the minimum password length. Defaults to 8 if not set.
@@ -8548,7 +8563,7 @@ OCIS_PASSWORD_POLICY_MIN_CHARACTERS:
removalVersion: ""
deprecationInfo: ""
OCIS_PASSWORD_POLICY_MIN_DIGITS:
name: OCIS_PASSWORD_POLICY_MIN_DIGITS;SHARING_PASSWORD_POLICY_MIN_DIGITS
name: OCIS_PASSWORD_POLICY_MIN_DIGITS;FRONTEND_PASSWORD_POLICY_MIN_DIGITS
defaultValue: "1"
type: int
description: Define the minimum number of digits. Defaults to 1 if not set.
@@ -8557,7 +8572,7 @@ OCIS_PASSWORD_POLICY_MIN_DIGITS:
removalVersion: ""
deprecationInfo: ""
OCIS_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS:
name: OCIS_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS
name: OCIS_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS;FRONTEND_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS
defaultValue: "1"
type: int
description: Define the minimum number of uppercase letters. Defaults to 1 if not
@@ -8567,7 +8582,7 @@ OCIS_PASSWORD_POLICY_MIN_LOWERCASE_CHARACTERS:
removalVersion: ""
deprecationInfo: ""
OCIS_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS:
name: OCIS_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS
name: OCIS_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS;FRONTEND_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS
defaultValue: "1"
type: int
description: Define the minimum number of characters from the special characters
@@ -8577,7 +8592,7 @@ OCIS_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS:
removalVersion: ""
deprecationInfo: ""
OCIS_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS:
name: OCIS_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS;SHARING_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS
name: OCIS_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS;FRONTEND_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS
defaultValue: "1"
type: int
description: Define the minimum number of lowercase letters. Defaults to 1 if not
@@ -8587,8 +8602,8 @@ OCIS_PASSWORD_POLICY_MIN_UPPERCASE_CHARACTERS:
removalVersion: ""
deprecationInfo: ""
OCIS_PERSISTENT_STORE:
name: OCIS_PERSISTENT_STORE;USERLOG_STORE
defaultValue: memory
name: OCIS_PERSISTENT_STORE;POSTPROCESSING_STORE
defaultValue: nats-js-kv
type: string
description: 'The type of the store. Supported values are: ''memory'', ''ocmem'',
''etcd'', ''redis'', ''redis-sentinel'', ''nats-js'', ''noop''. See the text description
@@ -8598,7 +8613,7 @@ OCIS_PERSISTENT_STORE:
removalVersion: ""
deprecationInfo: ""
OCIS_PERSISTENT_STORE_AUTH_PASSWORD:
name: OCIS_PERSISTENT_STORE_AUTH_PASSWORD;USERLOG_STORE_AUTH_PASSWORD
name: OCIS_PERSISTENT_STORE_AUTH_PASSWORD;POSTPROCESSING_STORE_AUTH_PASSWORD
defaultValue: ""
type: string
description: The password to authenticate with the store. Only applies when store
@@ -8608,7 +8623,7 @@ OCIS_PERSISTENT_STORE_AUTH_PASSWORD:
removalVersion: ""
deprecationInfo: ""
OCIS_PERSISTENT_STORE_AUTH_USERNAME:
name: OCIS_PERSISTENT_STORE_AUTH_USERNAME;USERLOG_STORE_AUTH_USERNAME
name: OCIS_PERSISTENT_STORE_AUTH_USERNAME;POSTPROCESSING_STORE_AUTH_USERNAME
defaultValue: ""
type: string
description: The username to authenticate with the store. Only applies when store
@@ -8618,8 +8633,8 @@ OCIS_PERSISTENT_STORE_AUTH_USERNAME:
removalVersion: ""
deprecationInfo: ""
OCIS_PERSISTENT_STORE_NODES:
name: OCIS_PERSISTENT_STORE_NODES;USERLOG_STORE_NODES
defaultValue: '[]'
name: OCIS_PERSISTENT_STORE_NODES;POSTPROCESSING_STORE_NODES
defaultValue: '[127.0.0.1:9233]'
type: '[]string'
description: A list of nodes to access the configured store. This has no effect
when 'memory' or 'ocmem' stores are configured. Note that the behaviour how nodes
@@ -8630,7 +8645,7 @@ OCIS_PERSISTENT_STORE_NODES:
removalVersion: ""
deprecationInfo: ""
OCIS_PERSISTENT_STORE_SIZE:
name: OCIS_PERSISTENT_STORE_SIZE;USERLOG_STORE_SIZE
name: OCIS_PERSISTENT_STORE_SIZE;POSTPROCESSING_STORE_SIZE
defaultValue: "0"
type: int
description: The maximum quantity of items in the store. Only applies when store
@@ -8641,11 +8656,11 @@ OCIS_PERSISTENT_STORE_SIZE:
removalVersion: ""
deprecationInfo: ""
OCIS_PERSISTENT_STORE_TTL:
name: OCIS_PERSISTENT_STORE_TTL;USERLOG_STORE_TTL
defaultValue: 336h0m0s
name: OCIS_PERSISTENT_STORE_TTL;POSTPROCESSING_STORE_TTL
defaultValue: 0s
type: Duration
description: Time to live for events in the store. Defaults to '336h' (2 weeks).
See the Environment Variable Types description for more details.
description: Time to live for events in the store. See the Environment Variable
Types description for more details.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
@@ -8663,7 +8678,7 @@ OCIS_REVA_GATEWAY:
name: OCIS_REVA_GATEWAY
defaultValue: com.owncloud.api.gateway
type: string
description: CS3 gateway used to look up user metadata
description: The CS3 gateway endpoint.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
@@ -8691,7 +8706,7 @@ OCIS_REVA_GATEWAY_TLS_MODE:
removalVersion: ""
deprecationInfo: ""
OCIS_SERVICE_ACCOUNT_ID:
name: OCIS_SERVICE_ACCOUNT_ID;USERLOG_SERVICE_ACCOUNT_ID
name: OCIS_SERVICE_ACCOUNT_ID;FRONTEND_SERVICE_ACCOUNT_ID
defaultValue: ""
type: string
description: The ID of the service account the service should use. See the 'auth-service'
@@ -8701,7 +8716,7 @@ OCIS_SERVICE_ACCOUNT_ID:
removalVersion: ""
deprecationInfo: ""
OCIS_SERVICE_ACCOUNT_SECRET:
name: OCIS_SERVICE_ACCOUNT_SECRET;USERLOG_SERVICE_ACCOUNT_SECRET
name: OCIS_SERVICE_ACCOUNT_SECRET;FRONTEND_SERVICE_ACCOUNT_SECRET
defaultValue: ""
type: string
description: The service account secret.
@@ -8710,7 +8725,7 @@ OCIS_SERVICE_ACCOUNT_SECRET:
removalVersion: ""
deprecationInfo: ""
OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD:
name: OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD;SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD
name: OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD;FRONTEND_OCS_PUBLIC_SHARE_MUST_HAVE_PASSWORD
defaultValue: "true"
type: bool
description: Set this to true if you want to enforce passwords on all public shares.
@@ -8719,13 +8734,11 @@ OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD:
removalVersion: ""
deprecationInfo: ""
OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD:
name: OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD;SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD
name: OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD;FRONTEND_OCS_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD
defaultValue: "false"
type: bool
description: Set this to true if you want to enforce passwords on Uploader, Editor
or Contributor shares. If not using the global OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD,
you must define the FRONTEND_OCS_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD in
the frontend service.
description: Set this to true if you want to enforce passwords for writable shares.
Only effective if the setting for 'passwords on all public shares' is set to false.
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""
@@ -8773,7 +8786,7 @@ OCIS_SYSTEM_USER_ID:
removalVersion: ""
deprecationInfo: ""
OCIS_SYSTEM_USER_IDP:
name: OCIS_SYSTEM_USER_IDP;SETTINGS_SYSTEM_USER_IDP
name: OCIS_SYSTEM_USER_IDP;SHARING_PUBLIC_CS3_SYSTEM_USER_IDP
defaultValue: internal
type: string
description: IDP of the oCIS STORAGE-SYSTEM system user.
@@ -8782,7 +8795,7 @@ OCIS_SYSTEM_USER_IDP:
removalVersion: ""
deprecationInfo: ""
OCIS_TRACING_COLLECTOR:
name: OCIS_TRACING_COLLECTOR;USERLOG_TRACING_COLLECTOR
name: OCIS_TRACING_COLLECTOR;NATS_TRACING_COLLECTOR
defaultValue: ""
type: string
description: The HTTP endpoint for sending spans directly to a collector, i.e. http://jaeger-collector:14268/api/traces.
@@ -8792,7 +8805,7 @@ OCIS_TRACING_COLLECTOR:
removalVersion: ""
deprecationInfo: ""
OCIS_TRACING_ENABLED:
name: OCIS_TRACING_ENABLED;USERLOG_TRACING_ENABLED
name: OCIS_TRACING_ENABLED;NATS_TRACING_ENABLED
defaultValue: "false"
type: bool
description: Activates tracing.
@@ -8801,7 +8814,7 @@ OCIS_TRACING_ENABLED:
removalVersion: ""
deprecationInfo: ""
OCIS_TRACING_ENDPOINT:
name: OCIS_TRACING_ENDPOINT;USERLOG_TRACING_ENDPOINT
name: OCIS_TRACING_ENDPOINT;NATS_TRACING_ENDPOINT
defaultValue: ""
type: string
description: The endpoint of the tracing agent.
@@ -8810,7 +8823,7 @@ OCIS_TRACING_ENDPOINT:
removalVersion: ""
deprecationInfo: ""
OCIS_TRACING_TYPE:
name: OCIS_TRACING_TYPE;USERLOG_TRACING_TYPE
name: OCIS_TRACING_TYPE;NATS_TRACING_TYPE
defaultValue: ""
type: string
description: The type of tracing. Defaults to '', which is the same as 'jaeger'.
@@ -8823,13 +8836,13 @@ OCIS_TRANSFER_SECRET:
name: OCIS_TRANSFER_SECRET
defaultValue: ""
type: string
description: The storage transfer secret.
description: Transfer secret for signing file up- and download requests.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_TRANSLATION_PATH:
name: OCIS_TRANSLATION_PATH;USERLOG_TRANSLATION_PATH
name: OCIS_TRANSLATION_PATH;NOTIFICATIONS_TRANSLATION_PATH
defaultValue: ""
type: string
description: (optional) Set this to a path with custom translations to overwrite
@@ -8840,20 +8853,21 @@ OCIS_TRANSLATION_PATH:
removalVersion: ""
deprecationInfo: ""
OCIS_URL:
name: OCIS_URL;OCIS_OIDC_ISSUER;PROXY_OIDC_ISSUER
name: OCIS_URL;OCIS_OIDC_ISSUER;GROUPS_IDP_URL
defaultValue: https://localhost:9200
type: string
description: URL of the OIDC issuer. It defaults to URL of the builtin IDP.
description: The identity provider value to set in the group IDs of the CS3 group
objects for groups returned by this group provider.
introductionVersion: pre5.0
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
OCIS_WOPI_DISABLE_CHAT:
name: APP_PROVIDER_WOPI_DISABLE_CHAT;OCIS_WOPI_DISABLE_CHAT
name: COLLABORATION_WOPI_DISABLE_CHAT;OCIS_WOPI_DISABLE_CHAT
defaultValue: "false"
type: bool
description: Disable the chat functionality of the office app.
introductionVersion: pre5.0
description: Disable chat in the frontend.
introductionVersion: '%%NEXT%%'
deprecationVersion: ""
removalVersion: ""
deprecationInfo: ""
@@ -9103,8 +9117,8 @@ OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE:
name: OCM_OCM_PROVIDER_AUTHORIZER_PROVIDERS_FILE
defaultValue: /etc/ocis/ocmproviders.json
type: string
description: Path to the JSON file where ocm invite data will be stored. If not
defined, the root directory derives from $OCIS_BASE_DATA_PATH:/storage.
description: Path to the JSON file where ocm invite data will be stored. Defaults
to $OCIS_CONFIG_DIR:/ocmproviders.json.
introductionVersion: "5.0"
deprecationVersion: ""
removalVersion: ""

View File

@@ -1,7 +1,7 @@
---
title: "Beta testplan"
date: 2022-03-24T00:00:00+00:00
weight: 37
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: beta-testplan.md

View File

@@ -1,7 +1,7 @@
---
title: "Documentation"
date: 2020-07-27T08:39:38+00:00
weight: 99
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: build-docs.md

View File

@@ -1,7 +1,7 @@
---
title: "Build"
date: 2020-02-27T20:35:00+01:00
weight: 30
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: build.md

View File

@@ -1,7 +1,7 @@
---
title: "Continuous Integration"
date: 2020-10-01T20:35:00+01:00
weight: 100
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: continuous-integration.md

View File

@@ -1,7 +1,7 @@
---
title: "Debugging"
date: 2020-03-19T08:21:00+01:00
weight: 50
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: debugging.md

View File

@@ -1,36 +0,0 @@
---
title: "Deprecating Variables"
date: 2022-11-29T15:41:00+01:00
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: deprecating-variables.md
---
{{< toc >}}
## Deprecating Environment Variables
Sometimes it is necessary to deprecate environment to align their naming with conventions. We therefore added annotations to automate the documentation process. It is necessary to know when the variable is going to be deprecated, when it is going to be removed and why.
### Example
```golang
// Notifications defines the config options for the notifications service.
type Notifications struct {
RevaGateway string `yaml:"reva_gateway" env:"OCIS_REVA_GATEWAY;REVA_GATEWAY" desc:"CS3 gateway used to look up user metadata" deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"REVA_GATEWAY changing name for consistency" deprecationReplacement:"OCIS_REVA_GATEWAY"`
...
}
```
There are four different annotation variables that need to be filled:
| Annotation |Description| Format|
|---|---|---|
| deprecationVersion | The version the variable will be deprecated | semver (e.g. 3.0)|
| removalVersion| The version the variable will be removed from the codebase. Note that according to semver, a removal **MUST NOT** be made in a minor or patch version change, but only in a major release | semver (e.g. 4.0.0) |
| deprecationInfo | Information why the variable is deprecated, must start with the name of the variable in order to avoid confusion, when there are multiple options in the `env:`-field | string (e.g. NATS_NATS_HOST is confusing) |
| deprecationReplacement | The name of the variable that is going to replace the deprecated one.| string (e.g. NATS_HOST_ADDRESS) |
### What happens next?
Once a variable has been finally removed, the annotations must be removed again from the code, since they do not serve any purpose from this point.

View File

@@ -0,0 +1,13 @@
---
title: "Environment Variables"
date: 2024-08-22T15:41:00+01:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: envvars.md
---
Environment variables are an essential part of configuring services.
If you are going to create new ones or deprecate existing ones, you must read the [Envvar Naming Scope]({{< ref "services/general-info/envvar-scopes.md" >}}) and the
[Deprecating Variables]({{< ref "services/general-info/deprecating-variables.md" >}}) documentation for more details first before doing so.

View File

@@ -1,7 +1,7 @@
---
title: "Profiling"
date: 2021-08-24T12:32:20+01:00
weight: 56
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: profiling.md

View File

@@ -1,7 +1,7 @@
---
title: "Acceptance Testing"
date: 2018-05-02T00:00:00+00:00
weight: 38
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development
geekdocFilePath: testing.md

View File

@@ -1,7 +1,7 @@
---
title: "Unit Testing"
date: 2024-04-25T00:00:00+00:00
weight: 5
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development/unit-testing
geekdocFilePath: _index.md

View File

@@ -1,7 +1,7 @@
---
title: "Standard Library Testing"
date: 2024-04-25T00:00:00+00:00
weight: 15
weight: 10
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/ocis/development/unit-testing
geekdocFilePath: testing-pkg.md

View File

@@ -91,3 +91,6 @@ Translations have a `context` and a `translatable string`. The context is shown
l10n-clean:
rm -f $(TEMPLATE_FILE);
```
* Add Description Text to README\
Add the full `Translations` and `Default Language` text blocks including their sub sections to the service readme. You can derive from the `activitylog` or `userlog` service for easy copy/paste.

View File

@@ -0,0 +1,54 @@
---
title: "Envvar Deprecation"
date: 2024-08-22T15:41:00+01:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/services/general-info
geekdocFilePath: deprecating-variables.md
---
{{< toc >}}
## Deprecating Environment Variables
Sometimes it is necessary to deprecate an environment variable to align the naming with conventions or remove it completely. We therefore added annotations to automate the *documentation* process.
The relevant annotations in the envvar struct tag are:
* `deprecationVersion`\
The release an envvar is announced for deprecation.
* `removalVersion`\
The version it is finally going to be removed is defined via the mandatory placeholder `%%NEXT_PRODUCTION_VERSION%%`, not an actual version number.
* `deprecationInfo`\
The reason why it was deprecated.
* `deprecationReplacement`\
Only if it is going to be replaced, not necessary if removed.
{{< hint warning >}}
During the development cycle, the value for the `removalVersion` must be set to `%%NEXT_PRODUCTION_VERSION%%`. This placeholder will be replaced by the real version number during the production releasing process.
{{< /hint >}}
For the documentation to show the correct value for the `removalVersion`, our docs helper scripts will automatically generate the correct version to be printed in the documentation. If `%%NEXT_PRODUCTION_VERSION%%` is found in the query, it will be replaced with `next-prod`, else the value found is used.
### Example
```golang
// Notifications defines the config options for the notifications service.
type Notifications struct {
RevaGateway string `yaml:"reva_gateway" env:"OCIS_REVA_GATEWAY;REVA_GATEWAY" desc:"CS3 gateway used to look up user metadata" deprecationVersion:"3.0" removalVersion:"%%NEXT_PRODUCTION_VERSION%%" deprecationInfo:"REVA_GATEWAY changing name for consistency" deprecationReplacement:"OCIS_REVA_GATEWAY"`
...
}
```
There are four different annotation variables that need to be filled:
| Annotation |Description| Format|
|---|---|---|
| deprecationVersion | The version the variable will be deprecated | semver (e.g. 3.0)|
| removalVersion| The version the variable will be removed from the codebase. Note that according to semver, a removal **MUST NOT** be made in a minor or patch version change, but only in a major release | `%%NEXT_PRODUCTION_VERSION%%` |
| deprecationInfo | Information why the variable is deprecated, must start with the name of the variable in order to avoid confusion, when there are multiple options in the `env:`-field | string (e.g. NATS_NATS_HOST is confusing) |
| deprecationReplacement | The name of the variable that is going to replace the deprecated one.| string (e.g. NATS_HOST_ADDRESS) |
### What Happens Next?
Once a variable has been finally been removed, the annotations must be removed again from the code, since they don't serve any purpose.

View File

@@ -1,5 +1,5 @@
---
title: Envvar Naming Scope
title: Envvar Naming Scopes
date: 2023-03-23T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
@@ -8,6 +8,8 @@ geekdocFilePath: envvar-scopes.md
geekdocCollapseSection: true
---
{{< toc >}}
The scope of an environment variable can be derived from its name. Therefore, it is important to follow the correct naming scheme to enable easy and proper identification. This is important when either:
- a new local envvar is introduced.
@@ -20,7 +22,7 @@ The scope of an environment variable can be derived from its name. Therefore, it
- Mandatory when used in a service, a global envvar must have a local counterpart.
- Variables that do not belong to any service are by definition global.
## Name Scope
## Naming Scope
### Local Envvars
@@ -34,14 +36,32 @@ Note that this envvar is the global representation of the local example from abo
To get a list of global envvars used in all services, see the [Global Environment Variables](https://doc.owncloud.com/ocis/next/deployment/services/env-vars-special-scope.html#global-environment-variables) table in the ocis admin documentation.
### Lifecycle
## Lifecycle of Envvars
In the struct tag values of our config data types, we are using three key/value pairs to document the lifecycle of a config variable: `introductionVersion`, `deprecationVersion` and `removalVersion`. During the development cycle, a new value should set to `%%NEXT%%` as long as no release is scheduled. During the release process, the placeholder will be replaced with the actual version number. Our docs helper scripts will then automatically generate the correct documentation based on the version number.
The envvar struct tag contains at maximum the following key/value pairs to document the lifecycle of a config variable:
## Deprecations
* `introductionVersion`
* `deprecationVersion`
* `removalVersion`
* `deprecationInfo`
* `deprecationReplacement`
All environment variable types that are used in a service follow the same [deprecation rules]({{< ref "ocis/development/deprecating-variables/_index.md" >}}) independent of their scope.
### Introduce new Envvars
## Separating Envvars
If a new envvar is introduced, only the `introductionVersion` is required.
{{< hint warning >}}
During the development cycle, the value for the `introductionVersion` must be set to `%%NEXT%%`. This placeholder will be removed by the real version number during the production releasing process.
{{< /hint >}}
For the documentation to show the correct value for the `IV` (introduction version), our docs helper scripts will automatically generate the correct version to be printed in the documentation. If `%%NEXT%%` is found in the query, it will be replaced with `next`, else the value found is used.
During the releasing process for a production release, the placeholder `%%NEXT%%` has to be replaced with the new production version number like `%%NEXT%%``7.0.0`.
### Deprecate Existing Envvars
See the [deprecation rules]({{< ref "./deprecating-variables.md" >}}) documentation for more details.
## Separating Multiple Envvars
When multiple envvars are defined for one purpose like a global and local one, use `;` (semicolon) to properly separate the envvars in go code. Though it is possible to separate with `,` (comma) according go rules, the current implementation of the docs generation process only recognizes semicolons as separator.

View File

@@ -32,7 +32,7 @@ Use this checklist with copy/paste in your PR - right from the beginning. It ren
- Add the service config to `ocis-pkg/config/defaultconfig.go`
- [ ] If the service is using service accounts, add it to `ocis/pkg/init/init.go`
- [ ] Add the service to `.drone.star` to enable CI.
- [ ] Inform doc team in an _early stage_ to review the readme AND the environment variables created.
- [ ] Inform doc team in an *early stage* to review the readme AND the environment variables created.
- The description must reflect the behaviour AND usually has a positive code quality impact.
- [ ] Create proper description strings for envvars - see other services for examples, especially when it comes to multiple values. This must include:
- base description, set of available values, description of each value.
@@ -44,4 +44,5 @@ Use this checklist with copy/paste in your PR - right from the beginning. It ren
- [ ] Make sure to have a function `FullDefaultConfig()` in `pkg/config/defaults/defaultconfig.go` of your service. It is needed to create the documentation.
- [ ] Add metrics to the code to enable monitoring. See the proxy service for implementation details.
- Plus add documentation about monitoring in the README.md file
- [ ] When the service requires translations that have to be covered by the service and are not sourced by web, see the [add translation]({{< ref "./add-translations.md" >}}) documentation for more details.
```

View File

@@ -49,7 +49,7 @@ We also suggest using the last port in your extensions' range as a debug/metrics
| 9180-9184 | FREE (formerly used by accounts) |
| 9185-9189 | [thumbnails]({{< ref "../thumbnails/_index.md" >}}) |
| 9190-9194 | [settings]({{< ref "../settings/_index.md" >}}) |
| 9195-9197 | [activitylog]({{< ref "../activitylog/_index.md" >}}) |
| 9195-9197 | [activitylog]({{< ref "../activitylog/_index.md" >}}) |
| 9198-9199 | [auth-service]({{< ref "../auth-service/_index.md" >}}) |
| 9200-9204 | [proxy]({{< ref "../proxy/_index.md" >}}) |
| 9205-9209 | [proxy]({{< ref "../proxy/_index.md" >}}) |
@@ -103,7 +103,7 @@ We also suggest using the last port in your extensions' range as a debug/metrics
| 9445-9449 | FREE |
| 9450-9454 | FREE |
| 9455-9459 | FREE |
| 9460-9464 | [store]({{< ref "../store/_index.md" >}}) |
| 9460-9464 | FREE (formerly used by store-service) |
| 9465-9469 | FREE |
| 9470-9474 | FREE |
| 9475-9479 | FREE |

View File

@@ -1 +0,0 @@
grpc.md

View File

@@ -1,18 +0,0 @@
---
title: "Store"
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/services/store
geekdocFilePath: _index.md
geekdocCollapseSection: true
---
## Abstract
This service provides ...
## Table of Contents
{{< toc-tree >}}

View File

@@ -1,15 +0,0 @@
---
title: Service Configuration
date: 2018-05-02T00:00:00+00:00
weight: 20
geekdocRepo: https://github.com/owncloud/ocis
geekdocEditPath: edit/master/docs/services/store
geekdocFilePath: configuration.md
geekdocCollapseSection: true
---
## Example YAML Config
{{< include file="services/_includes/store-config-example.yaml" language="yaml" >}}
{{< include file="services/_includes/store_configvars.md" >}}

22
go.mod
View File

@@ -7,7 +7,7 @@ require (
github.com/CiscoM31/godata v1.0.10
github.com/KimMachineGun/automemlimit v0.6.1
github.com/Masterminds/semver v1.5.0
github.com/MicahParks/keyfunc v1.9.0
github.com/MicahParks/keyfunc/v2 v2.1.0
github.com/Nerzal/gocloak/v13 v13.9.0
github.com/bbalet/stopwords v1.0.0
github.com/beevik/etree v1.4.1
@@ -15,7 +15,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.11.0
github.com/cs3org/go-cs3apis v0.0.0-20240724121416-062c4e3046cb
github.com/cs3org/reva/v2 v2.23.0
github.com/cs3org/reva/v2 v2.23.1-0.20240826144102-af5123b523cf
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1
@@ -23,7 +23,6 @@ require (
github.com/ggwhite/go-masker v1.1.0
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/render v1.0.3
github.com/go-jose/go-jose/v3 v3.0.3
github.com/go-ldap/ldap/v3 v3.4.8
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3
github.com/go-micro/plugins/v4/client/grpc v1.2.1
@@ -42,14 +41,14 @@ require (
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0
github.com/go-playground/validator/v10 v10.22.0
github.com/gofrs/uuid v4.4.0+incompatible
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/golang/protobuf v1.5.4
github.com/google/go-cmp v0.6.0
github.com/google/go-tika v0.3.1
github.com/google/uuid v1.6.0
github.com/gookit/config/v2 v2.2.5
github.com/gorilla/mux v1.8.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0
github.com/invopop/validation v0.8.0
github.com/jellydator/ttlcache/v2 v2.11.1
github.com/jellydator/ttlcache/v3 v3.2.0
@@ -67,13 +66,13 @@ require (
github.com/oklog/run v1.1.0
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.20.0
github.com/onsi/ginkgo/v2 v2.20.1
github.com/onsi/gomega v1.34.1
github.com/open-policy-agent/opa v0.67.1
github.com/orcaman/concurrent-map v1.0.0
github.com/owncloud/libre-graph-api-go v1.0.5-0.20240820135012-5fac8096ce9c
github.com/pkg/errors v0.9.1
github.com/pkg/xattr v0.4.9
github.com/pkg/xattr v0.4.10
github.com/prometheus/client_golang v1.20.1
github.com/r3labs/sse/v2 v2.10.0
github.com/riandyrn/otelchi v0.9.0
@@ -93,7 +92,7 @@ require (
github.com/urfave/cli/v2 v2.27.4
github.com/xhit/go-simple-mail/v2 v2.16.0
go-micro.dev/v4 v4.11.0
go.etcd.io/bbolt v1.3.10
go.etcd.io/bbolt v1.3.11
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0
go.opentelemetry.io/contrib/zpages v0.53.0
@@ -110,7 +109,7 @@ require (
golang.org/x/sync v0.8.0
golang.org/x/term v0.23.0
golang.org/x/text v0.17.0
google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142
google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2
gopkg.in/yaml.v2 v2.4.0
@@ -195,6 +194,7 @@ require (
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-git/go-git/v5 v5.11.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
@@ -220,7 +220,7 @@ require (
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
github.com/golang/glog v1.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@@ -348,7 +348,7 @@ require (
golang.org/x/tools v0.24.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect

37
go.sum
View File

@@ -75,8 +75,8 @@ github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3Q
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o=
github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw=
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
@@ -255,8 +255,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c=
github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME=
github.com/cs3org/go-cs3apis v0.0.0-20240724121416-062c4e3046cb h1:KmYZDReplv/yfwc1LNYpDcVhVujC3Pasv6WjXx1haSU=
github.com/cs3org/go-cs3apis v0.0.0-20240724121416-062c4e3046cb/go.mod h1:yyP8PRo0EZou3nSH7H4qjlzQwaydPeIRNgX50npQHpE=
github.com/cs3org/reva/v2 v2.23.0 h1:tRa+q6usndTQ6LbaxtfEub3UsKVruJ1l7HY6K+ZKS9s=
github.com/cs3org/reva/v2 v2.23.0/go.mod h1:p7CHBXcg6sSqB+0JMNDfC1S7TSh9FghXkw1kTV3KcJI=
github.com/cs3org/reva/v2 v2.23.1-0.20240826144102-af5123b523cf h1:VMg9uATNCBjJhU0dJJ5wgchLCCkZr/6IxjJxY+8hAAs=
github.com/cs3org/reva/v2 v2.23.1-0.20240826144102-af5123b523cf/go.mod h1:p7CHBXcg6sSqB+0JMNDfC1S7TSh9FghXkw1kTV3KcJI=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
@@ -482,11 +482,10 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo=
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -610,8 +609,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vb
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE=
@@ -922,8 +921,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.20.0 h1:PE84V2mHqoT1sglvHc8ZdQtPcwmvvt29WLEEO3xmdZw=
github.com/onsi/ginkgo/v2 v2.20.0/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
@@ -970,8 +969,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE=
github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -1219,8 +1218,8 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
go-micro.dev/v4 v4.11.0 h1:DZ2xcr0pnZJDlp6MJiCLhw4tXRxLw9xrJlPT91kubr0=
go-micro.dev/v4 v4.11.0/go.mod h1:eE/tD53n3KbVrzrWxKLxdkGw45Fg1qaNLWjpJMvIUF4=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c=
go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4=
go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A=
@@ -1669,10 +1668,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a h1:YIa/rzVqMEokBkPtydCkx1VLmv3An1Uw7w1P1m6EhOY=
google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:AHT0dDg3SoMOgZGnZk29b5xTbPHMoEC8qthmBLJCpys=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=

View File

@@ -38,7 +38,6 @@ import (
storageshares "github.com/owncloud/ocis/v2/services/storage-shares/pkg/config"
storagesystem "github.com/owncloud/ocis/v2/services/storage-system/pkg/config"
storageusers "github.com/owncloud/ocis/v2/services/storage-users/pkg/config"
store "github.com/owncloud/ocis/v2/services/store/pkg/config"
thumbnails "github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
userlog "github.com/owncloud/ocis/v2/services/userlog/pkg/config"
users "github.com/owncloud/ocis/v2/services/users/pkg/config"
@@ -68,6 +67,7 @@ type Config struct {
GRPCClientTLS *shared.GRPCClientTLS `yaml:"grpc_client_tls"`
GRPCServiceTLS *shared.GRPCServiceTLS `yaml:"grpc_service_tls"`
HTTPServiceTLS shared.HTTPServiceTLS `yaml:"http_service_tls"`
Reva *shared.Reva `yaml:"reva"`
Mode Mode // DEPRECATED
File string
@@ -117,7 +117,6 @@ type Config struct {
StoragePublicLink *storagepublic.Config `yaml:"storage_public"`
StorageShares *storageshares.Config `yaml:"storage_shares"`
StorageUsers *storageusers.Config `yaml:"storage_users"`
Store *store.Config `yaml:"store"`
Thumbnails *thumbnails.Config `yaml:"thumbnails"`
Userlog *userlog.Config `yaml:"userlog"`
Users *users.Config `yaml:"users"`

View File

@@ -1,6 +1,7 @@
package config
import (
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
activitylog "github.com/owncloud/ocis/v2/services/activitylog/pkg/config/defaults"
antivirus "github.com/owncloud/ocis/v2/services/antivirus/pkg/config/defaults"
appProvider "github.com/owncloud/ocis/v2/services/app-provider/pkg/config/defaults"
@@ -37,7 +38,6 @@ import (
storageshares "github.com/owncloud/ocis/v2/services/storage-shares/pkg/config/defaults"
storageSystem "github.com/owncloud/ocis/v2/services/storage-system/pkg/config/defaults"
storageusers "github.com/owncloud/ocis/v2/services/storage-users/pkg/config/defaults"
store "github.com/owncloud/ocis/v2/services/store/pkg/config/defaults"
thumbnails "github.com/owncloud/ocis/v2/services/thumbnails/pkg/config/defaults"
userlog "github.com/owncloud/ocis/v2/services/userlog/pkg/config/defaults"
users "github.com/owncloud/ocis/v2/services/users/pkg/config/defaults"
@@ -53,6 +53,9 @@ func DefaultConfig() *Config {
Port: "9250",
Host: "localhost",
},
Reva: &shared.Reva{
Address: "com.owncloud.api.gateway",
},
Activitylog: activitylog.DefaultConfig(),
Antivirus: antivirus.DefaultConfig(),
@@ -90,7 +93,6 @@ func DefaultConfig() *Config {
StorageShares: storageshares.DefaultConfig(),
StorageSystem: storageSystem.DefaultConfig(),
StorageUsers: storageusers.DefaultConfig(),
Store: store.DefaultConfig(),
Thumbnails: thumbnails.DefaultConfig(),
Userlog: userlog.DefaultConfig(),
Users: users.DefaultConfig(),

View File

@@ -58,7 +58,9 @@ func EnsureDefaults(cfg *config.Config) {
if cfg.GRPCServiceTLS == nil {
cfg.GRPCServiceTLS = &shared.GRPCServiceTLS{}
}
if cfg.Reva == nil {
cfg.Reva = &shared.Reva{}
}
}
// EnsureCommons copies applicable parts of the oCIS config into the commons part
@@ -111,6 +113,8 @@ func EnsureCommons(cfg *config.Config) {
if cfg.OcisURL != "" {
cfg.Commons.OcisURL = cfg.OcisURL
}
cfg.Commons.Reva = structs.CopyOrZeroValue(cfg.Reva)
}
// Validate checks that all required configs are set. If a required config value

View File

@@ -1,9 +1,7 @@
package oidc
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -15,10 +13,9 @@ import (
"sync"
"time"
"github.com/MicahParks/keyfunc"
"github.com/MicahParks/keyfunc/v2"
goidc "github.com/coreos/go-oidc/v3/oidc"
"github.com/go-jose/go-jose/v3"
"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
"golang.org/x/oauth2"
@@ -95,6 +92,7 @@ func NewOIDCClient(opts ...Option) OIDCClient {
httpClient: options.HTTPClient,
accessTokenVerifyMethod: options.AccessTokenVerifyMethod,
JWKSOptions: options.JWKSOptions, // TODO I don't like that we pass down config options ...
JWKS: options.JWKS,
providerLock: &sync.Mutex{},
jwksLock: &sync.Mutex{},
remoteKeySet: options.KeySet,
@@ -296,7 +294,14 @@ func (c *oidcClient) verifyAccessTokenJWT(token string) (RegClaimsWithSID, jwt.M
return claims, mapClaims, errors.New("error initializing jwks keyfunc")
}
_, err := jwt.ParseWithClaims(token, &claims, jwks.Keyfunc)
issuer := c.issuer
if c.provider.AccessTokenIssuer != "" {
// AD FS .well-known/openid-configuration has an optional `access_token_issuer` which takes precedence over `issuer`
// See https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-oidce/586de7dd-3385-47c7-93a2-935d9e90441c
issuer = c.provider.AccessTokenIssuer
}
_, err := jwt.ParseWithClaims(token, &claims, jwks.Keyfunc, jwt.WithIssuer(issuer))
if err != nil {
return claims, mapClaims, err
}
@@ -308,93 +313,50 @@ func (c *oidcClient) verifyAccessTokenJWT(token string) (RegClaimsWithSID, jwt.M
return claims, mapClaims, err
}
issuer := c.issuer
if c.provider.AccessTokenIssuer != "" {
// AD FS .well-known/openid-configuration has an optional `access_token_issuer` which takes precedence over `issuer`
// See https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-oidce/586de7dd-3385-47c7-93a2-935d9e90441c
issuer = c.provider.AccessTokenIssuer
}
if !claims.VerifyIssuer(issuer, true) {
vErr := jwt.ValidationError{}
vErr.Inner = jwt.ErrTokenInvalidIssuer
vErr.Errors |= jwt.ValidationErrorIssuer
return claims, mapClaims, vErr
}
return claims, mapClaims, nil
}
func (c *oidcClient) VerifyLogoutToken(ctx context.Context, rawToken string) (*LogoutToken, error) {
var claims LogoutToken
if err := c.lookupWellKnownOpenidConfiguration(ctx); err != nil {
return nil, err
}
jws, err := jose.ParseSigned(rawToken)
if err != nil {
return nil, err
}
// Throw out tokens with invalid claims before trying to verify the token. This lets
// us do cheap checks before possibly re-syncing keys.
payload, err := parseJWT(rawToken)
if err != nil {
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
}
var token LogoutToken
if err := json.Unmarshal(payload, &token); err != nil {
return nil, fmt.Errorf("oidc: failed to unmarshal claims: %v", err)
jwks := c.getKeyfunc()
if jwks == nil {
return nil, errors.New("error initializing jwks keyfunc")
}
//4. Verify that the Logout Token contains a sub Claim, a sid Claim, or both.
if token.Subject == "" && token.SessionId == "" {
return nil, fmt.Errorf("oidc: logout token must contain either sub or sid and MAY contain both")
}
//5. Verify that the Logout Token contains an events Claim whose value is JSON object containing the member name http://schemas.openid.net/event/backchannel-logout.
if token.Events.Event == nil {
return nil, fmt.Errorf("oidc: logout token must contain logout event")
}
//6. Verify that the Logout Token does not contain a nonce Claim.
var n struct {
Nonce *string `json:"nonce"`
}
json.Unmarshal(payload, &n)
if n.Nonce != nil {
return nil, fmt.Errorf("oidc: nonce on logout token MUST NOT be present")
}
// Check issuer.
if !c.skipIssuerValidation && token.Issuer != c.issuer {
return nil, fmt.Errorf("oidc: logout token issued by a different provider, expected %q got %q", c.issuer, token.Issuer)
}
switch len(jws.Signatures) {
case 0:
return nil, fmt.Errorf("oidc: logout token not signed")
case 1:
// do nothing
default:
return nil, fmt.Errorf("oidc: multiple signatures on logout token not supported")
}
sig := jws.Signatures[0]
// From the backchannel-logout spec: Like ID Tokens, selection of the
// algorithm used is governed by the id_token_signing_alg_values_supported
// Discovery parameter and the id_token_signed_response_alg Registration
// parameter when they are used; otherwise, the value SHOULD be the default
// of RS256
supportedSigAlgs := c.algorithms
if len(supportedSigAlgs) == 0 {
supportedSigAlgs = []string{RS256}
}
if !contains(supportedSigAlgs, sig.Header.Algorithm) {
return nil, fmt.Errorf("oidc: logout token signed with unsupported algorithm, expected %q got %q", supportedSigAlgs, sig.Header.Algorithm)
}
gotPayload, err := c.remoteKeySet.VerifySignature(goidc.ClientContext(ctx, c.httpClient), rawToken)
_, err := jwt.ParseWithClaims(rawToken, &claims, jwks.Keyfunc, jwt.WithValidMethods(supportedSigAlgs), jwt.WithIssuer(c.issuer))
if err != nil {
return nil, fmt.Errorf("failed to verify signature: %v", err)
c.Logger.Debug().Err(err).Msg("Failed to parse logout token")
return nil, err
}
// Basic token validation has happened in ParseWithClaims (signature,
// issuer, audience, ...). Now for some logout token specific checks.
// 1. Verify that the Logout Token contains a sub Claim, a sid Claim, or both.
if claims.Subject == "" && claims.SessionId == "" {
return nil, fmt.Errorf("oidc: logout token must contain either sub or sid and MAY contain both")
}
// 2. Verify that the Logout Token contains an events Claim whose value is JSON object containing the member name http://schemas.openid.net/event/backchannel-logout.
if claims.Events.Event == nil {
return nil, fmt.Errorf("oidc: logout token must contain logout event")
}
// 3. Verify that the Logout Token does not contain a nonce Claim.
if claims.Nonce != nil {
return nil, fmt.Errorf("oidc: nonce on logout token MUST NOT be present")
}
// Ensure that the payload returned by the square actually matches the payload parsed earlier.
if !bytes.Equal(gotPayload, payload) {
return nil, errors.New("oidc: internal error, payload parsed did not match previous payload")
}
return &token, nil
return &claims, nil
}
func unmarshalResp(r *http.Response, body []byte, v interface{}) error {
@@ -409,24 +371,3 @@ func unmarshalResp(r *http.Response, body []byte, v interface{}) error {
}
return fmt.Errorf("expected Content-Type = application/json, got %q: %v", ct, err)
}
func contains(sli []string, ele string) bool {
for _, s := range sli {
if s == ele {
return true
}
}
return false
}
func parseJWT(p string) ([]byte, error) {
parts := strings.Split(p, ".")
if len(parts) < 2 {
return nil, fmt.Errorf("oidc: malformed jwt, expected 3 parts got %d", len(parts))
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("oidc: malformed jwt payload: %v", err)
}
return payload, nil
}

View File

@@ -2,152 +2,124 @@ package oidc_test
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"fmt"
"testing"
goidc "github.com/coreos/go-oidc/v3/oidc"
"github.com/go-jose/go-jose/v3"
"github.com/MicahParks/keyfunc/v2"
"github.com/golang-jwt/jwt/v5"
"github.com/owncloud/ocis/v2/ocis-pkg/oidc"
)
type signingKey struct {
keyID string // optional
priv interface{}
pub interface{}
alg jose.SignatureAlgorithm
}
// sign creates a JWS using the private key from the provided payload.
func (s *signingKey) sign(t testing.TB, payload []byte) string {
privKey := &jose.JSONWebKey{Key: s.priv, Algorithm: string(s.alg), KeyID: s.keyID}
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: s.alg, Key: privKey}, nil)
if err != nil {
t.Fatal(err)
}
jws, err := signer.Sign(payload)
if err != nil {
t.Fatal(err)
}
data, err := jws.CompactSerialize()
if err != nil {
t.Fatal(err)
}
return data
}
func (s *signingKey) jwk() jose.JSONWebKey {
return jose.JSONWebKey{Key: s.pub, Use: "sig", Algorithm: string(s.alg), KeyID: s.keyID}
priv interface{}
jwks *keyfunc.JWKS
}
func TestLogoutVerify(t *testing.T) {
tests := []logoutVerificationTest{
{
name: "good token",
logoutToken: ` {
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": {
"http://schemas.openid.net/event/backchannel-logout": {}
}
}`,
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
},
{
name: "invalid issuer",
issuer: "https://bar",
logoutToken: `{"iss":"https://foo"}`,
config: goidc.Config{
SkipExpiryCheck: true,
},
name: "invalid issuer",
issuer: "https://bar",
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo1",
"sub": "248289761001",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "invalid sig",
logoutToken: `{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": {
"http://schemas.openid.net/event/backchannel-logout": {}
}
}`,
config: goidc.Config{
SkipExpiryCheck: true,
},
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
verificationKey: newRSAKey(t),
wantErr: true,
},
{
name: "no sid and no sub",
logoutToken: ` {
"iss": "https://foo",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"events": {
"http://schemas.openid.net/event/backchannel-logout": {}
}
}`,
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "Prohibited nonce present",
logoutToken: ` {
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"nonce" : "prohibited",
"events": {
"http://schemas.openid.net/event/backchannel-logout": {}
}
}`,
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"nonce": "123",
"events": map[string]interface{}{
"http://schemas.openid.net/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "Wrong Event string",
logoutToken: ` {
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": {
"not a logout event": {}
}
}`,
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
"events": map[string]interface{}{
"http://blah.blah.blash/event/backchannel-logout": struct{}{},
},
}),
signKey: newRSAKey(t),
wantErr: true,
},
{
name: "No Event string",
logoutToken: ` {
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
}`,
logoutToken: jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"iss": "https://foo",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"iat": 1471566154,
"jti": "bWJq",
"sid": "08a5019c-17e1-4977-8f42-65a12843ea02",
}),
signKey: newRSAKey(t),
wantErr: true,
},
@@ -165,7 +137,7 @@ type logoutVerificationTest struct {
issuer string
// JWT payload (just the claims).
logoutToken string
logoutToken *jwt.Token
// Key to sign the ID Token with.
signKey *signingKey
@@ -173,40 +145,31 @@ type logoutVerificationTest struct {
// testing invalid signatures.
verificationKey *signingKey
config goidc.Config
wantErr bool
}
type testVerifier struct {
jwk jose.JSONWebKey
}
func (t *testVerifier) VerifySignature(ctx context.Context, jwt string) ([]byte, error) {
jws, err := jose.ParseSigned(jwt)
if err != nil {
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
}
return jws.Verify(&t.jwk)
}
func (v logoutVerificationTest) runGetToken(t *testing.T) (*oidc.LogoutToken, error) {
token := v.signKey.sign(t, []byte(v.logoutToken))
// token := v.signKey.sign(t, []byte(v.logoutToken))
v.logoutToken.Header["kid"] = "1"
token, err := v.logoutToken.SignedString(v.signKey.priv)
if err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
issuer := "https://foo"
var ks goidc.KeySet
var jwks *keyfunc.JWKS
if v.verificationKey == nil {
ks = &testVerifier{v.signKey.jwk()}
jwks = v.signKey.jwks
} else {
ks = &testVerifier{v.verificationKey.jwk()}
jwks = v.verificationKey.jwks
}
pm := oidc.ProviderMetadata{}
verifier := oidc.NewOIDCClient(
oidc.WithOidcIssuer(issuer),
oidc.WithKeySet(ks),
oidc.WithConfig(&v.config),
oidc.WithJWKS(jwks),
oidc.WithProviderMetadata(&pm),
)
@@ -228,13 +191,15 @@ func newRSAKey(t testing.TB) *signingKey {
if err != nil {
t.Fatal(err)
}
return &signingKey{"", priv, priv.Public(), jose.RS256}
}
givenKey := keyfunc.NewGivenRSA(
&priv.PublicKey,
keyfunc.GivenKeyOptions{Algorithm: jwt.SigningMethodRS256.Alg()},
)
jwks := keyfunc.NewGiven(
map[string]keyfunc.GivenKey{
"1": givenKey,
},
)
func newECDSAKey(t *testing.T) *signingKey {
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
return &signingKey{"", priv, priv.Public(), jose.ES256}
return &signingKey{priv, jwks}
}

View File

@@ -6,7 +6,7 @@ import (
"net/http"
"strings"
"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
)
@@ -59,35 +59,12 @@ type ProviderMetadata struct {
// Logout Token defines an logout Token
type LogoutToken struct {
// The URL of the server which issued this token. OpenID Connect
// requires this value always be identical to the URL used for
// initial discovery.
//
// Note: Because of a known issue with Google Accounts' implementation
// this value may differ when using Google.
//
// See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
Issuer string `json:"iss"` // example "https://server.example.com"
// A unique string which identifies the end user.
Subject string `json:"sub"` //"248289761001"
// The client ID, or set of client IDs, that this token is issued for. For
// common uses, this is the client that initialized the auth flow.
//
// This package ensures the audience contains an expected value.
Audience jwt.ClaimStrings `json:"aud"` // "s6BhdRkqt3"
// When the token was issued by the provider.
IssuedAt *jwt.NumericDate `json:"iat"`
jwt.RegisteredClaims
// The Session Id
SessionId string `json:"sid"`
Events LogoutEvent `json:"events"`
// Jwt Id
JwtID string `json:"jti"`
SessionId string `json:"sid"`
Events LogoutEvent `json:"events"`
// Note: This is just here to be able to check for nonce being absent
Nonce *string `json:"nonce"`
}
// LogoutEvent defines a logout Event

View File

@@ -1,11 +1,11 @@
// Code generated by mockery v2.40.2. DO NOT EDIT.
// Code generated by mockery v2.43.2. DO NOT EDIT.
package mocks
import (
context "context"
jwt "github.com/golang-jwt/jwt/v4"
jwt "github.com/golang-jwt/jwt/v5"
mock "github.com/stretchr/testify/mock"
oauth2 "golang.org/x/oauth2"

View File

@@ -3,6 +3,7 @@ package oidc
import (
"net/http"
"github.com/MicahParks/keyfunc/v2"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
@@ -22,7 +23,14 @@ type Options struct {
OIDCIssuer string
// JWKSOptions to use when retrieving keys
JWKSOptions config.JWKS
// KeySet to use when verifiing signatures
// the JWKS keyset to use for verifying signatures of Access- and
// Logout-Tokens
// this option is mostly needed for unit test. To avoid fetching the keys
// from the issuer
JWKS *keyfunc.JWKS
// KeySet to use when verifiing signatures of jwt encoded
// user info responses
// TODO move userinfo verification to use jwt/keyfunc as well
KeySet KeySet
// AccessTokenVerifyMethod to use when verifying access tokens
// TODO pass a function or interface to verify? an AccessTokenVerifier?
@@ -80,6 +88,13 @@ func WithJWKSOptions(val config.JWKS) Option {
}
}
// WithJWKS provides a function to set the JWKS option (mainly useful for testing).
func WithJWKS(val *keyfunc.JWKS) Option {
return func(o *Options) {
o.JWKS = val
}
}
// WithKeySet provides a function to set the KeySet option.
func WithKeySet(val KeySet) Option {
return func(o *Options) {

View File

@@ -8,10 +8,10 @@ import (
mRegistry "go-micro.dev/v4/registry"
"go-micro.dev/v4/server"
"go-micro.dev/v4/util/addr"
mAddr "go-micro.dev/v4/util/addr"
)
func BuildGRPCService(serviceID, address string, version string) *mRegistry.Service {
func BuildGRPCService(serviceID, transport, address, version string) *mRegistry.Service {
var host string
var port int
@@ -23,20 +23,25 @@ func BuildGRPCService(serviceID, address string, version string) *mRegistry.Serv
host = parts[0]
}
addr, err := addr.Extract(host)
if err != nil {
addr = host
addr := host
if transport != "unix" {
var err error
addr, err = mAddr.Extract(host)
if err != nil {
addr = host
}
addr = net.JoinHostPort(addr, strconv.Itoa(port))
}
node := &mRegistry.Node{
Id: serviceID + "-" + server.DefaultId,
Address: net.JoinHostPort(addr, fmt.Sprint(port)),
Address: addr,
Metadata: make(map[string]string),
}
node.Metadata["registry"] = GetRegistry().String()
node.Metadata["server"] = "grpc"
node.Metadata["transport"] = "grpc"
node.Metadata["transport"] = transport
node.Metadata["protocol"] = "grpc"
return &mRegistry.Service{
@@ -59,7 +64,7 @@ func BuildHTTPService(serviceID, address string, version string) *mRegistry.Serv
host = parts[0]
}
addr, err := addr.Extract(host)
addr, err := mAddr.Extract(host)
if err != nil {
addr = host
}

View File

@@ -89,6 +89,8 @@ Do not remove any revisions but print the revisions that would be removed.
Allows specifying the blobstore to use. Defaults to `ocis`. Can be switched to `s3ng` but needs addtional envvar configuration (see the `storage-users` service for more details).
* `-v` / `--verbose`\
Prints additional information about the revisions that are removed.
* `--glob-mechanism` (default: `glob`\
(advanced) Allows specifying the mechanism to use for globbing. Can be `glob`, `list` or `workers`. In most cases the default `glob` does not need to be changed. If large spaces need to be purged, `list` or `workers` can be used to improve performance at the cost of higher cpu and ram usage. `list` will spawn 10 threads that list folder contents in parallel. `workers` will use a special globbing mechanism and multiple threads to achieve the best performance for the highest cost.
### Trash CLI

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"path/filepath"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
ocisbs "github.com/cs3org/reva/v2/pkg/storage/fs/ocis/blobstore"
"github.com/cs3org/reva/v2/pkg/storage/fs/posix/lookup"
s3bs "github.com/cs3org/reva/v2/pkg/storage/fs/s3ng/blobstore"
@@ -19,7 +20,7 @@ import (
var (
// _nodesGlobPattern is the glob pattern to find all nodes
_nodesGlobPattern = "spaces/*/*/*/*/*/*/*/*"
_nodesGlobPattern = "spaces/*/*/nodes/"
)
// RevisionsCommand is the entrypoint for the revisions command.
@@ -30,7 +31,7 @@ func RevisionsCommand(cfg *config.Config) *cli.Command {
Subcommands: []*cli.Command{
PurgeRevisionsCommand(cfg),
},
Before: func(c *cli.Context) error {
Before: func(_ *cli.Context) error {
return configlog.ReturnError(parser.ParseConfig(cfg, true))
},
Action: func(_ *cli.Context) error {
@@ -74,6 +75,11 @@ func PurgeRevisionsCommand(cfg *config.Config) *cli.Command {
Aliases: []string{"r"},
Usage: "purge all revisions of this file/space. If not set, all revisions will be purged",
},
&cli.StringFlag{
Name: "glob-mechanism",
Usage: "the glob mechanism to find all nodes. Can be 'glob', 'list' or 'workers'. 'glob' uses globbing with a single worker. 'workers' spawns multiple go routines, accelatering the command drastically but causing high cpu and ram usage. 'list' looks for references by listing directories with multiple workers. Default is 'glob'",
Value: "glob",
},
},
Action: func(c *cli.Context) error {
basePath := c.String("basepath")
@@ -108,43 +114,72 @@ func PurgeRevisionsCommand(cfg *config.Config) *cli.Command {
return err
}
p, err := generatePath(basePath, c.String("resource-id"))
if err != nil {
fmt.Printf("❌ Error parsing resourceID: %s", err)
return err
var rid *provider.ResourceId
resid, err := storagespace.ParseID(c.String("resource-id"))
if err == nil {
rid = &resid
}
if err := revisions.PurgeRevisions(p, bs, c.Bool("dry-run"), c.Bool("verbose")); err != nil {
fmt.Printf("❌ Error purging revisions: %s", err)
return err
mechanism := c.String("glob-mechanism")
if rid.GetOpaqueId() != "" {
mechanism = "glob"
}
var ch <-chan string
switch mechanism {
default:
fallthrough
case "glob":
p := generatePath(basePath, rid)
if rid.GetOpaqueId() == "" {
p = filepath.Join(p, "*/*/*/*/*")
}
ch = revisions.Glob(p)
case "workers":
p := generatePath(basePath, rid)
ch = revisions.GlobWorkers(p, "/*", "/*/*/*/*")
case "list":
p := filepath.Join(basePath, "spaces")
if rid != nil {
p = generatePath(basePath, rid)
}
ch = revisions.List(p, 10)
}
files, blobs, revisions := revisions.PurgeRevisions(ch, bs, c.Bool("dry-run"), c.Bool("verbose"))
printResults(files, blobs, revisions, c.Bool("dry-run"))
return nil
},
}
}
func generatePath(basePath string, resourceID string) (string, error) {
if resourceID == "" {
return filepath.Join(basePath, _nodesGlobPattern), nil
func printResults(countFiles, countBlobs, countRevisions int, dryRun bool) {
switch {
case countFiles == 0 && countRevisions == 0 && countBlobs == 0:
fmt.Println("❎ No revisions found. Storage provider is clean.")
case !dryRun:
fmt.Printf("✅ Deleted %d revisions (%d files / %d blobs)\n", countRevisions, countFiles, countBlobs)
default:
fmt.Printf("👉 Would delete %d revisions (%d files / %d blobs)\n", countRevisions, countFiles, countBlobs)
}
}
rid, err := storagespace.ParseID(resourceID)
if err != nil {
return "", err
func generatePath(basePath string, rid *provider.ResourceId) string {
if rid == nil {
return filepath.Join(basePath, _nodesGlobPattern)
}
sid := lookup.Pathify(rid.GetSpaceId(), 1, 2)
if sid == "" {
sid = "*/*"
return ""
}
nid := lookup.Pathify(rid.GetOpaqueId(), 4, 2)
if nid == "" {
nid = "*/*/*/*/"
return filepath.Join(basePath, "spaces", sid, "nodes")
}
return filepath.Join(basePath, "spaces", sid, "nodes", nid+"*"), nil
return filepath.Join(basePath, "spaces", sid, "nodes", nid+"*")
}
func init() {

View File

@@ -44,7 +44,6 @@ import (
storageshares "github.com/owncloud/ocis/v2/services/storage-shares/pkg/command"
storagesystem "github.com/owncloud/ocis/v2/services/storage-system/pkg/command"
storageusers "github.com/owncloud/ocis/v2/services/storage-users/pkg/command"
store "github.com/owncloud/ocis/v2/services/store/pkg/command"
thumbnails "github.com/owncloud/ocis/v2/services/thumbnails/pkg/command"
userlog "github.com/owncloud/ocis/v2/services/userlog/pkg/command"
users "github.com/owncloud/ocis/v2/services/users/pkg/command"
@@ -234,11 +233,6 @@ var svccmds = []register.Command{
cfg.StorageUsers.Commons = cfg.Commons
})
},
func(cfg *config.Config) *cli.Command {
return ServiceCommand(cfg, cfg.Store.Service.Name, store.GetCommands(cfg.Store), func(c *config.Config) {
cfg.Store.Commons = cfg.Commons
})
},
func(cfg *config.Config) *cli.Command {
return ServiceCommand(cfg, cfg.Thumbnails.Service.Name, thumbnails.GetCommands(cfg.Thumbnails), func(c *config.Config) {
cfg.Thumbnails.Commons = cfg.Commons

View File

@@ -2,12 +2,12 @@
package revisions
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"sync"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
"github.com/shamaton/msgpack/v2"
@@ -26,25 +26,121 @@ type DelBlobstore interface {
Delete(node *node.Node) error
}
// Glob uses globbing to find all revision nodes in a storage provider.
func Glob(pattern string) <-chan string {
ch := make(chan string)
go func() {
defer close(ch)
nodes, err := filepath.Glob(filepath.Join(pattern))
if err != nil {
fmt.Println("error globbing", pattern, err)
return
}
if len(nodes) == 0 {
fmt.Println("no nodes found. Double check storage path")
return
}
for _, n := range nodes {
if _versionRegex.MatchString(n) {
ch <- n
}
}
}()
return ch
}
// GlobWorkers uses multiple go routine to glob all revision nodes in a storage provider.
func GlobWorkers(pattern string, depth string, remainder string) <-chan string {
wg := sync.WaitGroup{}
ch := make(chan string)
go func() {
defer close(ch)
nodes, err := filepath.Glob(pattern + depth)
if err != nil {
fmt.Println("error globbing", pattern, err)
return
}
if len(nodes) == 0 {
fmt.Println("no nodes found. Double check storage path")
return
}
for _, node := range nodes {
wg.Add(1)
go func(node string) {
defer wg.Done()
nodes, err := filepath.Glob(node + remainder)
if err != nil {
fmt.Println("error globbing", node, err)
return
}
for _, n := range nodes {
if _versionRegex.MatchString(n) {
ch <- n
}
}
}(node)
}
wg.Wait()
}()
return ch
}
// Walk walks the storage provider to find all revision nodes.
func Walk(base string) <-chan string {
ch := make(chan string)
go func() {
defer close(ch)
err := filepath.Walk(base, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Println("error walking", base, err)
return err
}
if !_versionRegex.MatchString(info.Name()) {
return nil
}
ch <- path
return nil
})
if err != nil {
fmt.Println("error walking", base, err)
return
}
}()
return ch
}
// List uses directory listing to find all revision nodes in a storage provider.
func List(base string, workers int) <-chan string {
ch := make(chan string)
go func() {
defer close(ch)
if err := listFolder(base, ch, make(chan struct{}, workers)); err != nil {
fmt.Println("error listing", base, err)
return
}
}()
return ch
}
// PurgeRevisions removes all revisions from a storage provider.
func PurgeRevisions(pattern string, bs DelBlobstore, dryRun bool, verbose bool) error {
if verbose {
fmt.Println("Looking for nodes in", pattern)
}
nodes, err := filepath.Glob(pattern)
if err != nil {
return err
}
if len(nodes) == 0 {
return errors.New("no nodes found, double check storage path")
}
func PurgeRevisions(nodes <-chan string, bs DelBlobstore, dryRun, verbose bool) (int, int, int) {
countFiles := 0
countBlobs := 0
countRevisions := 0
for _, d := range nodes {
var err error
for d := range nodes {
if !_versionRegex.MatchString(d) {
continue
}
@@ -106,14 +202,37 @@ func PurgeRevisions(pattern string, bs DelBlobstore, dryRun bool, verbose bool)
}
}
switch {
case countFiles == 0 && countRevisions == 0 && countBlobs == 0:
fmt.Println("❎ No revisions found. Storage provider is clean.")
case !dryRun:
fmt.Printf("✅ Deleted %d revisions (%d files / %d blobs)\n", countRevisions, countFiles, countBlobs)
default:
fmt.Printf("👉 Would delete %d revisions (%d files / %d blobs)\n", countRevisions, countFiles, countBlobs)
return countFiles, countBlobs, countRevisions
}
func listFolder(path string, ch chan<- string, workers chan struct{}) error {
workers <- struct{}{}
wg := sync.WaitGroup{}
children, err := os.ReadDir(path)
if err != nil {
<-workers
return err
}
for _, child := range children {
if child.IsDir() {
wg.Add(1)
go func() {
defer wg.Done()
if err := listFolder(filepath.Join(path, child.Name()), ch, workers); err != nil {
fmt.Println("error listing", path, err)
}
}()
}
if _versionRegex.MatchString(child.Name()) {
ch <- filepath.Join(path, child.Name())
}
}
<-workers
wg.Wait()
return nil
}

View File

@@ -0,0 +1,170 @@
package revisions
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strconv"
"testing"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/lookup"
"github.com/google/uuid"
"github.com/test-go/testify/require"
)
var (
_basePath = "/spaces/8f/638374-6ea8-4f0d-80c4-66d9b49830a5/nodes/"
)
// func TestInit(t *testing.T) {
// initialize(10, 2)
// defer os.RemoveAll("test_temp")
// }
func TestGlob30(t *testing.T) { test(t, 10, 2, glob) }
func TestGlob80(t *testing.T) { test(t, 20, 3, glob) }
func TestGlob250(t *testing.T) { test(t, 50, 4, glob) }
func TestGlob600(t *testing.T) { test(t, 100, 5, glob) }
func TestWalk30(t *testing.T) { test(t, 10, 2, walk) }
func TestWalk80(t *testing.T) { test(t, 20, 3, walk) }
func TestWalk250(t *testing.T) { test(t, 50, 4, walk) }
func TestWalk600(t *testing.T) { test(t, 100, 5, walk) }
func TestList30(t *testing.T) { test(t, 10, 2, list2) }
func TestList80(t *testing.T) { test(t, 20, 3, list10) }
func TestList250(t *testing.T) { test(t, 50, 4, list20) }
func TestList600(t *testing.T) { test(t, 100, 5, list2) }
func TestGlobWorkers30(t *testing.T) { test(t, 10, 2, globWorkersD1) }
func TestGlobWorkers80(t *testing.T) { test(t, 20, 3, globWorkersD2) }
func TestGlobWorkers250(t *testing.T) { test(t, 50, 4, globWorkersD4) }
func TestGlobWorkers600(t *testing.T) { test(t, 100, 5, globWorkersD2) }
func BenchmarkGlob30(b *testing.B) { benchmark(b, 10, 2, glob) }
func BenchmarkWalk30(b *testing.B) { benchmark(b, 10, 2, walk) }
func BenchmarkList30(b *testing.B) { benchmark(b, 10, 2, list2) }
func BenchmarkGlobWorkers30(b *testing.B) { benchmark(b, 10, 2, globWorkersD2) }
func BenchmarkGlob80(b *testing.B) { benchmark(b, 20, 3, glob) }
func BenchmarkWalk80(b *testing.B) { benchmark(b, 20, 3, walk) }
func BenchmarkList80(b *testing.B) { benchmark(b, 20, 3, list2) }
func BenchmarkGlobWorkers80(b *testing.B) { benchmark(b, 20, 3, globWorkersD2) }
func BenchmarkGlob250(b *testing.B) { benchmark(b, 50, 4, glob) }
func BenchmarkWalk250(b *testing.B) { benchmark(b, 50, 4, walk) }
func BenchmarkList250(b *testing.B) { benchmark(b, 50, 4, list2) }
func BenchmarkGlobWorkers250(b *testing.B) { benchmark(b, 50, 4, globWorkersD2) }
func BenchmarkGlobAT600(b *testing.B) { benchmark(b, 100, 5, glob) }
func BenchmarkWalkAT600(b *testing.B) { benchmark(b, 100, 5, walk) }
func BenchmarkList2AT600(b *testing.B) { benchmark(b, 100, 5, list2) }
func BenchmarkList10AT600(b *testing.B) { benchmark(b, 100, 5, list10) }
func BenchmarkList20AT600(b *testing.B) { benchmark(b, 100, 5, list20) }
func BenchmarkGlobWorkersD1AT600(b *testing.B) { benchmark(b, 100, 5, globWorkersD1) }
func BenchmarkGlobWorkersD2AT600(b *testing.B) { benchmark(b, 100, 5, globWorkersD2) }
func BenchmarkGlobWorkersD4AT600(b *testing.B) { benchmark(b, 100, 5, globWorkersD4) }
func BenchmarkGlobAT22000(b *testing.B) { benchmark(b, 2000, 10, glob) }
func BenchmarkWalkAT22000(b *testing.B) { benchmark(b, 2000, 10, walk) }
func BenchmarkList2AT22000(b *testing.B) { benchmark(b, 2000, 10, list2) }
func BenchmarkList10AT22000(b *testing.B) { benchmark(b, 2000, 10, list10) }
func BenchmarkList20AT22000(b *testing.B) { benchmark(b, 2000, 10, list20) }
func BenchmarkGlobWorkersD1AT22000(b *testing.B) { benchmark(b, 2000, 10, globWorkersD1) }
func BenchmarkGlobWorkersD2AT22000(b *testing.B) { benchmark(b, 2000, 10, globWorkersD2) }
func BenchmarkGlobWorkersD4AT22000(b *testing.B) { benchmark(b, 2000, 10, globWorkersD4) }
func BenchmarkGlob110000(b *testing.B) { benchmark(b, 10000, 10, glob) }
func BenchmarkWalk110000(b *testing.B) { benchmark(b, 10000, 10, walk) }
func BenchmarkList110000(b *testing.B) { benchmark(b, 10000, 10, list2) }
func BenchmarkGlobWorkers110000(b *testing.B) { benchmark(b, 10000, 10, globWorkersD2) }
func benchmark(b *testing.B, numNodes int, numRevisions int, f func(string) <-chan string) {
base := initialize(numNodes, numRevisions)
defer os.RemoveAll(base)
b.ResetTimer()
for i := 0; i < b.N; i++ {
ch := f(base)
PurgeRevisions(ch, nil, false, false)
}
b.StopTimer()
}
func test(t *testing.T, numNodes int, numRevisions int, f func(string) <-chan string) {
base := initialize(numNodes, numRevisions)
defer os.RemoveAll(base)
ch := f(base)
_, _, revisions := PurgeRevisions(ch, nil, false, false)
require.Equal(t, numNodes*numRevisions, revisions, "Deleted Revisions")
}
func glob(base string) <-chan string {
return Glob(base + _basePath + "*/*/*/*/*")
}
func walk(base string) <-chan string {
return Walk(base + _basePath)
}
func list2(base string) <-chan string {
return List(base+_basePath, 2)
}
func list10(base string) <-chan string {
return List(base+_basePath, 10)
}
func list20(base string) <-chan string {
return List(base+_basePath, 20)
}
func globWorkersD1(base string) <-chan string {
return GlobWorkers(base+_basePath, "*", "/*/*/*/*")
}
func globWorkersD2(base string) <-chan string {
return GlobWorkers(base+_basePath, "*/*", "/*/*/*")
}
func globWorkersD4(base string) <-chan string {
return GlobWorkers(base+_basePath, "*/*/*/*", "/*")
}
func initialize(numNodes int, numRevisions int) string {
base := "test_temp_" + uuid.New().String()
if err := os.Mkdir(base, os.ModePerm); err != nil {
fmt.Println("Error creating test_temp directory", err)
os.RemoveAll(base)
os.Exit(1)
}
// create base path
if err := os.MkdirAll(base+_basePath, fs.ModePerm); err != nil {
fmt.Println("Error creating base path", err)
os.RemoveAll(base)
os.Exit(1)
}
for i := 0; i < numNodes; i++ {
path := lookup.Pathify(uuid.New().String(), 4, 2)
dir := filepath.Dir(path)
if err := os.MkdirAll(base+_basePath+dir, fs.ModePerm); err != nil {
fmt.Println("Error creating test_temp directory", err)
os.RemoveAll(base)
os.Exit(1)
}
if _, err := os.Create(base + _basePath + path); err != nil {
fmt.Println("Error creating file", err)
os.RemoveAll(base)
os.Exit(1)
}
for i := 0; i < numRevisions; i++ {
os.Create(base + _basePath + path + ".REV.2024-05-22T07:32:53.89969" + strconv.Itoa(i) + "Z")
}
}
return base
}

View File

@@ -526,7 +526,7 @@ func pingNats(cfg *ociscfg.Config) error {
return err
}
func pingGateway(_ *ociscfg.Config) error {
func pingGateway(cfg *ociscfg.Config) error {
// init grpc connection
_, err := ogrpc.NewClient()
if err != nil {
@@ -536,7 +536,7 @@ func pingGateway(_ *ociscfg.Config) error {
b := backoff.NewExponentialBackOff()
o := func() error {
n := b.NextBackOff()
_, err := pool.GetGatewayServiceClient("com.owncloud.api.gateway")
_, err := pool.GetGatewayServiceClient(cfg.Reva.Address)
if err != nil && n > time.Second {
logger.New().Error().Err(err).Msgf("can't connect to gateway service, retrying in %s", n)
}

View File

@@ -16,10 +16,6 @@ packages:
github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0:
interfaces:
ValueService:
github.com/owncloud/ocis/v2/protogen/gen/ocis/services/store/v0:
interfaces:
StoreService:
github.com/owncloud/ocis/v2/protogen/gen/ocis/services/thumbnails/v0:
interfaces:
ThumbnailService:

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.40.1. DO NOT EDIT.
// Code generated by mockery v2.43.2. DO NOT EDIT.
package mocks

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.40.1. DO NOT EDIT.
// Code generated by mockery v2.43.2. DO NOT EDIT.
package mocks

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.40.1. DO NOT EDIT.
// Code generated by mockery v2.43.2. DO NOT EDIT.
package mocks

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.40.1. DO NOT EDIT.
// Code generated by mockery v2.43.2. DO NOT EDIT.
package mocks

View File

@@ -1,484 +0,0 @@
// Code generated by mockery v2.40.1. DO NOT EDIT.
package mocks
import (
context "context"
client "go-micro.dev/v4/client"
mock "github.com/stretchr/testify/mock"
v0 "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/store/v0"
)
// StoreService is an autogenerated mock type for the StoreService type
type StoreService struct {
mock.Mock
}
type StoreService_Expecter struct {
mock *mock.Mock
}
func (_m *StoreService) EXPECT() *StoreService_Expecter {
return &StoreService_Expecter{mock: &_m.Mock}
}
// Databases provides a mock function with given fields: ctx, in, opts
func (_m *StoreService) Databases(ctx context.Context, in *v0.DatabasesRequest, opts ...client.CallOption) (*v0.DatabasesResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for Databases")
}
var r0 *v0.DatabasesResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *v0.DatabasesRequest, ...client.CallOption) (*v0.DatabasesResponse, error)); ok {
return rf(ctx, in, opts...)
}
if rf, ok := ret.Get(0).(func(context.Context, *v0.DatabasesRequest, ...client.CallOption) *v0.DatabasesResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0.DatabasesResponse)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *v0.DatabasesRequest, ...client.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StoreService_Databases_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Databases'
type StoreService_Databases_Call struct {
*mock.Call
}
// Databases is a helper method to define mock.On call
// - ctx context.Context
// - in *v0.DatabasesRequest
// - opts ...client.CallOption
func (_e *StoreService_Expecter) Databases(ctx interface{}, in interface{}, opts ...interface{}) *StoreService_Databases_Call {
return &StoreService_Databases_Call{Call: _e.mock.On("Databases",
append([]interface{}{ctx, in}, opts...)...)}
}
func (_c *StoreService_Databases_Call) Run(run func(ctx context.Context, in *v0.DatabasesRequest, opts ...client.CallOption)) *StoreService_Databases_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]client.CallOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(client.CallOption)
}
}
run(args[0].(context.Context), args[1].(*v0.DatabasesRequest), variadicArgs...)
})
return _c
}
func (_c *StoreService_Databases_Call) Return(_a0 *v0.DatabasesResponse, _a1 error) *StoreService_Databases_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *StoreService_Databases_Call) RunAndReturn(run func(context.Context, *v0.DatabasesRequest, ...client.CallOption) (*v0.DatabasesResponse, error)) *StoreService_Databases_Call {
_c.Call.Return(run)
return _c
}
// Delete provides a mock function with given fields: ctx, in, opts
func (_m *StoreService) Delete(ctx context.Context, in *v0.DeleteRequest, opts ...client.CallOption) (*v0.DeleteResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 *v0.DeleteResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *v0.DeleteRequest, ...client.CallOption) (*v0.DeleteResponse, error)); ok {
return rf(ctx, in, opts...)
}
if rf, ok := ret.Get(0).(func(context.Context, *v0.DeleteRequest, ...client.CallOption) *v0.DeleteResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0.DeleteResponse)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *v0.DeleteRequest, ...client.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StoreService_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete'
type StoreService_Delete_Call struct {
*mock.Call
}
// Delete is a helper method to define mock.On call
// - ctx context.Context
// - in *v0.DeleteRequest
// - opts ...client.CallOption
func (_e *StoreService_Expecter) Delete(ctx interface{}, in interface{}, opts ...interface{}) *StoreService_Delete_Call {
return &StoreService_Delete_Call{Call: _e.mock.On("Delete",
append([]interface{}{ctx, in}, opts...)...)}
}
func (_c *StoreService_Delete_Call) Run(run func(ctx context.Context, in *v0.DeleteRequest, opts ...client.CallOption)) *StoreService_Delete_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]client.CallOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(client.CallOption)
}
}
run(args[0].(context.Context), args[1].(*v0.DeleteRequest), variadicArgs...)
})
return _c
}
func (_c *StoreService_Delete_Call) Return(_a0 *v0.DeleteResponse, _a1 error) *StoreService_Delete_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *StoreService_Delete_Call) RunAndReturn(run func(context.Context, *v0.DeleteRequest, ...client.CallOption) (*v0.DeleteResponse, error)) *StoreService_Delete_Call {
_c.Call.Return(run)
return _c
}
// List provides a mock function with given fields: ctx, in, opts
func (_m *StoreService) List(ctx context.Context, in *v0.ListRequest, opts ...client.CallOption) (v0.Store_ListService, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for List")
}
var r0 v0.Store_ListService
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *v0.ListRequest, ...client.CallOption) (v0.Store_ListService, error)); ok {
return rf(ctx, in, opts...)
}
if rf, ok := ret.Get(0).(func(context.Context, *v0.ListRequest, ...client.CallOption) v0.Store_ListService); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(v0.Store_ListService)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *v0.ListRequest, ...client.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StoreService_List_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'List'
type StoreService_List_Call struct {
*mock.Call
}
// List is a helper method to define mock.On call
// - ctx context.Context
// - in *v0.ListRequest
// - opts ...client.CallOption
func (_e *StoreService_Expecter) List(ctx interface{}, in interface{}, opts ...interface{}) *StoreService_List_Call {
return &StoreService_List_Call{Call: _e.mock.On("List",
append([]interface{}{ctx, in}, opts...)...)}
}
func (_c *StoreService_List_Call) Run(run func(ctx context.Context, in *v0.ListRequest, opts ...client.CallOption)) *StoreService_List_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]client.CallOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(client.CallOption)
}
}
run(args[0].(context.Context), args[1].(*v0.ListRequest), variadicArgs...)
})
return _c
}
func (_c *StoreService_List_Call) Return(_a0 v0.Store_ListService, _a1 error) *StoreService_List_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *StoreService_List_Call) RunAndReturn(run func(context.Context, *v0.ListRequest, ...client.CallOption) (v0.Store_ListService, error)) *StoreService_List_Call {
_c.Call.Return(run)
return _c
}
// Read provides a mock function with given fields: ctx, in, opts
func (_m *StoreService) Read(ctx context.Context, in *v0.ReadRequest, opts ...client.CallOption) (*v0.ReadResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for Read")
}
var r0 *v0.ReadResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *v0.ReadRequest, ...client.CallOption) (*v0.ReadResponse, error)); ok {
return rf(ctx, in, opts...)
}
if rf, ok := ret.Get(0).(func(context.Context, *v0.ReadRequest, ...client.CallOption) *v0.ReadResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0.ReadResponse)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *v0.ReadRequest, ...client.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StoreService_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
type StoreService_Read_Call struct {
*mock.Call
}
// Read is a helper method to define mock.On call
// - ctx context.Context
// - in *v0.ReadRequest
// - opts ...client.CallOption
func (_e *StoreService_Expecter) Read(ctx interface{}, in interface{}, opts ...interface{}) *StoreService_Read_Call {
return &StoreService_Read_Call{Call: _e.mock.On("Read",
append([]interface{}{ctx, in}, opts...)...)}
}
func (_c *StoreService_Read_Call) Run(run func(ctx context.Context, in *v0.ReadRequest, opts ...client.CallOption)) *StoreService_Read_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]client.CallOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(client.CallOption)
}
}
run(args[0].(context.Context), args[1].(*v0.ReadRequest), variadicArgs...)
})
return _c
}
func (_c *StoreService_Read_Call) Return(_a0 *v0.ReadResponse, _a1 error) *StoreService_Read_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *StoreService_Read_Call) RunAndReturn(run func(context.Context, *v0.ReadRequest, ...client.CallOption) (*v0.ReadResponse, error)) *StoreService_Read_Call {
_c.Call.Return(run)
return _c
}
// Tables provides a mock function with given fields: ctx, in, opts
func (_m *StoreService) Tables(ctx context.Context, in *v0.TablesRequest, opts ...client.CallOption) (*v0.TablesResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for Tables")
}
var r0 *v0.TablesResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *v0.TablesRequest, ...client.CallOption) (*v0.TablesResponse, error)); ok {
return rf(ctx, in, opts...)
}
if rf, ok := ret.Get(0).(func(context.Context, *v0.TablesRequest, ...client.CallOption) *v0.TablesResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0.TablesResponse)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *v0.TablesRequest, ...client.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StoreService_Tables_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Tables'
type StoreService_Tables_Call struct {
*mock.Call
}
// Tables is a helper method to define mock.On call
// - ctx context.Context
// - in *v0.TablesRequest
// - opts ...client.CallOption
func (_e *StoreService_Expecter) Tables(ctx interface{}, in interface{}, opts ...interface{}) *StoreService_Tables_Call {
return &StoreService_Tables_Call{Call: _e.mock.On("Tables",
append([]interface{}{ctx, in}, opts...)...)}
}
func (_c *StoreService_Tables_Call) Run(run func(ctx context.Context, in *v0.TablesRequest, opts ...client.CallOption)) *StoreService_Tables_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]client.CallOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(client.CallOption)
}
}
run(args[0].(context.Context), args[1].(*v0.TablesRequest), variadicArgs...)
})
return _c
}
func (_c *StoreService_Tables_Call) Return(_a0 *v0.TablesResponse, _a1 error) *StoreService_Tables_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *StoreService_Tables_Call) RunAndReturn(run func(context.Context, *v0.TablesRequest, ...client.CallOption) (*v0.TablesResponse, error)) *StoreService_Tables_Call {
_c.Call.Return(run)
return _c
}
// Write provides a mock function with given fields: ctx, in, opts
func (_m *StoreService) Write(ctx context.Context, in *v0.WriteRequest, opts ...client.CallOption) (*v0.WriteResponse, error) {
_va := make([]interface{}, len(opts))
for _i := range opts {
_va[_i] = opts[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, in)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for Write")
}
var r0 *v0.WriteResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *v0.WriteRequest, ...client.CallOption) (*v0.WriteResponse, error)); ok {
return rf(ctx, in, opts...)
}
if rf, ok := ret.Get(0).(func(context.Context, *v0.WriteRequest, ...client.CallOption) *v0.WriteResponse); ok {
r0 = rf(ctx, in, opts...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v0.WriteResponse)
}
}
if rf, ok := ret.Get(1).(func(context.Context, *v0.WriteRequest, ...client.CallOption) error); ok {
r1 = rf(ctx, in, opts...)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StoreService_Write_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Write'
type StoreService_Write_Call struct {
*mock.Call
}
// Write is a helper method to define mock.On call
// - ctx context.Context
// - in *v0.WriteRequest
// - opts ...client.CallOption
func (_e *StoreService_Expecter) Write(ctx interface{}, in interface{}, opts ...interface{}) *StoreService_Write_Call {
return &StoreService_Write_Call{Call: _e.mock.On("Write",
append([]interface{}{ctx, in}, opts...)...)}
}
func (_c *StoreService_Write_Call) Run(run func(ctx context.Context, in *v0.WriteRequest, opts ...client.CallOption)) *StoreService_Write_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]client.CallOption, len(args)-2)
for i, a := range args[2:] {
if a != nil {
variadicArgs[i] = a.(client.CallOption)
}
}
run(args[0].(context.Context), args[1].(*v0.WriteRequest), variadicArgs...)
})
return _c
}
func (_c *StoreService_Write_Call) Return(_a0 *v0.WriteResponse, _a1 error) *StoreService_Write_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *StoreService_Write_Call) RunAndReturn(run func(context.Context, *v0.WriteRequest, ...client.CallOption) (*v0.WriteResponse, error)) *StoreService_Write_Call {
_c.Call.Return(run)
return _c
}
// NewStoreService creates a new instance of StoreService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewStoreService(t interface {
mock.TestingT
Cleanup(func())
}) *StoreService {
mock := &StoreService{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,929 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: ocis/services/store/v0/store.proto
package v0
import (
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
v0 "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/store/v0"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ReadRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Options *v0.ReadOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
}
func (x *ReadRequest) Reset() {
*x = ReadRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReadRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadRequest) ProtoMessage() {}
func (x *ReadRequest) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadRequest.ProtoReflect.Descriptor instead.
func (*ReadRequest) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{0}
}
func (x *ReadRequest) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *ReadRequest) GetOptions() *v0.ReadOptions {
if x != nil {
return x.Options
}
return nil
}
type ReadResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Records []*v0.Record `protobuf:"bytes,1,rep,name=records,proto3" json:"records,omitempty"`
}
func (x *ReadResponse) Reset() {
*x = ReadResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ReadResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ReadResponse) ProtoMessage() {}
func (x *ReadResponse) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ReadResponse.ProtoReflect.Descriptor instead.
func (*ReadResponse) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{1}
}
func (x *ReadResponse) GetRecords() []*v0.Record {
if x != nil {
return x.Records
}
return nil
}
type WriteRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Record *v0.Record `protobuf:"bytes,1,opt,name=record,proto3" json:"record,omitempty"`
Options *v0.WriteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
}
func (x *WriteRequest) Reset() {
*x = WriteRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *WriteRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WriteRequest) ProtoMessage() {}
func (x *WriteRequest) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WriteRequest.ProtoReflect.Descriptor instead.
func (*WriteRequest) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{2}
}
func (x *WriteRequest) GetRecord() *v0.Record {
if x != nil {
return x.Record
}
return nil
}
func (x *WriteRequest) GetOptions() *v0.WriteOptions {
if x != nil {
return x.Options
}
return nil
}
type WriteResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *WriteResponse) Reset() {
*x = WriteResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *WriteResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WriteResponse) ProtoMessage() {}
func (x *WriteResponse) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WriteResponse.ProtoReflect.Descriptor instead.
func (*WriteResponse) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{3}
}
type DeleteRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Options *v0.DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
}
func (x *DeleteRequest) Reset() {
*x = DeleteRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteRequest) ProtoMessage() {}
func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead.
func (*DeleteRequest) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{4}
}
func (x *DeleteRequest) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *DeleteRequest) GetOptions() *v0.DeleteOptions {
if x != nil {
return x.Options
}
return nil
}
type DeleteResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DeleteResponse) Reset() {
*x = DeleteResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DeleteResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DeleteResponse) ProtoMessage() {}
func (x *DeleteResponse) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead.
func (*DeleteResponse) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{5}
}
type ListRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Options *v0.ListOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"`
}
func (x *ListRequest) Reset() {
*x = ListRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListRequest) ProtoMessage() {}
func (x *ListRequest) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListRequest.ProtoReflect.Descriptor instead.
func (*ListRequest) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{6}
}
func (x *ListRequest) GetOptions() *v0.ListOptions {
if x != nil {
return x.Options
}
return nil
}
type ListResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Keys []string `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"`
}
func (x *ListResponse) Reset() {
*x = ListResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListResponse) ProtoMessage() {}
func (x *ListResponse) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ListResponse.ProtoReflect.Descriptor instead.
func (*ListResponse) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{7}
}
func (x *ListResponse) GetKeys() []string {
if x != nil {
return x.Keys
}
return nil
}
type DatabasesRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *DatabasesRequest) Reset() {
*x = DatabasesRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DatabasesRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DatabasesRequest) ProtoMessage() {}
func (x *DatabasesRequest) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DatabasesRequest.ProtoReflect.Descriptor instead.
func (*DatabasesRequest) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{8}
}
type DatabasesResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Databases []string `protobuf:"bytes,1,rep,name=databases,proto3" json:"databases,omitempty"`
}
func (x *DatabasesResponse) Reset() {
*x = DatabasesResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *DatabasesResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*DatabasesResponse) ProtoMessage() {}
func (x *DatabasesResponse) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use DatabasesResponse.ProtoReflect.Descriptor instead.
func (*DatabasesResponse) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{9}
}
func (x *DatabasesResponse) GetDatabases() []string {
if x != nil {
return x.Databases
}
return nil
}
type TablesRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Database string `protobuf:"bytes,1,opt,name=database,proto3" json:"database,omitempty"`
}
func (x *TablesRequest) Reset() {
*x = TablesRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TablesRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TablesRequest) ProtoMessage() {}
func (x *TablesRequest) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TablesRequest.ProtoReflect.Descriptor instead.
func (*TablesRequest) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{10}
}
func (x *TablesRequest) GetDatabase() string {
if x != nil {
return x.Database
}
return ""
}
type TablesResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Tables []string `protobuf:"bytes,1,rep,name=tables,proto3" json:"tables,omitempty"`
}
func (x *TablesResponse) Reset() {
*x = TablesResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TablesResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TablesResponse) ProtoMessage() {}
func (x *TablesResponse) ProtoReflect() protoreflect.Message {
mi := &file_ocis_services_store_v0_store_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TablesResponse.ProtoReflect.Descriptor instead.
func (*TablesResponse) Descriptor() ([]byte, []int) {
return file_ocis_services_store_v0_store_proto_rawDescGZIP(), []int{11}
}
func (x *TablesResponse) GetTables() []string {
if x != nil {
return x.Tables
}
return nil
}
var File_ocis_services_store_v0_store_proto protoreflect.FileDescriptor
var file_ocis_services_store_v0_store_proto_rawDesc = []byte{
0x0a, 0x22, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x1a, 0x22, 0x6f, 0x63,
0x69, 0x73, 0x2f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2f, 0x73, 0x74, 0x6f, 0x72,
0x65, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65,
0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61,
0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x5e, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x3d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x52, 0x65, 0x61, 0x64,
0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x22, 0x48, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x38, 0x0a, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72,
0x64, 0x52, 0x07, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x22, 0x86, 0x01, 0x0a, 0x0c, 0x57,
0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x36, 0x0a, 0x06, 0x72,
0x65, 0x63, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x6f, 0x63,
0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72,
0x65, 0x2e, 0x76, 0x30, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x06, 0x72, 0x65, 0x63,
0x6f, 0x72, 0x64, 0x12, 0x3e, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x57, 0x72,
0x69, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x62, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76,
0x30, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52,
0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4c, 0x0a, 0x0b, 0x4c, 0x69,
0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x07, 0x6f, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x6f, 0x63, 0x69,
0x73, 0x2e, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x2e, 0x76, 0x30, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52,
0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x28, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73,
0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x4a, 0x04, 0x08, 0x01,
0x10, 0x02, 0x22, 0x12, 0x0a, 0x10, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x31, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64,
0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09,
0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x22, 0x2b, 0x0a, 0x0d, 0x54, 0x61, 0x62,
0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x61,
0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x61,
0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x22, 0x28, 0x0a, 0x0e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x62, 0x6c,
0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73,
0x32, 0xa5, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x53, 0x0a, 0x04, 0x52, 0x65,
0x61, 0x64, 0x12, 0x23, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x52, 0x65, 0x61, 0x64,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30,
0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
0x56, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x24, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76,
0x30, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25,
0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x12, 0x25, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e,
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76,
0x30, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x12, 0x55, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x23, 0x2e, 0x6f, 0x63, 0x69,
0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65,
0x2e, 0x76, 0x30, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x24, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x62, 0x0a, 0x09, 0x44, 0x61, 0x74,
0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e,
0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x29, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61,
0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a,
0x06, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x25, 0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30,
0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26,
0x2e, 0x6f, 0x63, 0x69, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x30, 0x2e, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xd9, 0x02, 0x5a, 0x3b, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64,
0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67,
0x65, 0x6e, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f,
0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x30, 0x92, 0x41, 0x98, 0x02, 0x12, 0xb3, 0x01, 0x0a,
0x1d, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69,
0x74, 0x65, 0x20, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, 0x47,
0x0a, 0x0d, 0x6f, 0x77, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x12,
0x20, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69,
0x73, 0x1a, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x6f, 0x77, 0x6e, 0x63, 0x6c,
0x6f, 0x75, 0x64, 0x2e, 0x63, 0x6f, 0x6d, 0x2a, 0x42, 0x0a, 0x0a, 0x41, 0x70, 0x61, 0x63, 0x68,
0x65, 0x2d, 0x32, 0x2e, 0x30, 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f,
0x75, 0x64, 0x2f, 0x6f, 0x63, 0x69, 0x73, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73,
0x74, 0x65, 0x72, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30,
0x2e, 0x30, 0x2a, 0x02, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x38, 0x0a, 0x10, 0x44, 0x65,
0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x12, 0x24,
0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x6f, 0x77, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64,
0x2e, 0x64, 0x65, 0x76, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x74,
0x6f, 0x72, 0x65, 0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_ocis_services_store_v0_store_proto_rawDescOnce sync.Once
file_ocis_services_store_v0_store_proto_rawDescData = file_ocis_services_store_v0_store_proto_rawDesc
)
func file_ocis_services_store_v0_store_proto_rawDescGZIP() []byte {
file_ocis_services_store_v0_store_proto_rawDescOnce.Do(func() {
file_ocis_services_store_v0_store_proto_rawDescData = protoimpl.X.CompressGZIP(file_ocis_services_store_v0_store_proto_rawDescData)
})
return file_ocis_services_store_v0_store_proto_rawDescData
}
var file_ocis_services_store_v0_store_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
var file_ocis_services_store_v0_store_proto_goTypes = []interface{}{
(*ReadRequest)(nil), // 0: ocis.services.store.v0.ReadRequest
(*ReadResponse)(nil), // 1: ocis.services.store.v0.ReadResponse
(*WriteRequest)(nil), // 2: ocis.services.store.v0.WriteRequest
(*WriteResponse)(nil), // 3: ocis.services.store.v0.WriteResponse
(*DeleteRequest)(nil), // 4: ocis.services.store.v0.DeleteRequest
(*DeleteResponse)(nil), // 5: ocis.services.store.v0.DeleteResponse
(*ListRequest)(nil), // 6: ocis.services.store.v0.ListRequest
(*ListResponse)(nil), // 7: ocis.services.store.v0.ListResponse
(*DatabasesRequest)(nil), // 8: ocis.services.store.v0.DatabasesRequest
(*DatabasesResponse)(nil), // 9: ocis.services.store.v0.DatabasesResponse
(*TablesRequest)(nil), // 10: ocis.services.store.v0.TablesRequest
(*TablesResponse)(nil), // 11: ocis.services.store.v0.TablesResponse
(*v0.ReadOptions)(nil), // 12: ocis.messages.store.v0.ReadOptions
(*v0.Record)(nil), // 13: ocis.messages.store.v0.Record
(*v0.WriteOptions)(nil), // 14: ocis.messages.store.v0.WriteOptions
(*v0.DeleteOptions)(nil), // 15: ocis.messages.store.v0.DeleteOptions
(*v0.ListOptions)(nil), // 16: ocis.messages.store.v0.ListOptions
}
var file_ocis_services_store_v0_store_proto_depIdxs = []int32{
12, // 0: ocis.services.store.v0.ReadRequest.options:type_name -> ocis.messages.store.v0.ReadOptions
13, // 1: ocis.services.store.v0.ReadResponse.records:type_name -> ocis.messages.store.v0.Record
13, // 2: ocis.services.store.v0.WriteRequest.record:type_name -> ocis.messages.store.v0.Record
14, // 3: ocis.services.store.v0.WriteRequest.options:type_name -> ocis.messages.store.v0.WriteOptions
15, // 4: ocis.services.store.v0.DeleteRequest.options:type_name -> ocis.messages.store.v0.DeleteOptions
16, // 5: ocis.services.store.v0.ListRequest.options:type_name -> ocis.messages.store.v0.ListOptions
0, // 6: ocis.services.store.v0.Store.Read:input_type -> ocis.services.store.v0.ReadRequest
2, // 7: ocis.services.store.v0.Store.Write:input_type -> ocis.services.store.v0.WriteRequest
4, // 8: ocis.services.store.v0.Store.Delete:input_type -> ocis.services.store.v0.DeleteRequest
6, // 9: ocis.services.store.v0.Store.List:input_type -> ocis.services.store.v0.ListRequest
8, // 10: ocis.services.store.v0.Store.Databases:input_type -> ocis.services.store.v0.DatabasesRequest
10, // 11: ocis.services.store.v0.Store.Tables:input_type -> ocis.services.store.v0.TablesRequest
1, // 12: ocis.services.store.v0.Store.Read:output_type -> ocis.services.store.v0.ReadResponse
3, // 13: ocis.services.store.v0.Store.Write:output_type -> ocis.services.store.v0.WriteResponse
5, // 14: ocis.services.store.v0.Store.Delete:output_type -> ocis.services.store.v0.DeleteResponse
7, // 15: ocis.services.store.v0.Store.List:output_type -> ocis.services.store.v0.ListResponse
9, // 16: ocis.services.store.v0.Store.Databases:output_type -> ocis.services.store.v0.DatabasesResponse
11, // 17: ocis.services.store.v0.Store.Tables:output_type -> ocis.services.store.v0.TablesResponse
12, // [12:18] is the sub-list for method output_type
6, // [6:12] is the sub-list for method input_type
6, // [6:6] is the sub-list for extension type_name
6, // [6:6] is the sub-list for extension extendee
0, // [0:6] is the sub-list for field type_name
}
func init() { file_ocis_services_store_v0_store_proto_init() }
func file_ocis_services_store_v0_store_proto_init() {
if File_ocis_services_store_v0_store_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_ocis_services_store_v0_store_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReadRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReadResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WriteRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WriteResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DatabasesRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DatabasesResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TablesRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_ocis_services_store_v0_store_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TablesResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_ocis_services_store_v0_store_proto_rawDesc,
NumEnums: 0,
NumMessages: 12,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_ocis_services_store_v0_store_proto_goTypes,
DependencyIndexes: file_ocis_services_store_v0_store_proto_depIdxs,
MessageInfos: file_ocis_services_store_v0_store_proto_msgTypes,
}.Build()
File_ocis_services_store_v0_store_proto = out.File
file_ocis_services_store_v0_store_proto_rawDesc = nil
file_ocis_services_store_v0_store_proto_goTypes = nil
file_ocis_services_store_v0_store_proto_depIdxs = nil
}

View File

@@ -1,254 +0,0 @@
// Code generated by protoc-gen-micro. DO NOT EDIT.
// source: ocis/services/store/v0/store.proto
package v0
import (
fmt "fmt"
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options"
_ "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/store/v0"
proto "google.golang.org/protobuf/proto"
math "math"
)
import (
context "context"
api "go-micro.dev/v4/api"
client "go-micro.dev/v4/client"
server "go-micro.dev/v4/server"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// Reference imports to suppress errors if they are not otherwise used.
var _ api.Endpoint
var _ context.Context
var _ client.Option
var _ server.Option
// Api Endpoints for Store service
func NewStoreEndpoints() []*api.Endpoint {
return []*api.Endpoint{}
}
// Client API for Store service
type StoreService interface {
Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error)
Write(ctx context.Context, in *WriteRequest, opts ...client.CallOption) (*WriteResponse, error)
Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error)
List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (Store_ListService, error)
Databases(ctx context.Context, in *DatabasesRequest, opts ...client.CallOption) (*DatabasesResponse, error)
Tables(ctx context.Context, in *TablesRequest, opts ...client.CallOption) (*TablesResponse, error)
}
type storeService struct {
c client.Client
name string
}
func NewStoreService(name string, c client.Client) StoreService {
return &storeService{
c: c,
name: name,
}
}
func (c *storeService) Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) {
req := c.c.NewRequest(c.name, "Store.Read", in)
out := new(ReadResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storeService) Write(ctx context.Context, in *WriteRequest, opts ...client.CallOption) (*WriteResponse, error) {
req := c.c.NewRequest(c.name, "Store.Write", in)
out := new(WriteResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storeService) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) {
req := c.c.NewRequest(c.name, "Store.Delete", in)
out := new(DeleteResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storeService) List(ctx context.Context, in *ListRequest, opts ...client.CallOption) (Store_ListService, error) {
req := c.c.NewRequest(c.name, "Store.List", &ListRequest{})
stream, err := c.c.Stream(ctx, req, opts...)
if err != nil {
return nil, err
}
if err := stream.Send(in); err != nil {
return nil, err
}
return &storeServiceList{stream}, nil
}
type Store_ListService interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
CloseSend() error
Close() error
Recv() (*ListResponse, error)
}
type storeServiceList struct {
stream client.Stream
}
func (x *storeServiceList) CloseSend() error {
return x.stream.CloseSend()
}
func (x *storeServiceList) Close() error {
return x.stream.Close()
}
func (x *storeServiceList) Context() context.Context {
return x.stream.Context()
}
func (x *storeServiceList) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *storeServiceList) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *storeServiceList) Recv() (*ListResponse, error) {
m := new(ListResponse)
err := x.stream.Recv(m)
if err != nil {
return nil, err
}
return m, nil
}
func (c *storeService) Databases(ctx context.Context, in *DatabasesRequest, opts ...client.CallOption) (*DatabasesResponse, error) {
req := c.c.NewRequest(c.name, "Store.Databases", in)
out := new(DatabasesResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storeService) Tables(ctx context.Context, in *TablesRequest, opts ...client.CallOption) (*TablesResponse, error) {
req := c.c.NewRequest(c.name, "Store.Tables", in)
out := new(TablesResponse)
err := c.c.Call(ctx, req, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for Store service
type StoreHandler interface {
Read(context.Context, *ReadRequest, *ReadResponse) error
Write(context.Context, *WriteRequest, *WriteResponse) error
Delete(context.Context, *DeleteRequest, *DeleteResponse) error
List(context.Context, *ListRequest, Store_ListStream) error
Databases(context.Context, *DatabasesRequest, *DatabasesResponse) error
Tables(context.Context, *TablesRequest, *TablesResponse) error
}
func RegisterStoreHandler(s server.Server, hdlr StoreHandler, opts ...server.HandlerOption) error {
type store interface {
Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error
Write(ctx context.Context, in *WriteRequest, out *WriteResponse) error
Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error
List(ctx context.Context, stream server.Stream) error
Databases(ctx context.Context, in *DatabasesRequest, out *DatabasesResponse) error
Tables(ctx context.Context, in *TablesRequest, out *TablesResponse) error
}
type Store struct {
store
}
h := &storeHandler{hdlr}
return s.Handle(s.NewHandler(&Store{h}, opts...))
}
type storeHandler struct {
StoreHandler
}
func (h *storeHandler) Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error {
return h.StoreHandler.Read(ctx, in, out)
}
func (h *storeHandler) Write(ctx context.Context, in *WriteRequest, out *WriteResponse) error {
return h.StoreHandler.Write(ctx, in, out)
}
func (h *storeHandler) Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error {
return h.StoreHandler.Delete(ctx, in, out)
}
func (h *storeHandler) List(ctx context.Context, stream server.Stream) error {
m := new(ListRequest)
if err := stream.Recv(m); err != nil {
return err
}
return h.StoreHandler.List(ctx, m, &storeListStream{stream})
}
type Store_ListStream interface {
Context() context.Context
SendMsg(interface{}) error
RecvMsg(interface{}) error
Close() error
Send(*ListResponse) error
}
type storeListStream struct {
stream server.Stream
}
func (x *storeListStream) Close() error {
return x.stream.Close()
}
func (x *storeListStream) Context() context.Context {
return x.stream.Context()
}
func (x *storeListStream) SendMsg(m interface{}) error {
return x.stream.Send(m)
}
func (x *storeListStream) RecvMsg(m interface{}) error {
return x.stream.Recv(m)
}
func (x *storeListStream) Send(m *ListResponse) error {
return x.stream.Send(m)
}
func (h *storeHandler) Databases(ctx context.Context, in *DatabasesRequest, out *DatabasesResponse) error {
return h.StoreHandler.Databases(ctx, in, out)
}
func (h *storeHandler) Tables(ctx context.Context, in *TablesRequest, out *TablesResponse) error {
return h.StoreHandler.Tables(ctx, in, out)
}

View File

@@ -1,242 +0,0 @@
{
"swagger": "2.0",
"info": {
"title": "ownCloud Infinite Scale store",
"version": "1.0.0",
"contact": {
"name": "ownCloud GmbH",
"url": "https://github.com/owncloud/ocis",
"email": "support@owncloud.com"
},
"license": {
"name": "Apache-2.0",
"url": "https://github.com/owncloud/ocis/blob/master/LICENSE"
}
},
"tags": [
{
"name": "Store"
}
],
"schemes": [
"http",
"https"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {},
"definitions": {
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"$ref": "#/definitions/protobufAny"
}
}
}
},
"v0DatabasesResponse": {
"type": "object",
"properties": {
"databases": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v0DeleteOptions": {
"type": "object",
"properties": {
"database": {
"type": "string"
},
"table": {
"type": "string"
}
}
},
"v0DeleteResponse": {
"type": "object"
},
"v0Field": {
"type": "object",
"properties": {
"type": {
"type": "string",
"title": "type of value e.g string, int, int64, bool, float64"
},
"value": {
"type": "string",
"title": "the actual value"
}
}
},
"v0ListOptions": {
"type": "object",
"properties": {
"database": {
"type": "string"
},
"table": {
"type": "string"
},
"prefix": {
"type": "string"
},
"suffix": {
"type": "string"
},
"limit": {
"type": "string",
"format": "uint64"
},
"offset": {
"type": "string",
"format": "uint64"
}
}
},
"v0ListResponse": {
"type": "object",
"properties": {
"keys": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v0ReadOptions": {
"type": "object",
"properties": {
"database": {
"type": "string"
},
"table": {
"type": "string"
},
"prefix": {
"type": "boolean"
},
"suffix": {
"type": "boolean"
},
"limit": {
"type": "string",
"format": "uint64"
},
"offset": {
"type": "string",
"format": "uint64"
},
"where": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/v0Field"
}
}
}
},
"v0ReadResponse": {
"type": "object",
"properties": {
"records": {
"type": "array",
"items": {
"$ref": "#/definitions/v0Record"
}
}
}
},
"v0Record": {
"type": "object",
"properties": {
"key": {
"type": "string",
"title": "key of the recorda"
},
"value": {
"type": "string",
"format": "byte",
"title": "value in the record"
},
"expiry": {
"type": "string",
"format": "int64",
"title": "time.Duration (signed int64 nanoseconds)"
},
"metadata": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/v0Field"
},
"title": "the associated metadata"
}
}
},
"v0TablesResponse": {
"type": "object",
"properties": {
"tables": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v0WriteOptions": {
"type": "object",
"properties": {
"database": {
"type": "string"
},
"table": {
"type": "string"
},
"expiry": {
"type": "string",
"format": "int64",
"title": "time.Time"
},
"ttl": {
"type": "string",
"format": "int64",
"title": "time.Duration"
}
}
},
"v0WriteResponse": {
"type": "object"
}
},
"externalDocs": {
"description": "Developer Manual",
"url": "https://owncloud.dev/services/store/"
}
}

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.40.1. DO NOT EDIT.
// Code generated by mockery v2.43.2. DO NOT EDIT.
package mocks

View File

@@ -1,4 +1,4 @@
# Activitylog Service
# Activitylog
The `activitylog` service is responsible for storing events (activities) per resource.
@@ -13,3 +13,29 @@ Log services like the `activitylog`, `userlog`, `clientlog` and `sse` are respon
## Activitylog Store
The `activitylog` stores activities for each resource. It works in conjunction with the `eventhistory` service to keep the data it needs to store to a minimum.
## Translations
The `activitylog` service has embedded translations sourced via transifex to provide a basic set of translated languages. These embedded translations are available for all deployment scenarios. In addition, the service supports custom translations, though it is currently not possible to just add custom translations to embedded ones. If custom translations are configured, the embedded ones are not used. To configure custom translations, the `ACTIVITYLOG_TRANSLATION_PATH` environment variable needs to point to a base folder that will contain the translation files. This path must be available from all instances of the activitylog service, a shared storage is recommended. Translation files must be of type [.po](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html#PO-Files) or [.mo](https://www.gnu.org/software/gettext/manual/html_node/Binaries.html). For each language, the filename needs to be `activitylog.po` (or `activitylog.mo`) and stored in a folder structure defining the language code. In general the path/name pattern for a translation file needs to be:
```text
{ACTIVITYLOG_TRANSLATION_PATH}/{language-code}/LC_MESSAGES/activitylog.po
```
The language code pattern is composed of `language[_territory]` where `language` is the base language and `_territory` is optional and defines a country.
For example, for the language `de`, one needs to place the corresponding translation files to `{ACTIVITYLOG_TRANSLATION_PATH}/de_DE/LC_MESSAGES/activitylog.po`.
<!-- also see the notifications readme -->
Important: For the time being, the embedded ownCloud Web frontend only supports the main language code but does not handle any territory. When strings are available in the language code `language_territory`, the web frontend does not see it as it only requests `language`. In consequence, any translations made must exist in the requested `language` to avoid a fallback to the default.
### Translation Rules
* If a requested language code is not available, the service tries to fall back to the base language if available. For example, if the requested language-code `de_DE` is not available, the service tries to fall back to translations in the `de` folder.
* If the base language `de` is also not available, the service falls back to the system's default English (`en`),
which is the source of the texts provided by the code.
## Default Language
The default language can be defined via the `OCIS_DEFAULT_LANGUAGE` environment variable. See the `settings` service for a detailed description.

View File

@@ -26,6 +26,9 @@ type Config struct {
HTTP HTTP `yaml:"http"`
TokenManager *TokenManager `yaml:"token_manager"`
TranslationPath string `yaml:"translation_path" env:"OCIS_TRANSLATION_PATH;ACTIVITYLOG_TRANSLATION_PATH" desc:"(optional) Set this to a path with custom translations to overwrite the builtin translations. Note that file and folder naming rules apply, see the documentation for more details." introductionVersion:"%%NEXT%%"`
DefaultLanguage string `yaml:"default_language" env:"OCIS_DEFAULT_LANGUAGE" desc:"The default language used by services and the WebUI. If not defined, English will be used as default. See the documentation for more details." introductionVersion:"%%NEXT%%"`
ServiceAccount ServiceAccount `yaml:"service_account"`
Context context.Context `yaml:"-"`

View File

@@ -37,7 +37,8 @@ func DefaultConfig() *config.Config {
Database: "activitylog",
Table: "",
},
RevaGateway: shared.DefaultRevaConfig().Address,
RevaGateway: shared.DefaultRevaConfig().Address,
DefaultLanguage: "en",
HTTP: config.HTTP{
Addr: "127.0.0.1:0",
Root: "/",

View File

@@ -164,9 +164,8 @@ func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *h
continue
}
// FIXME: configurable default locale?
loc := l10n.MustGetUserLocale(r.Context(), activeUser.GetId().GetOpaqueId(), r.Header.Get(l10n.HeaderAcceptLanguage), s.valService)
t := l10n.NewTranslatorFromCommonConfig("en", _domain, "", _localeFS, _localeSubPath)
t := l10n.NewTranslatorFromCommonConfig(s.cfg.DefaultLanguage, _domain, s.cfg.TranslationPath, _localeFS, _localeSubPath)
resp.Activities = append(resp.Activities, NewActivity(t.Translate(message, loc), ts, e.GetId(), vars))
}

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2024-08-21 05:51+0000\n"
"POT-Creation-Date: 2024-08-22 00:53+0000\n"
"PO-Revision-Date: 2024-08-20 10:13+0000\n"
"Last-Translator: Martin <github@diemattels.at>, 2024\n"
"Language-Team: German (https://app.transifex.com/owncloud-org/teams/6149/de/)\n"
@@ -23,15 +23,15 @@ msgstr ""
#: pkg/service/response.go:23
msgid "{user} added {resource} to {space}"
msgstr "{user} hat {resource} zum {space} hinzugefügt"
msgstr "{user} hat {resource} zu {space} hinzugefügt"
#: pkg/service/response.go:31
msgid "{user} added {sharee} as member of {space}"
msgstr "{user} hat {sharee} als Mitglied zum {space} hinzugefügt"
msgstr "{user} hat {sharee} als Mitglied zu {space} hinzugefügt"
#: pkg/service/response.go:24
msgid "{user} deleted {resource} from {space}"
msgstr "{user} hat {resource} vom {space} gelöscht"
msgstr "{user} hat {resource} in {space} gelöscht"
#: pkg/service/response.go:25
msgid "{user} moved {resource} to {space}"

View File

@@ -0,0 +1,62 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Viktor Scharf, 2024
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2024-08-24 00:53+0000\n"
"PO-Revision-Date: 2024-08-20 10:13+0000\n"
"Last-Translator: Viktor Scharf, 2024\n"
"Language-Team: Russian (https://app.transifex.com/owncloud-org/teams/6149/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ru\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
#: pkg/service/response.go:23
msgid "{user} added {resource} to {space}"
msgstr "{user} добавил {resource} в {space}"
#: pkg/service/response.go:31
msgid "{user} added {sharee} as member of {space}"
msgstr "{user} добавил {sharee} как участника {space}"
#: pkg/service/response.go:24
msgid "{user} deleted {resource} from {space}"
msgstr "{user} удалил {resource} из {space}"
#: pkg/service/response.go:25
msgid "{user} moved {resource} to {space}"
msgstr "{user} переместил {resource} в {space}"
#: pkg/service/response.go:30
msgid "{user} removed link to {resource}"
msgstr "{user} удалил ссылку на {resource}"
#: pkg/service/response.go:28
msgid "{user} removed {sharee} from {resource}"
msgstr "{user} удалил {sharee} из {resource}"
#: pkg/service/response.go:32
msgid "{user} removed {sharee} from {space}"
msgstr "{user} удалил {sharee} из {space}"
#: pkg/service/response.go:26
msgid "{user} renamed {oldResource} to {resource}"
msgstr "{user} переименовал {oldResource} в {resource}"
#: pkg/service/response.go:29
msgid "{user} shared {resource} via link"
msgstr "{user} поделился {resource} через ссылку"
#: pkg/service/response.go:27
msgid "{user} shared {resource} with {sharee}"
msgstr "{user} поделился {resource} с {sharee}"

View File

@@ -0,0 +1,62 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# Besnik Bleta <besnik@programeshqip.org>, 2024
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2024-08-22 00:53+0000\n"
"PO-Revision-Date: 2024-08-20 10:13+0000\n"
"Last-Translator: Besnik Bleta <besnik@programeshqip.org>, 2024\n"
"Language-Team: Albanian (https://app.transifex.com/owncloud-org/teams/6149/sq/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: sq\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: pkg/service/response.go:23
msgid "{user} added {resource} to {space}"
msgstr "{user} shtoi {resource} te {space}"
#: pkg/service/response.go:31
msgid "{user} added {sharee} as member of {space}"
msgstr "{user} shtoi {sharee} si anëtar të {space}"
#: pkg/service/response.go:24
msgid "{user} deleted {resource} from {space}"
msgstr "{user} fshiu {resource} nga {space}"
#: pkg/service/response.go:25
msgid "{user} moved {resource} to {space}"
msgstr "{user} e shpuri {resource} te {space}"
#: pkg/service/response.go:30
msgid "{user} removed link to {resource}"
msgstr "{user} hoqi lidhjen për te {resource}"
#: pkg/service/response.go:28
msgid "{user} removed {sharee} from {resource}"
msgstr "{user} hoqi {sharee} nga {resource}"
#: pkg/service/response.go:32
msgid "{user} removed {sharee} from {space}"
msgstr "{user} hoqi {sharee} nga {space}"
#: pkg/service/response.go:26
msgid "{user} renamed {oldResource} to {resource}"
msgstr "{user} riemërtoi {oldResource} si {resource}"
#: pkg/service/response.go:29
msgid "{user} shared {resource} via link"
msgstr "{user} ndau me të tjerët {resource} përmes lidhjeje"
#: pkg/service/response.go:27
msgid "{user} shared {resource} with {sharee}"
msgstr "{user} ndau {resource} me {sharee}"

View File

@@ -99,6 +99,7 @@ func WithTrashedResource(ref *provider.Reference, rid *provider.ResourceId) Acti
resp, err := gwc.ListRecycle(ctx, &provider.ListRecycleRequest{
Ref: ref,
Key: rid.GetOpaqueId(),
})
if err != nil {
return err

View File

@@ -81,7 +81,7 @@ func Server(cfg *config.Config) *cli.Command {
sync.Trap(&gr, cancel)
}
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -48,7 +48,7 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"APP_PROVIDER_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"pre5.0"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"APP_PROVIDER_GRPC_PROTOCOL" desc:"The transport protocol of the GPRC service." introductionVersion:"pre5.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;APP_PROVIDER_GRPC_PROTOCOL" desc:"The transport protocol of the GPRC service." introductionVersion:"pre5.0"`
}
type Drivers struct {

View File

@@ -76,7 +76,7 @@ func Server(cfg *config.Config) *cli.Command {
cancel()
})
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -47,7 +47,7 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"APP_REGISTRY_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"pre5.0"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"APP_REGISTRY_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;APP_REGISTRY_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
}
type AppRegistry struct {

View File

@@ -89,7 +89,7 @@ func Server(cfg *config.Config) *cli.Command {
sync.Trap(&gr, cancel)
}
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -58,7 +58,7 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"AUTH_APP_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"%%NEXT%%"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"AUTH_APP_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"%%NEXT%%"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;AUTH_APP_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"%%NEXT%%"`
}
// HTTP defines the available http configuration.

View File

@@ -94,7 +94,7 @@ func Server(cfg *config.Config) *cli.Command {
sync.Trap(&gr, cancel)
}
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -48,7 +48,7 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"AUTH_BASIC_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"pre5.0"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"AUTH_BASIC_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;AUTH_BASIC_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
}
type AuthProviders struct {

View File

@@ -81,7 +81,7 @@ func Server(cfg *config.Config) *cli.Command {
sync.Trap(&gr, cancel)
}
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -48,7 +48,7 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"AUTH_BEARER_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"pre5.0"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"AUTH_BEARER_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;AUTH_BEARER_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
}
type OIDC struct {

View File

@@ -81,7 +81,7 @@ func Server(cfg *config.Config) *cli.Command {
sync.Trap(&gr, cancel)
}
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -48,5 +48,5 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"AUTH_MACHINE_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"pre5.0"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"AUTH_MACHINE_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;AUTH_MACHINE_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
}

View File

@@ -82,7 +82,7 @@ func Server(cfg *config.Config) *cli.Command {
sync.Trap(&gr, cancel)
}
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -47,7 +47,7 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"AUTH_SERVICE_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"5.0"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"AUTH_SERVICE_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"5.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;AUTH_SERVICE_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"5.0"`
}
// ServiceAccount is the configuration for the used service account

View File

@@ -221,6 +221,7 @@ func processShareEvent(ctx context.Context, ref *provider.Reference, gwc gateway
func processItemTrashedEvent(ctx context.Context, ref *provider.Reference, gwc gateway.GatewayAPIClient, initiatorid string, itemID *provider.ResourceId) ([]string, FileEvent, error) {
resp, err := gwc.ListRecycle(ctx, &provider.ListRecycleRequest{
Ref: ref,
Key: itemID.GetOpaqueId(),
})
if err != nil {
return nil, FileEvent{}, err

View File

@@ -33,6 +33,7 @@ func DefaultConfig() *config.Config {
},
GRPC: config.GRPC{
Addr: "127.0.0.1:9301",
Protocol: "tcp",
Namespace: "com.owncloud.api",
},
HTTP: config.HTTP{

View File

@@ -2,6 +2,8 @@ package config
// GRPC defines the available grpc configuration.
type GRPC struct {
Addr string `yaml:"addr" env:"COLLABORATION_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"6.0.0"`
Addr string `yaml:"addr" env:"COLLABORATION_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"6.0.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;COLLABORATION_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"%%NEXT%%"`
Namespace string `yaml:"-"`
}

View File

@@ -52,10 +52,8 @@ var _ = Describe("ContentConnector", func() {
},
Path: ".",
},
User: &userv1beta1.User{}, // Not used for now
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
EditAppUrl: "http://test.ex.prv/edit",
ViewAppUrl: "http://test.ex.prv/view",
User: &userv1beta1.User{}, // Not used for now
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
}
randomContent = "This is the content of the test.txt file"
@@ -186,10 +184,8 @@ var _ = Describe("ContentConnector", func() {
},
Path: ".",
},
User: &userv1beta1.User{}, // Not used for now
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY,
EditAppUrl: "http://test.ex.prv/edit",
ViewAppUrl: "http://test.ex.prv/view",
User: &userv1beta1.User{}, // Not used for now
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_VIEW_ONLY,
}
ctx := middleware.WopiContextToCtx(context.Background(), wopiCtx)

View File

@@ -1050,8 +1050,9 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
// to get the folder we actually need to do a GetPath() request
//BreadcrumbFolderName: path.Dir(statRes.Info.Path),
fileinfo.KeyHostViewURL: wopiContext.ViewAppUrl,
fileinfo.KeyHostEditURL: wopiContext.EditAppUrl,
// TODO: these URLs must point to ocis, which is hosting the editor's iframe
//fileinfo.KeyHostViewURL: wopiContext.ViewAppUrl,
//fileinfo.KeyHostEditURL: wopiContext.EditAppUrl,
fileinfo.KeyEnableOwnerTermination: true, // only for collabora
fileinfo.KeySupportsExtendedLockLength: true,
@@ -1061,7 +1062,6 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
fileinfo.KeySupportsDeleteFile: true,
fileinfo.KeySupportsRename: true,
//fileinfo.KeyUserCanNotWriteRelative: true,
fileinfo.KeyIsAnonymousUser: isAnonymousUser,
fileinfo.KeyUserFriendlyName: userFriendlyName,
fileinfo.KeyUserID: userId,

View File

@@ -82,9 +82,7 @@ var _ = Describe("FileConnector", func() {
// },
//},
},
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
EditAppUrl: "http://test.ex.prv/edit",
ViewAppUrl: "http://test.ex.prv/view",
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
}
})
@@ -1546,8 +1544,6 @@ var _ = Describe("FileConnector", func() {
BaseFileName: "test.txt",
BreadcrumbDocName: "test.txt",
UserCanNotWriteRelative: false,
HostViewURL: "http://test.ex.prv/view",
HostEditURL: "http://test.ex.prv/edit",
SupportsExtendedLockLength: true,
SupportsGetLock: true,
SupportsLocks: true,

View File

@@ -18,7 +18,7 @@ import (
// There are no explicit requirements for the context, and it will be passed
// without changes to the underlying RegisterService method.
func RegisterOcisService(ctx context.Context, cfg *config.Config, logger log.Logger) error {
svc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name+"."+cfg.App.Name, cfg.GRPC.Addr, version.GetString())
svc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name+"."+cfg.App.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
return registry.RegisterService(ctx, svc, logger)
}

View File

@@ -1,6 +1,6 @@
package middleware
import "github.com/golang-jwt/jwt/v4"
import "github.com/golang-jwt/jwt/v5"
// Claims contains the jwt registered claims plus the used WOPI context
type Claims struct {

View File

@@ -11,7 +11,7 @@ import (
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"
"github.com/owncloud/ocis/v2/services/collaboration/pkg/config"
"github.com/owncloud/ocis/v2/services/collaboration/pkg/helpers"
"github.com/rs/zerolog"
@@ -31,8 +31,6 @@ type WopiContext struct {
FileReference *providerv1beta1.Reference
User *userv1beta1.User
ViewMode appproviderv1beta1.ViewMode
EditAppUrl string
ViewAppUrl string
}
// WopiContextAuthMiddleware will prepare an HTTP handler to be used as
@@ -71,11 +69,6 @@ func WopiContextAuthMiddleware(cfg *config.Config, next http.Handler) http.Handl
return
}
if err := claims.Valid(); err != nil {
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
return
}
ctx := r.Context()
wopiContextAccessToken, err := DecryptAES([]byte(cfg.Wopi.Secret), claims.WopiContext.AccessToken)

View File

@@ -2,10 +2,11 @@ package service
import (
"context"
"fmt"
"errors"
"net/url"
"path"
"strconv"
"strings"
appproviderv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -80,147 +81,47 @@ func (s *Service) OpenInApp(
Path: ".",
}
// build a urlsafe and stable file reference that can be used for proxy routing,
// so that all sessions on one file end on the same office server
fileRef := helpers.HashResourceId(req.GetResourceInfo().GetId())
logger := s.logger.With().
Str("FileReference", providerFileRef.String()).
Str("ViewMode", req.GetViewMode().String()).
Str("Requester", user.GetId().String()).
Logger()
// get the file extension to use the right wopi app url
fileExt := path.Ext(req.GetResourceInfo().GetPath())
var viewCommentAppURL string
var viewAppURL string
var editAppURL string
if viewCommentAppURLs, ok := s.appURLs["view_comment"]; ok {
if u, ok := viewCommentAppURLs[fileExt]; ok {
viewCommentAppURL = u
}
}
if viewAppURLs, ok := s.appURLs["view"]; ok {
if u, ok := viewAppURLs[fileExt]; ok {
viewAppURL = u
}
}
if editAppURLs, ok := s.appURLs["edit"]; ok {
if u, ok := editAppURLs[fileExt]; ok {
editAppURL = u
}
}
if editAppURL == "" && viewAppURL == "" && viewCommentAppURL == "" {
err := fmt.Errorf("OpenInApp: neither edit nor view app url found")
s.logger.Error().
Err(err).
Str("FileReference", providerFileRef.String()).
Str("ViewMode", req.GetViewMode().String()).
Str("Requester", user.GetId().String()).Send()
return nil, err
// get the appURL we need to use
appURL := s.getAppUrl(fileExt, req.GetViewMode())
if appURL == "" {
logger.Error().Msg("OpenInApp: neither edit nor view app URL found")
return nil, errors.New("neither edit nor view app URL found")
}
if editAppURL == "" {
// assuming that an view action is always available in the /hosting/discovery manifest
// eg. Collabora does support viewing jpgs but no editing
// eg. OnlyOffice does support viewing pdfs but no editing
// there is no known case of supporting edit only without view
editAppURL = viewAppURL
}
if viewAppURL == "" {
// the URL of the end-user application in view mode when different (defaults to edit mod URL)
viewAppURL = editAppURL
}
// TODO: check if collabora will support an "edit" url in the future
if viewAppURL == "" && editAppURL == "" && viewCommentAppURL != "" {
// there are rare cases where neither view nor edit is supported but view_comment is
viewAppURL = viewCommentAppURL
// that can be the case for editable and viewable files
if req.GetViewMode() == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE {
editAppURL = viewCommentAppURL
}
}
wopiSrcURL, err := url.Parse(s.config.Wopi.WopiSrc)
// append the parameters we need
appURL, err = s.addQueryToURL(appURL, req)
if err != nil {
return nil, err
}
wopiSrcURL.Path = path.Join("wopi", "files", fileRef)
addWopiSrcQueryParam := func(baseURL string) (string, error) {
u, err := url.Parse(baseURL)
if err != nil {
return "", err
}
q := u.Query()
q.Add("WOPISrc", wopiSrcURL.String())
if s.config.Wopi.DisableChat {
q.Add("dchat", "1")
}
lang := utils.ReadPlainFromOpaque(req.GetOpaque(), "lang")
if lang != "" {
q.Add("ui", lang) // OnlyOffice
q.Add("lang", lang) // Collabora, Impact on the default document language of OnlyOffice
q.Add("UI_LLCC", lang) // Office365
}
qs := q.Encode()
u.RawQuery = qs
return u.String(), nil
}
viewAppURL, err = addWopiSrcQueryParam(viewAppURL)
if err != nil {
s.logger.Error().
Err(err).
Str("FileReference", providerFileRef.String()).
Str("ViewMode", req.GetViewMode().String()).
Str("Requester", user.GetId().String()).
Msg("OpenInApp: error parsing viewAppUrl")
return nil, err
}
editAppURL, err = addWopiSrcQueryParam(editAppURL)
if err != nil {
s.logger.Error().
Err(err).
Str("FileReference", providerFileRef.String()).
Str("ViewMode", req.GetViewMode().String()).
Str("Requester", user.GetId().String()).
Msg("OpenInApp: error parsing editAppUrl")
logger.Error().Err(err).Msg("OpenInApp: error parsing appUrl")
return nil, err
}
appURL := viewAppURL
if req.GetViewMode() == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE {
appURL = editAppURL
}
// create the wopiContext and generate the token
wopiContext := middleware.WopiContext{
AccessToken: req.GetAccessToken(), // it will be encrypted
ViewOnlyToken: utils.ReadPlainFromOpaque(req.GetOpaque(), "viewOnlyToken"),
FileReference: &providerFileRef,
User: user,
ViewMode: req.GetViewMode(),
EditAppUrl: editAppURL,
ViewAppUrl: viewAppURL,
}
accessToken, accessExpiration, err := middleware.GenerateWopiToken(wopiContext, s.config)
if err != nil {
s.logger.Error().
Err(err).
Str("FileReference", providerFileRef.String()).
Str("ViewMode", req.GetViewMode().String()).
Str("Requester", user.GetId().String()).
Msg("OpenInApp: error generating the token")
logger.Error().Err(err).Msg("OpenInApp: error generating the token")
return &appproviderv1beta1.OpenInAppResponse{
Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_INTERNAL},
}, err
}
s.logger.Debug().
Str("FileReference", providerFileRef.String()).
Str("ViewMode", req.GetViewMode().String()).
Str("Requester", user.GetId().String()).
Msg("OpenInApp: success")
logger.Debug().Msg("OpenInApp: success")
return &appproviderv1beta1.OpenInAppResponse{
Status: &rpcv1beta1.Status{Code: rpcv1beta1.Code_CODE_OK},
@@ -237,3 +138,97 @@ func (s *Service) OpenInApp(
},
}, nil
}
// getAppUrlFor gets the appURL from the list of appURLs based on the
// action and file extension provided. If there is no match, an empty
// string will be returned.
func (s *Service) getAppUrlFor(action, fileExt string) string {
if actionURL, ok := s.appURLs[action]; ok {
if actionExtensionURL, ok := actionURL[fileExt]; ok {
return actionExtensionURL
}
}
return ""
}
// getAppUrl will get the appURL that should be used based on the extension
// and the provided view mode.
// "view" urls will be chosen first, then if the view mode is "read/write",
// "edit" urls will be prioritized. Note that "view" url might be returned for
// "read/write" view mode if no "edit" url is found.
func (s *Service) getAppUrl(fileExt string, viewMode appproviderv1beta1.ViewMode) string {
// prioritize view action if possible
appURL := s.getAppUrlFor("view", fileExt)
if strings.ToLower(s.config.App.Name) == "collabora" {
// collabora provides only one action per extension. usual options
// are "view" (checked above), "edit" or "view_comment" (this last one
// is exclusive of collabora)
if appURL == "" {
if editURL := s.getAppUrlFor("edit", fileExt); editURL != "" {
return editURL
}
if commentURL := s.getAppUrlFor("view_comment", fileExt); commentURL != "" {
return commentURL
}
}
} else {
// If not collabora, there might be an edit action for the extension.
// If read/write mode has been requested, prioritize edit action.
if viewMode == appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE {
if editAppURL := s.getAppUrlFor("edit", fileExt); editAppURL != "" {
appURL = editAppURL
}
}
}
return appURL
}
// addQueryToURL will add specific query parameters to the baseURL. These
// parameters are:
// * "WOPISrc" pointing to the requested resource in the OpenInAppRequest
// * "dchat" to disable the chat, based on configuration
// * "lang" (WOPI app dependent) with the language in the request. "lang"
// for collabora, "ui" for onlyoffice and "UI_LLCC" for the rest
func (s *Service) addQueryToURL(baseURL string, req *appproviderv1beta1.OpenInAppRequest) (string, error) {
u, err := url.Parse(baseURL)
if err != nil {
return "", err
}
// build a urlsafe and stable file reference that can be used for proxy routing,
// so that all sessions on one file end on the same office server
fileRef := helpers.HashResourceId(req.GetResourceInfo().GetId())
wopiSrcURL, err := url.Parse(s.config.Wopi.WopiSrc)
if err != nil {
return "", err
}
wopiSrcURL.Path = path.Join("wopi", "files", fileRef)
q := u.Query()
q.Add("WOPISrc", wopiSrcURL.String())
if s.config.Wopi.DisableChat {
q.Add("dchat", "1")
}
lang := utils.ReadPlainFromOpaque(req.GetOpaque(), "lang")
if lang != "" {
switch strings.ToLower(s.config.App.Name) {
case "collabora":
q.Add("lang", lang)
case "onlyoffice":
q.Add("ui", lang)
default:
q.Add("UI_LLCC", lang)
}
}
qs := q.Encode()
u.RawQuery = qs
return u.String(), nil
}

View File

@@ -6,7 +6,7 @@ import (
"time"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/v5"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/stretchr/testify/mock"
@@ -136,133 +136,66 @@ var _ = Describe("Discovery", func() {
Expect(resp).To(BeNil())
})
It("Success", func() {
ctx := context.Background()
nowTime := time.Now()
DescribeTable(
"Success",
func(appName, lang string, disableChat bool, expectedAppUrl string) {
ctx := context.Background()
nowTime := time.Now()
cfg.Wopi.WopiSrc = "https://wopiserver.test.prv"
cfg.Wopi.Secret = "my_supa_secret"
cfg.Wopi.WopiSrc = "https://wopiserver.test.prv"
cfg.Wopi.Secret = "my_supa_secret"
cfg.Wopi.DisableChat = disableChat
cfg.App.Name = appName
myself := &userv1beta1.User{
Id: &userv1beta1.UserId{
Idp: "myIdp",
OpaqueId: "opaque001",
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
},
Username: "username",
}
req := &appproviderv1beta1.OpenInAppRequest{
ResourceInfo: &providerv1beta1.ResourceInfo{
Id: &providerv1beta1.ResourceId{
StorageId: "myStorage",
OpaqueId: "storageOpaque001",
SpaceId: "SpaceA",
myself := &userv1beta1.User{
Id: &userv1beta1.UserId{
Idp: "myIdp",
OpaqueId: "opaque001",
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
},
Path: "/path/to/file.docx",
},
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime),
}
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lang", "de")
Username: "username",
}
gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{
Status: status.NewOK(ctx),
User: myself,
}, nil)
resp, err := srv.OpenInApp(ctx, req)
Expect(err).To(Succeed())
Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST"))
Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?UI_LLCC=de&WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&lang=de&ui=de"))
Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10)))
})
It("Success", func() {
ctx := context.Background()
nowTime := time.Now()
cfg.Wopi.WopiSrc = "https://wopiserver.test.prv"
cfg.Wopi.Secret = "my_supa_secret"
cfg.Wopi.DisableChat = true
myself := &userv1beta1.User{
Id: &userv1beta1.UserId{
Idp: "myIdp",
OpaqueId: "opaque001",
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
},
Username: "username",
}
req := &appproviderv1beta1.OpenInAppRequest{
ResourceInfo: &providerv1beta1.ResourceInfo{
Id: &providerv1beta1.ResourceId{
StorageId: "myStorage",
OpaqueId: "storageOpaque001",
SpaceId: "SpaceA",
req := &appproviderv1beta1.OpenInAppRequest{
ResourceInfo: &providerv1beta1.ResourceInfo{
Id: &providerv1beta1.ResourceId{
StorageId: "myStorage",
OpaqueId: "storageOpaque001",
SpaceId: "SpaceA",
},
Path: "/path/to/file.docx",
},
Path: "/path/to/file.docx",
},
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime),
}
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime),
}
if lang != "" {
req.Opaque = utils.AppendPlainToOpaque(req.Opaque, "lang", lang)
}
gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{
Status: status.NewOK(ctx),
User: myself,
}, nil)
gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{
Status: status.NewOK(ctx),
User: myself,
}, nil)
resp, err := srv.OpenInApp(ctx, req)
Expect(err).To(Succeed())
Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST"))
Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"))
Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10)))
})
It("Success", func() {
ctx := context.Background()
nowTime := time.Now()
cfg.Wopi.WopiSrc = "https://wopiserver.test.prv"
cfg.Wopi.Secret = "my_supa_secret"
cfg.Wopi.DisableChat = true
myself := &userv1beta1.User{
Id: &userv1beta1.UserId{
Idp: "myIdp",
OpaqueId: "opaque001",
Type: userv1beta1.UserType_USER_TYPE_PRIMARY,
},
Username: "username",
}
req := &appproviderv1beta1.OpenInAppRequest{
ResourceInfo: &providerv1beta1.ResourceInfo{
Id: &providerv1beta1.ResourceId{
StorageId: "myStorage",
OpaqueId: "storageOpaque001",
SpaceId: "SpaceA",
},
Path: "/path/to/file.docx",
},
ViewMode: appproviderv1beta1.ViewMode_VIEW_MODE_READ_WRITE,
AccessToken: MintToken(myself, cfg.Wopi.Secret, nowTime),
}
gatewayClient.On("WhoAmI", mock.Anything, mock.Anything).Times(1).Return(&gatewayv1beta1.WhoAmIResponse{
Status: status.NewOK(ctx),
User: myself,
}, nil)
resp, err := srv.OpenInApp(ctx, req)
Expect(err).To(Succeed())
Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST"))
Expect(resp.GetAppUrl().GetAppUrl()).To(Equal("https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"))
Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10)))
})
resp, err := srv.OpenInApp(ctx, req)
Expect(err).To(Succeed())
Expect(resp.GetStatus().GetCode()).To(Equal(rpcv1beta1.Code_CODE_OK))
Expect(resp.GetAppUrl().GetMethod()).To(Equal("POST"))
Expect(resp.GetAppUrl().GetAppUrl()).To(Equal(expectedAppUrl))
Expect(resp.GetAppUrl().GetFormParameters()["access_token_ttl"]).To(Equal(strconv.FormatInt(nowTime.Add(5*time.Hour).Unix()*1000, 10)))
},
Entry("Microsoft chat no lang", "Microsoft", "", false, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
Entry("Collabora chat no lang", "Collabora", "", false, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
Entry("OnlyOffice chat no lang", "OnlyOffice", "", false, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
Entry("Microsoft chat lang", "Microsoft", "de", false, "https://test.server.prv/hosting/wopi/word/edit?UI_LLCC=de&WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e"),
Entry("Collabora chat lang", "Collabora", "de", false, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&lang=de"),
Entry("OnlyOffice chat lang", "OnlyOffice", "de", false, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&ui=de"),
Entry("Microsoft no chat no lang", "Microsoft", "", true, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
Entry("Collabora no chat no lang", "Collabora", "", true, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
Entry("OnlyOffice no chat no lang", "OnlyOffice", "", true, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
Entry("Microsoft no chat lang", "Microsoft", "de", true, "https://test.server.prv/hosting/wopi/word/edit?UI_LLCC=de&WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1"),
Entry("Collabora no chat lang", "Collabora", "de", true, "https://test.server.prv/hosting/wopi/word/view?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1&lang=de"),
Entry("OnlyOffice no chat lang", "OnlyOffice", "de", true, "https://test.server.prv/hosting/wopi/word/edit?WOPISrc=https%3A%2F%2Fwopiserver.test.prv%2Fwopi%2Ffiles%2F2f6ec18696dd1008106749bd94106e5cfad5c09e15de7b77088d03843e71b43e&dchat=1&ui=de"),
)
})
})

View File

@@ -31,7 +31,74 @@ Store specific notes:
- When using `nats-js-kv` it is recommended to set `OCIS_CACHE_STORE_NODES` to the same value as `OCIS_EVENTS_ENDPOINT`. That way the cache uses the same nats instance as the event bus.
- When using the `nats-js-kv` store, it is possible to set `OCIS_CACHE_DISABLE_PERSISTENCE` to instruct nats to not persist cache data on disc.
## Storage registry
## Service Endpoints
**IMPORTANT**\
This functionality is currently experimental.
The gateway acts as a proxy for other CS3 services. As such it has to forward requests to a lot of services and needs to establish connections by looking up the IP address using the service registry. Instead of using the service registry each endpoint can also be configured to use the grpc `dns://` or `kubernetes://` URLs, which might be useful when running in kubernetes.
For a local single node deployment you might want to use `unix:` sockets as shown below. Using unix sockets will reduce the amount of service lookups and omit the TCP stack. For now, this is experimental and the services do not delete the socket on shutdown. PRs welcome.
```console
USERS_GRPC_PROTOCOL=unix"
USERS_GRPC_ADDR=/var/run/ocis/users.sock"
GATEWAY_USERS_ENDPOINT=unix:/var/run/ocis/users.sock"
GROUPS_GRPC_PROTOCOL=unix"
GROUPS_GRPC_ADDR=/var/run/ocis/groups.sock"
GATEWAY_GROUPS_ENDPOINT=unix:/var/run/ocis/groups.sock"
AUTH_APP_GRPC_PROTOCOL=unix"
AUTH_APP_GRPC_ADDR=/var/run/ocis/auth-app.sock"
GATEWAY_AUTH_APP_ENDPOINT=unix:/var/run/ocis/auth-app.sock"
AUTH_BASIC_GRPC_PROTOCOL=unix"
AUTH_BASIC_GRPC_ADDR=/var/run/ocis/auth-basic.sock"
GATEWAY_AUTH_BASIC_ENDPOINT=unix:/var/run/ocis/auth-basic.sock"
AUTH_MACHINE_GRPC_PROTOCOL=unix"
AUTH_MACHINE_GRPC_ADDR=/var/run/ocis/auth-machine.sock"
GATEWAY_AUTH_MACHINE_ENDPOINT=unix:/var/run/ocis/auth-machine.sock"
AUTH_SERVICE_GRPC_PROTOCOL=unix"
AUTH_SERVICE_GRPC_ADDR=/var/run/ocis/auth-service.sock"
GATEWAY_AUTH_SERVICE_ENDPOINT=unix:/var/run/ocis/auth-service.sock"
STORAGE_PUBLIC_LINK_GRPC_PROTOCOL=unix"
STORAGE_PUBLIC_LINK_GRPC_ADDR=/var/run/ocis/storage-public-link.sock"
GATEWAY_STORAGE_PUBLIC_LINK_ENDPOINT=unix:/var/run/ocis/storage-public-link.sock"
STORAGE_USERS_GRPC_PROTOCOL=unix"
STORAGE_USERS_GRPC_ADDR=/var/run/ocis/storage-users.sock"
GATEWAY_STORAGE_USERS_ENDPOINT=unix:/var/run/ocis/storage-users.sock"
// graph sometimes bypasses the gateway so we need to configure the socket here as wel
GRAPH_SPACES_STORAGE_USERS_ADDRESS=unix:/var/run/ocis/storage-users.sock"
STORAGE_SHARES_GRPC_PROTOCOL=unix"
STORAGE_SHARES_GRPC_ADDR=/var/run/ocis/storage-shares.sock"
GATEWAY_STORAGE_SHARES_ENDPOINT=unix:/var/run/ocis/storage-shares.sock"
APP_REGISTRY_GRPC_PROTOCOL=unix"
APP_REGISTRY_GRPC_ADDR=/var/run/ocis/app-registry.sock"
GATEWAY_APP_REGISTRY_ENDPOINT=unix:/var/run/ocis/app-registry.sock"
OCM_GRPC_PROTOCOL=unix"
OCM_GRPC_ADDR=/var/run/ocis/ocm.sock"
GATEWAY_OCM_ENDPOINT=unix:/var/run/ocis/ocm.sock"
// storage system
STORAGE_SYSTEM_GRPC_PROTOCOL="unix"
STORAGE_SYSTEM_GRPC_ADDR="/var/run/ocis/storage-system.sock"
STORAGE_GATEWAY_GRPC_ADDR="unix:/var/run/ocis/storage-system.sock"
STORAGE_GRPC_ADDR="unix:/var/run/ocis/storage-system.sock"
SHARING_USER_CS3_PROVIDER_ADDR="unix:/var/run/ocis/storage-system.sock"
SHARING_USER_JSONCS3_PROVIDER_ADDR="unix:/var/run/ocis/storage-system.sock"
SHARING_PUBLIC_CS3_PROVIDER_ADDR="unix:/var/run/ocis/storage-system.sock"
SHARING_PUBLIC_JSONCS3_PROVIDER_ADDR="unix:/var/run/ocis/storage-system.sock"
```
## Storage Registry
In order to add another storage provider the CS3 storage registry that is running as part of the CS3 gateway hes to be made aware of it. The easiest cleanest way to do it is to set `GATEWAY_STORAGE_REGISTRY_CONFIG_JSON=/path/to/storages.json` and list all storage providers like this:
@@ -101,4 +168,4 @@ In order to add another storage provider the CS3 storage registry that is runnin
}
```
In the above replace `{storage-users-mount-uuid}` with the mount UUID that was generated for the storage-users service. You can find it in the `config.yaml` generated on by `ocis init`. The last entry `com.owncloud.api.storage-hello` and its `providerid` `"hello-storage-id"` are an example for in additional storage provider, in this case running `hellofs`, an example minimal storage driver.
In the above replace `{storage-users-mount-uuid}` with the mount UUID that was generated for the storage-users service. You can find it in the `config.yaml` generated on by `ocis init`. The last entry `com.owncloud.api.storage-hello` and its `providerid` `"hello-storage-id"` are an example for in additional storage provider, in this case running `hellofs`, an example minimal storage driver.

View File

@@ -81,7 +81,7 @@ func Server(cfg *config.Config) *cli.Command {
cancel()
})
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Addr, version.GetString())
grpcSvc := registry.BuildGRPCService(cfg.GRPC.Namespace+"."+cfg.Service.Name, cfg.GRPC.Protocol, cfg.GRPC.Addr, version.GetString())
if err := registry.RegisterService(ctx, grpcSvc, logger); err != nil {
logger.Fatal().Err(err).Msg("failed to register the grpc service")
}

View File

@@ -31,20 +31,20 @@ type Config struct {
FrontendPublicURL string `yaml:"frontend_public_url" env:"OCIS_URL;GATEWAY_FRONTEND_PUBLIC_URL" desc:"The public facing URL of the oCIS frontend." introductionVersion:"pre5.0"`
UsersEndpoint string `yaml:"-"`
GroupsEndpoint string `yaml:"-"`
PermissionsEndpoint string `yaml:"-"`
SharingEndpoint string `yaml:"-"`
AuthAppEndpoint string `yaml:"-"`
AuthBasicEndpoint string `yaml:"-"`
AuthBearerEndpoint string `yaml:"-"`
AuthMachineEndpoint string `yaml:"-"`
AuthServiceEndpoint string `yaml:"-"`
StoragePublicLinkEndpoint string `yaml:"-"`
StorageUsersEndpoint string `yaml:"-"`
StorageSharesEndpoint string `yaml:"-"`
AppRegistryEndpoint string `yaml:"-"`
OCMEndpoint string `yaml:"-"`
UsersEndpoint string `yaml:"users_endpoint" env:"GATEWAY_USERS_ENDPOINT" desc:"The endpoint of the users service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
GroupsEndpoint string `yaml:"groups_endpoint" env:"GATEWAY_GROUPS_ENDPOINT" desc:"The endpoint of the groups service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
PermissionsEndpoint string `yaml:"permissions_endpoint" env:"GATEWAY_PERMISSIONS_ENDPOINT" desc:"The endpoint of the permissions service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
SharingEndpoint string `yaml:"sharing_endpoint" env:"GATEWAY_SHARING_ENDPOINT" desc:"The endpoint of the shares service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
AuthAppEndpoint string `yaml:"auth_app_endpoint" env:"GATEWAY_AUTH_APP_ENDPOINT" desc:"The endpoint of the auth-app service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
AuthBasicEndpoint string `yaml:"auth_basic_endpoint" env:"GATEWAY_AUTH_BASIC_ENDPOINT" desc:"The endpoint of the auth-basic service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
AuthBearerEndpoint string `yaml:"auth_bearer_endpoint" env:"GATEWAY_AUTH_BEARER_ENDPOINT" desc:"The endpoint of the auth-bearer service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
AuthMachineEndpoint string `yaml:"auth_machine_endpoint" env:"GATEWAY_AUTH_MACHINE_ENDPOINT" desc:"The endpoint of the auth-machine service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
AuthServiceEndpoint string `yaml:"auth_service_endpoint" env:"GATEWAY_AUTH_SERVICE_ENDPOINT" desc:"The endpoint of the auth-service service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
StoragePublicLinkEndpoint string `yaml:"storage_public_link_endpoint" env:"GATEWAY_STORAGE_PUBLIC_LINK_ENDPOINT" desc:"The endpoint of the storage-publiclink service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
StorageUsersEndpoint string `yaml:"storage_users_endpoint" env:"GATEWAY_STORAGE_USERS_ENDPOINT" desc:"The endpoint of the storage-users service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
StorageSharesEndpoint string `yaml:"storage_shares_endpoint" env:"GATEWAY_STORAGE_SHARES_ENDPOINT" desc:"The endpoint of the storag-shares service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
AppRegistryEndpoint string `yaml:"app_registry_endpoint" env:"GATEWAY_APP_REGISTRY_ENDPOINT" desc:"The endpoint of the app-registry service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
OCMEndpoint string `yaml:"ocm_endpoint" env:"GATEWAY_OCM_ENDPOINT" desc:"The endpoint of the ocm service. Can take a service name or a gRPC URI with the dns, kubernetes or unix protocol." introductionVersion:"%%NEXT%%"`
StorageRegistry StorageRegistry `yaml:"storage_registry"` // TODO: should we even support switching this?
@@ -74,7 +74,7 @@ type GRPCConfig struct {
Addr string `yaml:"addr" env:"OCIS_GATEWAY_GRPC_ADDR;GATEWAY_GRPC_ADDR" desc:"The bind address of the GRPC service." introductionVersion:"pre5.0"`
TLS *shared.GRPCServiceTLS `yaml:"tls"`
Namespace string `yaml:"-"`
Protocol string `yaml:"protocol" env:"GATEWAY_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
Protocol string `yaml:"protocol" env:"OCIS_GRPC_PROTOCOL;GATEWAY_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"pre5.0"`
}
type StorageRegistry struct {

View File

@@ -63,3 +63,29 @@ The client that is used to authenticate with keycloak has to be able to list use
* `view-authorization`
Note that these roles are only available to assign if the client is in the `master` realm.
## Translations
The `graph` service has embedded translations sourced via transifex to provide a basic set of translated languages. These embedded translations are available for all deployment scenarios. In addition, the service supports custom translations, though it is currently not possible to just add custom translations to embedded ones. If custom translations are configured, the embedded ones are not used. To configure custom translations, the `GRAPH_TRANSLATION_PATH` environment variable needs to point to a base folder that will contain the translation files. This path must be available from all instances of the graph service, a shared storage is recommended. Translation files must be of type [.po](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html#PO-Files) or [.mo](https://www.gnu.org/software/gettext/manual/html_node/Binaries.html). For each language, the filename needs to be `graph.po` (or `graph.mo`) and stored in a folder structure defining the language code. In general the path/name pattern for a translation file needs to be:
```text
{GRAPH_TRANSLATION_PATH}/{language-code}/LC_MESSAGES/graph.po
```
The language code pattern is composed of `language[_territory]` where `language` is the base language and `_territory` is optional and defines a country.
For example, for the language `de`, one needs to place the corresponding translation files to `{GRAPH_TRANSLATION_PATH}/de_DE/LC_MESSAGES/graph.po`.
<!-- also see the notifications readme -->
Important: For the time being, the embedded ownCloud Web frontend only supports the main language code but does not handle any territory. When strings are available in the language code `language_territory`, the web frontend does not see it as it only requests `language`. In consequence, any translations made must exist in the requested `language` to avoid a fallback to the default.
### Translation Rules
* If a requested language code is not available, the service tries to fall back to the base language if available. For example, if the requested language-code `de_DE` is not available, the service tries to fall back to translations in the `de` folder.
* If the base language `de` is also not available, the service falls back to the system's default English (`en`),
which is the source of the texts provided by the code.
## Default Language
The default language can be defined via the `OCIS_DEFAULT_LANGUAGE` environment variable. See the `settings` service for a detailed description.

View File

@@ -47,6 +47,7 @@ type Spaces struct {
GroupsCacheTTL int `yaml:"groups_cache_ttl" env:"GRAPH_SPACES_GROUPS_CACHE_TTL" desc:"Max TTL in seconds for the spaces groups cache." introductionVersion:"pre5.0"`
StorageUsersAddress string `yaml:"storage_users_address" env:"GRAPH_SPACES_STORAGE_USERS_ADDRESS" desc:"The address of the storage-users service." introductionVersion:"5.0"`
DefaultLanguage string `yaml:"default_language" env:"OCIS_DEFAULT_LANGUAGE" desc:"The default language used by services and the WebUI. If not defined, English will be used as default. See the documentation for more details." introductionVersion:"5.0"`
TranslationPath string `yaml:"translation_path" env:"OCIS_TRANSLATION_PATH;GRAPH_TRANSLATION_PATH" desc:"(optional) Set this to a path with custom translations to overwrite the builtin translations. Note that file and folder naming rules apply, see the documentation for more details." introductionVersion:"%%NEXT%%"`
}
type LDAP struct {

View File

@@ -20,8 +20,8 @@ const (
)
// Translate translates a string based on the locale and default locale
func Translate(content, locale, defaultLocale string) string {
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, "", _localeFS, _localeSubPath)
func Translate(content, locale, defaultLocale, translationPath string) string {
t := l10n.NewTranslatorFromCommonConfig(defaultLocale, _domain, translationPath, _localeFS, _localeSubPath)
return t.Translate(content, locale)
}

View File

@@ -73,13 +73,13 @@ const (
)
// NewDriveItemPermissionsService creates a new DriveItemPermissionsService
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, c *config.Config) (DriveItemPermissionsService, error) {
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache identity.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) {
return DriveItemPermissionsService{
BaseGraphService: BaseGraphService{
logger: &log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemService").Logger()},
gatewaySelector: gatewaySelector,
identityCache: identityCache,
config: c,
config: config,
},
}, nil
}
@@ -130,7 +130,7 @@ func (s DriveItemPermissionsService) Invite(ctx context.Context, resourceId *sto
permission := &libregraph.Permission{}
availableRoles := unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(s.config.UnifiedRoles.AvailableRoles...))
if role := unifiedrole.CS3ResourcePermissionsToRole(availableRoles, cs3ResourcePermissions, condition); role != nil {
if role := unifiedrole.CS3ResourcePermissionsToRole(availableRoles, cs3ResourcePermissions, condition, false); role != nil {
permission.Roles = []string{role.GetId()}
}
@@ -389,6 +389,17 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
if err != nil {
return collectionOfPermissions, err
}
if s.config.IncludeOCMSharees {
driveItems, err = s.listOCMShares(ctx, []*ocm.ListOCMSharesRequest_Filter{
{
Type: ocm.ListOCMSharesRequest_Filter_TYPE_RESOURCE_ID,
Term: &ocm.ListOCMSharesRequest_Filter_ResourceId{ResourceId: itemID},
},
}, driveItems)
if err != nil {
return collectionOfPermissions, err
}
}
}
// finally get public shares, which are possible for spaceroots and "normal" resources
driveItems, err = s.listPublicShares(ctx, []*link.ListPublicSharesRequest_Filter{

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