Compare commits

...

14 Commits

Author SHA1 Message Date
OpenCloud Devops
986545da52 🎉 Release 4.0.0 (#1770)
* 🎉 Release 3.7.1

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0

* 🎉 Release 4.0.0
2025-12-01 10:30:14 +01:00
Michael Barz
0515f2f53c fix: no tag prefix for containers (#1945) 2025-12-01 10:09:40 +01:00
opencloudeu
7307cda74d [tx] updated from transifex 2025-11-30 00:02:54 +00:00
Michael Barz
7778eab752 chore: add new production version (#1941) 2025-11-29 14:13:52 +01:00
opencloudeu
778580545b [tx] updated from transifex 2025-11-29 00:02:28 +00:00
Viktor Scharf
2bdd98f5cf [full-ci] revaBump-v2.40.1 (#1927)
* revaBump-v2.40.0

* adapt tests

* bring-#442

* adapt tests

* bring-#444

* ocm fixes

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* adapt tests

* adapt unit tests

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* revaUpdate-2.40.1

* update opencloud-version-4.0.0-rc.3

---------

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
Co-authored-by: Jörn Friedrich Dreyer <jfd@butonic.de>
2025-11-28 17:34:12 +01:00
Jörn Friedrich Dreyer
043a5cf951 Merge pull request #1940 from opencloud-eu/antivirus-readme-typos
Fix typos in antivirus README documentation
2025-11-28 15:42:59 +01:00
Michael Flemming
f7ce9202de Merge pull request #1937 from opencloud-eu/add_image_signing
Add image signing
2025-11-28 14:49:30 +01:00
Michael 'Flimmy' Flemming
287cc21981 add image signing with notation 2025-11-28 14:25:19 +01:00
Jürgen Weigert
d274f42aa8 Fix typos in antivirus README documentation 2025-11-28 14:20:53 +01:00
Florian Schade
de246ddc8f Merge pull request #1936 from opencloud-eu/dedicated-events-tls-insecure
introduce OC_EVENTS_TLS_INSECURE
2025-11-28 13:40:26 +01:00
Benedikt Kulmann
9e1c22b616 Merge pull request #1938 from opencloud-eu/bump-web-4.2.1
[full-ci] chore: bump web to v4.2.1
2025-11-28 13:10:55 +01:00
Benedikt Kulmann
c18489687f chore: bump web to v4.2.1 2025-11-28 11:47:56 +01:00
Jörn Friedrich Dreyer
56817b7de7 introduce OC_EVENTS_TLS_INSECURE
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
2025-11-28 11:17:39 +01:00
100 changed files with 1064 additions and 442 deletions

View File

@@ -1,4 +1,4 @@
# The test runner source for UI tests
WEB_COMMITID=3d7367cfb1abe288d0fc0b0b1cc494a7747bcaf6
WEB_COMMITID=50e3fff6a518361d59cba864a927470f313b6f91
WEB_BRANCH=stable-4.2

View File

@@ -27,6 +27,7 @@ OC_LITMUS = "owncloudci/litmus:latest"
OC_UBUNTU = "owncloud/ubuntu:20.04"
ONLYOFFICE_DOCUMENT_SERVER = "onlyoffice/documentserver:7.5.1"
PLUGINS_DOCKER_BUILDX = "woodpeckerci/plugin-docker-buildx:latest"
PLUGINS_NOTATION = "registry.heinlein.group/opencloud/notation-wp-plugin:latest"
PLUGINS_GITHUB_RELEASE = "woodpeckerci/plugin-release"
PLUGINS_GIT_ACTION = "quay.io/thegeeklab/wp-git-action"
PLUGINS_S3 = "plugins/s3:1"
@@ -387,7 +388,7 @@ config = {
"architectures": ["arm64", "amd64"],
"production": {
# NOTE: need to be updated if new production releases are determined
"tags": ["2.0"],
"tags": ["2.0", "4.0"],
"repo": docker_repo_slug,
"build_type": "production",
},
@@ -1657,12 +1658,12 @@ def dockerRelease(ctx, repo, build_type):
# if no additional tag is given, the build-plugin adds latest
hard_tag = "daily"
if ctx.build.event == "tag":
tag_version = ctx.build.ref.replace("refs/tags/", "")
tag_version = ctx.build.ref.replace("refs/tags/v", "")
tag_parts = tag_version.split("-")
# if a tag has something appended with "-" i.e. alpha, beta, rc1...
# set the entire string as tag, else leave empty to autotag with latest
hard_tag = tag_version if len(tag_parts) > 1 else ""
# set the entire string as tag, else tag with latest (same as empty with current plugin)
hard_tag = tag_version if len(tag_parts) > 1 else "latest"
depends_on = getPipelineNames(getGoBinForTesting(ctx))
@@ -1751,6 +1752,36 @@ def dockerRelease(ctx, repo, build_type):
event["tag"],
],
},
{
"name": "notation-signing",
"image": PLUGINS_NOTATION,
"settings": {
"key": {
"from_secret": "notation_key",
},
"crt": {
"from_secret": "notation_cert",
},
"target": "registry.heinlein.group/%s:%s" % (repo, hard_tag),
"pull_image": True,
"logins": [
{
"registry": "https://registry.heinlein.group",
"username": {
"from_secret": "harbor_opencloudeu_user",
},
"password": {
"from_secret": "harbor_opencloudeu_password",
},
},
],
},
"when": [
event["cron"],
event["base"],
event["tag"],
],
},
],
"depends_on": depends_on,
"when": [

View File

@@ -1,5 +1,80 @@
# Changelog
## [4.0.0](https://github.com/opencloud-eu/opencloud/releases/tag/v4.0.0) - 2025-12-01
### ❤️ Thanks to all contributors! ❤️
@AlexAndBear, @MahdiBaghbani, @ScharfViktor, @butonic, @dragonchaser, @flimmy, @fschade, @individual-it, @jnweiger, @kulmann, @micbar, @mikelolasagasti, @pbleser-oc, @rhafer, @schweigisito
### 💥 Breaking changes
- collaboration: Enable `InsertRemoteImage` option [[#1692](https://github.com/opencloud-eu/opencloud/pull/1692)]
### 📚 Documentation
- Fix typos in antivirus README documentation [[#1940](https://github.com/opencloud-eu/opencloud/pull/1940)]
- fix: add missing service README.md files with basic description [[#1859](https://github.com/opencloud-eu/opencloud/pull/1859)]
- Fix README.md files which contain broken or missing links [[#1854](https://github.com/opencloud-eu/opencloud/pull/1854)]
### 🐛 Bug Fixes
- introduce OC_EVENTS_TLS_INSECURE [[#1936](https://github.com/opencloud-eu/opencloud/pull/1936)]
- kill unused env vars [[#1888](https://github.com/opencloud-eu/opencloud/pull/1888)]
- rc-handling was only active for the dryrun, not the real build-and-push [[#1919](https://github.com/opencloud-eu/opencloud/pull/1919)]
- handle objectguid endianess [[#1901](https://github.com/opencloud-eu/opencloud/pull/1901)]
- fix: add update server to default csp rules [[#1875](https://github.com/opencloud-eu/opencloud/pull/1875)]
- fix: add missing capability flag support-radicale [[#1891](https://github.com/opencloud-eu/opencloud/pull/1891)]
- fix opensearch client certificate [[#1890](https://github.com/opencloud-eu/opencloud/pull/1890)]
- Bump reva [[#1882](https://github.com/opencloud-eu/opencloud/pull/1882)]
- load two yaml configs [[#1617](https://github.com/opencloud-eu/opencloud/pull/1617)]
- make user cache tenant aware [[#1732](https://github.com/opencloud-eu/opencloud/pull/1732)]
- fix: sanitise markdow code to make docusaurus happy [[#1851](https://github.com/opencloud-eu/opencloud/pull/1851)]
- update launch.json [[#1843](https://github.com/opencloud-eu/opencloud/pull/1843)]
- docs: Fix auth-app examples in README [[#1844](https://github.com/opencloud-eu/opencloud/pull/1844)]
- fix: fix typo in treesize logging [[#1826](https://github.com/opencloud-eu/opencloud/pull/1826)]
- fix: set global signing secret fallback correctly [[#1781](https://github.com/opencloud-eu/opencloud/pull/1781)]
### 📈 Enhancement
- feat(ocm): add WAYF configuration for reva OCM service [[#1714](https://github.com/opencloud-eu/opencloud/pull/1714)]
- log missing name or id attributes [[#1914](https://github.com/opencloud-eu/opencloud/pull/1914)]
- collabora: Set IsAdminUser and IsAnonymousUser in CheckFileInfo [[#1745](https://github.com/opencloud-eu/opencloud/pull/1745)]
### ✅ Tests
- [full-ci] disable running ci with watch fs when full-ci [[#1902](https://github.com/opencloud-eu/opencloud/pull/1902)]
- api-tests: delete spaces before users [[#1877](https://github.com/opencloud-eu/opencloud/pull/1877)]
- update tika version [[#1872](https://github.com/opencloud-eu/opencloud/pull/1872)]
- add share sync to collaborativePosix suite [[#1806](https://github.com/opencloud-eu/opencloud/pull/1806)]
- removed test virus files from repo [[#1812](https://github.com/opencloud-eu/opencloud/pull/1812)]
- increase timeouts waiting for notification & search [[#1802](https://github.com/opencloud-eu/opencloud/pull/1802)]
- Sync share before action [[#1795](https://github.com/opencloud-eu/opencloud/pull/1795)]
- correct STORAGE_USERS_POSIX_WATCH_FS env typo in CI [[#1746](https://github.com/opencloud-eu/opencloud/pull/1746)]
### 📦️ Dependencies
- [full-ci] revaBump-v2.40.1 [[#1927](https://github.com/opencloud-eu/opencloud/pull/1927)]
- [full-ci] chore: bump web to v4.2.1 [[#1938](https://github.com/opencloud-eu/opencloud/pull/1938)]
- build(deps): bump google.golang.org/grpc from 1.76.0 to 1.77.0 [[#1923](https://github.com/opencloud-eu/opencloud/pull/1923)]
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.12.1 to 2.12.2 [[#1922](https://github.com/opencloud-eu/opencloud/pull/1922)]
- build(deps): bump github.com/kovidgoyal/imaging from 1.7.2 to 1.8.17 [[#1912](https://github.com/opencloud-eu/opencloud/pull/1912)]
- build(deps): bump golang.org/x/crypto from 0.44.0 to 0.45.0 [[#1911](https://github.com/opencloud-eu/opencloud/pull/1911)]
- [decomposed]Update version 4.0.0 rc.2 [[#1917](https://github.com/opencloud-eu/opencloud/pull/1917)]
- chore: bump web to v4.2.1-rc.1 [[#1900](https://github.com/opencloud-eu/opencloud/pull/1900)]
- revaBump-getting#428 [[#1887](https://github.com/opencloud-eu/opencloud/pull/1887)]
- build(deps): bump github.com/blevesearch/bleve/v2 from 2.5.4 to 2.5.5 [[#1884](https://github.com/opencloud-eu/opencloud/pull/1884)]
- build(deps): bump github.com/olekukonko/tablewriter from 1.1.0 to 1.1.1 [[#1869](https://github.com/opencloud-eu/opencloud/pull/1869)]
- build(deps): bump golang.org/x/term from 0.36.0 to 0.37.0 [[#1845](https://github.com/opencloud-eu/opencloud/pull/1845)]
- reva-bump-2.39.2. update opencloud 4.0.0-rc.1 [[#1849](https://github.com/opencloud-eu/opencloud/pull/1849)]
- build(deps): bump golang.org/x/sync from 0.17.0 to 0.18.0 [[#1836](https://github.com/opencloud-eu/opencloud/pull/1836)]
- build(deps): bump golang.org/x/oauth2 from 0.32.0 to 0.33.0 [[#1828](https://github.com/opencloud-eu/opencloud/pull/1828)]
- build(deps): bump github.com/KimMachineGun/automemlimit from 0.7.4 to 0.7.5 [[#1787](https://github.com/opencloud-eu/opencloud/pull/1787)]
- build(deps): bump github.com/open-policy-agent/opa from 1.9.0 to 1.10.1 [[#1788](https://github.com/opencloud-eu/opencloud/pull/1788)]
- Bump reva [[#1786](https://github.com/opencloud-eu/opencloud/pull/1786)]
- build(deps): bump github.com/gabriel-vasile/mimetype from 1.4.10 to 1.4.11 [[#1775](https://github.com/opencloud-eu/opencloud/pull/1775)]
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.12.0 to 2.12.1 [[#1706](https://github.com/opencloud-eu/opencloud/pull/1706)]
- build(deps): bump github.com/onsi/ginkgo/v2 from 2.27.1 to 2.27.2 [[#1754](https://github.com/opencloud-eu/opencloud/pull/1754)]
## [3.7.0](https://github.com/opencloud-eu/opencloud/releases/tag/v3.7.0) - 2025-11-03
### ❤️ Thanks to all contributors! ❤️

8
go.mod
View File

@@ -64,7 +64,7 @@ require (
github.com/open-policy-agent/opa v1.10.1
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
github.com/opencloud-eu/reva/v2 v2.39.3
github.com/opencloud-eu/reva/v2 v2.40.1
github.com/opensearch-project/opensearch-go/v4 v4.5.0
github.com/orcaman/concurrent-map v1.0.0
github.com/pkg/errors v0.9.1
@@ -372,9 +372,9 @@ require (
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.etcd.io/etcd/api/v3 v3.6.5 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.5 // indirect
go.etcd.io/etcd/client/v3 v3.6.5 // indirect
go.etcd.io/etcd/api/v3 v3.6.6 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect
go.etcd.io/etcd/client/v3 v3.6.6 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect

16
go.sum
View File

@@ -963,8 +963,8 @@ github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9 h1:dIft
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
github.com/opencloud-eu/reva/v2 v2.39.3 h1:/9NW08Bpy1GaNAPo8HrlyT21Flj8uNnOUyWLud1ehGc=
github.com/opencloud-eu/reva/v2 v2.39.3/go.mod h1:kkGiMeEVR59VjDsmWIczWqRcwK8cy9ogTd/u802U3NI=
github.com/opencloud-eu/reva/v2 v2.40.1 h1:QwMkbGMhwDSwfk2WxbnTpIig2BugPBaVFjWcy2DSU3U=
github.com/opencloud-eu/reva/v2 v2.40.1/go.mod h1:DGH08n2mvtsQLkt8o15FV6m51FwSJJGhjR8Ty+iIJww=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
@@ -1275,12 +1275,12 @@ github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQ
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
go.etcd.io/etcd/api/v3 v3.6.5 h1:pMMc42276sgR1j1raO/Qv3QI9Af/AuyQUW6CBAWuntA=
go.etcd.io/etcd/api/v3 v3.6.5/go.mod h1:ob0/oWA/UQQlT1BmaEkWQzI0sJ1M0Et0mMpaABxguOQ=
go.etcd.io/etcd/client/pkg/v3 v3.6.5 h1:Duz9fAzIZFhYWgRjp/FgNq2gO1jId9Yae/rLn3RrBP8=
go.etcd.io/etcd/client/pkg/v3 v3.6.5/go.mod h1:8Wx3eGRPiy0qOFMZT/hfvdos+DjEaPxdIDiCDUv/FQk=
go.etcd.io/etcd/client/v3 v3.6.5 h1:yRwZNFBx/35VKHTcLDeO7XVLbCBFbPi+XV4OC3QJf2U=
go.etcd.io/etcd/client/v3 v3.6.5/go.mod h1:ZqwG/7TAFZ0BJ0jXRPoJjKQJtbFo/9NIY8uoFFKcCyo=
go.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ=
go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4=
go.etcd.io/etcd/client/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs=
go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI=
go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec=
go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=

View File

@@ -16,7 +16,7 @@ var (
// LatestTag is the latest released version plus the dev meta version.
// Will be overwritten by the release pipeline
// Needs a manual change for every tagged release
LatestTag = "4.0.0-rc.2+dev"
LatestTag = "4.0.0-rc.3+dev"
// Date indicates the build date.
// This has been removed, it looks like you can only replace static strings with recent go versions

View File

@@ -40,7 +40,7 @@ type Config struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Ivan Fustero, 2025\n"
"Language-Team: Catalan (https://app.transifex.com/opencloud-eu/teams/204053/ca/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jörn Friedrich Dreyer <jfd@butonic.de>, 2025\n"
"Language-Team: German (https://app.transifex.com/opencloud-eu/teams/204053/de/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Elías Martín, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/opencloud-eu/teams/204053/es/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: eric_G <junk.eg@free.fr>, 2025\n"
"Language-Team: French (https://app.transifex.com/opencloud-eu/teams/204053/fr/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Simone Broglia, 2025\n"
"Language-Team: Italian (https://app.transifex.com/opencloud-eu/teams/204053/it/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Junghyuk Kwon <kwon@junghy.uk>, 2025\n"
"Language-Team: Korean (https://app.transifex.com/opencloud-eu/teams/204053/ko/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-08 00:02+0000\n"
"POT-Creation-Date: 2025-11-29 00:01+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Daniel Nylander <po@danielnylander.se>, 2025\n"
"Language-Team: Swedish (https://app.transifex.com/opencloud-eu/teams/204053/sv/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: YQS Yang, 2025\n"
"Language-Team: Chinese (https://app.transifex.com/opencloud-eu/teams/204053/zh/)\n"

View File

@@ -36,13 +36,13 @@ Several factors can make it necessary to limit the maximum filesize the antiviru
Use the `ANTIVIRUS_MAX_SCAN_SIZE` environment variable to scan only a given number of bytes,
or to skip the whole resource.
Even if it's recommended to scan the whole file, several factors like scanner type and version,
Even if it is recommended to scan the whole file, several factors like scanner type and version,
bandwidth, performance issues, etc. might make a limit necessary.
In such cases, the antivirus the max scan size mode can be handy, the following modes are available:
In such cases, the antivirus max scan size mode can be handy, the following modes are available:
- `partial`: The file is scanned up to the given size. The rest of the file is not scanned. This is the default mode `ANTIVIRUS_MAX_SCAN_SIZE=partial`
- `skip`: The file is skipped and not scanned. `ANTIVIRUS_MAX_SCAN_SIZE=skip`
- `partial`: The file is scanned up to the given size. The rest of the file is not scanned. This is the default mode `ANTIVIRUS_MAX_SCAN_SIZE_MODE=partial`
- `skip`: The file is skipped and not scanned. `ANTIVIRUS_MAX_SCAN_SIZE_MODE=skip`
**IMPORTANT**
> Streaming of files to the virus scan service still [needs to be implemented](https://github.com/owncloud/ocis/issues/6803).

View File

@@ -75,7 +75,7 @@ type Debug struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;ANTIVIRUS_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;ANTIVIRUS_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;ANTIVIRUS_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;ANTIVIRUS_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;ANTIVIRUS_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided ANTIVIRUS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;ANTIVIRUS_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;ANTIVIRUS_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -25,7 +25,7 @@ type Config struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;AUDIT_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;AUDIT_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;AUDIT_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;AUDIT_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;AUDIT_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided AUDIT_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;AUDIT_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;AUDIT_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -31,7 +31,7 @@ type Config struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;CLIENTLOG_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;CLIENTLOG_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;CLIENTLOG_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;CLIENTLOG_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;CLIENTLOG_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;CLIENTLOG_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;CLIENTLOG_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -49,7 +49,7 @@ type Store struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;EVENTHISTORY_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;EVENTHISTORY_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;EVENTHISTORY_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;EVENTHISTORY_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;EVENTHISTORY_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. Will be seen as empty if NOTIFICATIONS_EVENTS_TLS_INSECURE is provided." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;EVENTHISTORY_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;EVENTHISTORY_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -174,8 +174,8 @@ type Checksums struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;FRONTEND_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;FRONTEND_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;FRONTEND_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"FRONTEND_EVENTS_TLS_ROOT_CA_CERTIFICATE;OCS_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;FRONTEND_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;FRONTEND_EVENTS_TLS_ROOT_CA_CERTIFICATE;OCS_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;FRONTEND_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;FRONTEND_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthPassword string `yaml:"password" env:"OC_EVENTS_AUTH_PASSWORD;FRONTEND_EVENTS_AUTH_PASSWORD" desc:"The password to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -129,7 +129,7 @@ type API struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;GRAPH_EVENTS_ENDPOINT" desc:"The address of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture. Set to a empty string to disable emitting events." introductionVersion:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;GRAPH_EVENTS_CLUSTER" desc:"The clusterID of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;GRAPH_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;GRAPH_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;GRAPH_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided GRAPH_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;GRAPH_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;GRAPH_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -133,6 +133,10 @@ func CreateUserModelFromCS3(u *cs3user.User) *libregraph.User {
OnPremisesSamAccountName: u.GetUsername(),
Id: &u.GetId().OpaqueId,
}
if u.GetId().GetType() == cs3user.UserType_USER_TYPE_FEDERATED {
ocmUserId := u.GetId().GetOpaqueId() + "@" + u.GetId().GetIdp()
user.Id = &ocmUserId
}
return user
}

View File

@@ -2,6 +2,8 @@ package cache
import (
"context"
"errors"
"strings"
"time"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -133,6 +135,20 @@ func (cache IdentityCache) GetAcceptedUser(ctx context.Context, userid string) (
return *identity.CreateUserModelFromCS3(u), nil
}
func getIDAndMeshProvider(user string) (id, provider string, err error) {
last := strings.LastIndex(user, "@")
if last == -1 {
return "", "", errors.New("not in the form <id>@<provider>")
}
if len(user[:last]) == 0 {
return "", "", errors.New("empty id")
}
if len(user[last+1:]) == 0 {
return "", "", errors.New("empty provider")
}
return user[:last], user[last+1:], nil
}
func (cache IdentityCache) GetAcceptedCS3User(ctx context.Context, userid string) (*cs3User.User, error) {
var user *cs3user.User
if item := cache.users.Get(userid); item == nil {
@@ -140,8 +156,14 @@ func (cache IdentityCache) GetAcceptedCS3User(ctx context.Context, userid string
if err != nil {
return nil, errorcode.New(errorcode.GeneralException, err.Error())
}
id, provider, err := getIDAndMeshProvider(userid)
if err != nil {
return nil, errorcode.New(errorcode.InvalidRequest, err.Error())
}
cs3UserID := &cs3User.UserId{
OpaqueId: userid,
Idp: provider,
OpaqueId: id,
Type: cs3User.UserType_USER_TYPE_FEDERATED,
}
user, err = revautils.GetAcceptedUserWithContext(ctx, cs3UserID, gatewayClient)
if err != nil {

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Ivan Fustero, 2025\n"
"Language-Team: Catalan (https://app.transifex.com/opencloud-eu/teams/204053/ca/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jörn Friedrich Dreyer <jfd@butonic.de>, 2025\n"
"Language-Team: German (https://app.transifex.com/opencloud-eu/teams/204053/de/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Elías Martín, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/opencloud-eu/teams/204053/es/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: eric_G <junk.eg@free.fr>, 2025\n"
"Language-Team: French (https://app.transifex.com/opencloud-eu/teams/204053/fr/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Simone Broglia, 2025\n"
"Language-Team: Italian (https://app.transifex.com/opencloud-eu/teams/204053/it/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: gapho shin, 2025\n"
"Language-Team: Korean (https://app.transifex.com/opencloud-eu/teams/204053/ko/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-08 00:02+0000\n"
"POT-Creation-Date: 2025-11-29 00:01+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Daniel Nylander <po@danielnylander.se>, 2025\n"
"Language-Team: Swedish (https://app.transifex.com/opencloud-eu/teams/204053/sv/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: YQS Yang, 2025\n"
"Language-Team: Chinese (https://app.transifex.com/opencloud-eu/teams/204053/zh/)\n"

View File

@@ -1354,6 +1354,7 @@ var _ = Describe("Users", func() {
Username: "federated",
Id: &userv1beta1.UserId{
OpaqueId: "federated",
Idp: "provider",
Type: userv1beta1.UserType_USER_TYPE_FEDERATED,
},
},
@@ -1377,7 +1378,7 @@ var _ = Describe("Users", func() {
Expect(err).ToNot(HaveOccurred())
Expect(len(res.Value)).To(Equal(1))
Expect(res.Value[0].GetId()).To(Equal("federated"))
Expect(res.Value[0].GetId()).To(Equal("federated@provider"))
Expect(res.Value[0].GetUserType()).To(Equal("Federated"))
})
It("does not list federated users when filtering for 'Member' users", func() {

View File

@@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"reflect"
@@ -106,7 +107,8 @@ func userIdToIdentity(ctx context.Context, cache cache.IdentityCache, tennantId,
// federatedIdToIdentity looks the user for the supplied id using the cache and returns it
// as a libregraph.Identity
func federatedIdToIdentity(ctx context.Context, cache cache.IdentityCache, userID string) (libregraph.Identity, error) {
func federatedIdToIdentity(ctx context.Context, cache cache.IdentityCache, cs3UserID *cs3User.UserId) (libregraph.Identity, error) {
userID := fmt.Sprintf("%s@%s", cs3UserID.GetOpaqueId(), cs3UserID.GetIdp())
identity := libregraph.Identity{
Id: libregraph.PtrString(userID),
LibreGraphUserType: libregraph.PtrString("Federated"),
@@ -123,7 +125,7 @@ func federatedIdToIdentity(ctx context.Context, cache cache.IdentityCache, userI
// as a libregraph.Identity. Skips the user lookup if the id type is USER_TYPE_SPACE_OWNER
func cs3UserIdToIdentity(ctx context.Context, cache cache.IdentityCache, cs3UserID *cs3User.UserId) (libregraph.Identity, error) {
if cs3UserID.GetType() == cs3User.UserType_USER_TYPE_FEDERATED {
return federatedIdToIdentity(ctx, cache, cs3UserID.GetOpaqueId())
return federatedIdToIdentity(ctx, cache, cs3UserID)
}
if cs3UserID.GetType() != cs3User.UserType_USER_TYPE_SPACE_OWNER {
return userIdToIdentity(ctx, cache, cs3UserID.GetTenantId(), cs3UserID.GetOpaqueId())

View File

@@ -55,7 +55,7 @@ type SMTP struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;NOTIFICATIONS_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;NOTIFICATIONS_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;NOTIFICATIONS_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;NOTIFICATIONS_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;NOTIFICATIONS_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;NOTIFICATIONS_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;NOTIFICATIONS_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Ivan Fustero, 2025\n"
"Language-Team: Catalan (https://app.transifex.com/opencloud-eu/teams/204053/ca/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jonas, 2025\n"
"Language-Team: German (https://app.transifex.com/opencloud-eu/teams/204053/de/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: eric_G <junk.eg@free.fr>, 2025\n"
"Language-Team: French (https://app.transifex.com/opencloud-eu/teams/204053/fr/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Simone Broglia, 2025\n"
"Language-Team: Italian (https://app.transifex.com/opencloud-eu/teams/204053/it/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: gapho shin, 2025\n"
"Language-Team: Korean (https://app.transifex.com/opencloud-eu/teams/204053/ko/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-08 00:02+0000\n"
"POT-Creation-Date: 2025-11-29 00:01+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Daniel Nylander <po@danielnylander.se>, 2025\n"
"Language-Team: Swedish (https://app.transifex.com/opencloud-eu/teams/204053/sv/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: YQS Yang, 2025\n"
"Language-Team: Chinese (https://app.transifex.com/opencloud-eu/teams/204053/zh/)\n"

View File

@@ -154,7 +154,7 @@ type OCMShareProviderJSONDriver struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;OCM_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;OCM_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OCM_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;OCM_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;OCM_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided OCM_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;OCM_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;OCM_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -50,7 +50,7 @@ type Postprocessing struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;POLICIES_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;POLICIES_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;POLICIES_EVENTS_TLS_INSECURE" desc:"Whether the server should skip the client certificate verification during the TLS handshake." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;POLICIES_EVENTS_TLS_INSECURE" desc:"Whether the server should skip the client certificate verification during the TLS handshake." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;POLICIES_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided POLICIES_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;POLICIES_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;POLICIES_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -39,7 +39,7 @@ type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;POSTPROCESSING_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;POSTPROCESSING_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;POSTPROCESSING_EVENTS_TLS_INSECURE" desc:"Whether the OpenCloud server should skip the client certificate verification during the TLS handshake." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;POSTPROCESSING_EVENTS_TLS_INSECURE" desc:"Whether the OpenCloud server should skip the client certificate verification during the TLS handshake." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;POSTPROCESSING_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided POSTPROCESSING_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;POSTPROCESSING_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;POSTPROCESSING_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -227,7 +227,7 @@ type ServiceAccount struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;PROXY_EVENTS_ENDPOINT" desc:"The address of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture. Set to a empty string to disable emitting events." introductionVersion:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;PROXY_EVENTS_CLUSTER" desc:"The clusterID of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;PROXY_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;PROXY_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;PROXY_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided PROXY_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;PROXY_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;PROXY_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -11,7 +11,7 @@ type Events struct {
NumConsumers int `yaml:"num_consumers" env:"SEARCH_EVENTS_NUM_CONSUMERS" desc:"The amount of concurrent event consumers to start. Event consumers are used for searching files. Multiple consumers increase parallelisation, but will also increase CPU and memory demands." introductionVersion:"1.0.0"`
DebounceDuration int `yaml:"debounce_duration" env:"SEARCH_EVENTS_REINDEX_DEBOUNCE_DURATION" desc:"The duration in milliseconds the reindex debouncer waits before triggering a reindex of a space that was modified." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;SEARCH_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;SEARCH_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;SEARCH_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided SEARCH_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;SEARCH_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;SEARCH_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Ivan Fustero, 2025\n"
"Language-Team: Catalan (https://app.transifex.com/opencloud-eu/teams/204053/ca/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jörn Friedrich Dreyer <jfd@butonic.de>, 2025\n"
"Language-Team: German (https://app.transifex.com/opencloud-eu/teams/204053/de/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Alejandro Robles, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/opencloud-eu/teams/204053/es/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: eric_G <junk.eg@free.fr>, 2025\n"
"Language-Team: French (https://app.transifex.com/opencloud-eu/teams/204053/fr/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Simone Pagano, 2025\n"
"Language-Team: Italian (https://app.transifex.com/opencloud-eu/teams/204053/it/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: gapho shin, 2025\n"
"Language-Team: Korean (https://app.transifex.com/opencloud-eu/teams/204053/ko/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Lulufox, 2025\n"
"Language-Team: Russian (https://app.transifex.com/opencloud-eu/teams/204053/ru/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Davis Kaza, 2025\n"
"Language-Team: Swedish (https://app.transifex.com/opencloud-eu/teams/204053/sv/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: YQS Yang, 2025\n"
"Language-Team: Chinese (https://app.transifex.com/opencloud-eu/teams/204053/zh/)\n"

View File

@@ -149,7 +149,7 @@ type PublicSharingJSONCS3Driver struct {
type Events struct {
Addr string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;SHARING_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
ClusterID string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;SHARING_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;SHARING_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;SHARING_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCaCertPath string `yaml:"tls_root_ca_cert_path" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;SHARING_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided SHARING_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;SHARING_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"auth_username" env:"OC_EVENTS_AUTH_USERNAME;SHARING_EVENTS_AUTH_USERNAME" desc:"Username for the events broker." introductionVersion:"1.0.0"`

View File

@@ -49,7 +49,7 @@ type Debug struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;SSE_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;SSE_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;SSE_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;SSE_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;SSE_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided SSE_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;SSE_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;SSE_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -224,7 +224,7 @@ type PosixDriver struct {
type Events struct {
Addr string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;STORAGE_USERS_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
ClusterID string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;STORAGE_USERS_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;STORAGE_USERS_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;STORAGE_USERS_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCaCertPath string `yaml:"tls_root_ca_cert_path" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;STORAGE_USERS_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided STORAGE_USERS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;STORAGE_USERS_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
NumConsumers int `yaml:"num_consumers" env:"STORAGE_USERS_EVENTS_NUM_CONSUMERS" desc:"The amount of concurrent event consumers to start. Event consumers are used for post-processing files. Multiple consumers increase parallelisation, but will also increase CPU and memory demands. The setting has no effect when the OC_ASYNC_UPLOADS is set to false. The default and minimum value is 1." introductionVersion:"1.0.0"`

View File

@@ -52,7 +52,7 @@ type Persistence struct {
type Events struct {
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;USERLOG_EVENTS_ENDPOINT" desc:"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:"1.0.0"`
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;USERLOG_EVENTS_CLUSTER" desc:"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:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;USERLOG_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;USERLOG_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"1.0.0"`
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;USERLOG_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided NOTIFICATIONS_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"1.0.0"`
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;USERLOG_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;USERLOG_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"1.0.0"`

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Ivan Fustero, 2025\n"
"Language-Team: Catalan (https://app.transifex.com/opencloud-eu/teams/204053/ca/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jörn Friedrich Dreyer <jfd@butonic.de>, 2025\n"
"Language-Team: German (https://app.transifex.com/opencloud-eu/teams/204053/de/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Elías Martín, 2025\n"
"Language-Team: Spanish (https://app.transifex.com/opencloud-eu/teams/204053/es/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: eric_G <junk.eg@free.fr>, 2025\n"
"Language-Team: French (https://app.transifex.com/opencloud-eu/teams/204053/fr/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Simone Broglia, 2025\n"
"Language-Team: Italian (https://app.transifex.com/opencloud-eu/teams/204053/it/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: gapho shin, 2025\n"
"Language-Team: Korean (https://app.transifex.com/opencloud-eu/teams/204053/ko/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Lulufox, 2025\n"
"Language-Team: Russian (https://app.transifex.com/opencloud-eu/teams/204053/ru/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-08 00:02+0000\n"
"POT-Creation-Date: 2025-11-29 00:01+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Daniel Nylander <po@danielnylander.se>, 2025\n"
"Language-Team: Swedish (https://app.transifex.com/opencloud-eu/teams/204053/sv/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-11-09 00:02+0000\n"
"POT-Creation-Date: 2025-11-30 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: YQS Yang, 2025\n"
"Language-Team: Chinese (https://app.transifex.com/opencloud-eu/teams/204053/zh/)\n"

View File

@@ -1,6 +1,6 @@
SHELL := bash
NAME := web
WEB_ASSETS_VERSION = v4.2.1-rc.1
WEB_ASSETS_VERSION = v4.2.1
WEB_ASSETS_BRANCH = main
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI

View File

@@ -120,13 +120,12 @@ class GraphHelper {
}
/**
* Federated users have a base64 encoded string of {remoteid}@{provider} as their id
* This regex matches only non empty base64 encoded strings
* Federated users have a string of {userid}@{provider} as their id
*
* @return string
*/
public static function getFederatedUserRegex(): string {
return '(?=(.{4})*$)[A-Za-z0-9+/]*={0,2}$';
return '^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}@https?://.+$';
}
/**

View File

@@ -2440,14 +2440,6 @@ class FeatureContext extends BehatVariablesContext {
],
"parameter" => []
],
[
"code" => "%identities_issuer_id_pattern%",
"function" => [
__NAMESPACE__ . '\TestHelpers\GraphHelper',
"getFederatedUserRegex"
],
"parameter" => []
],
[
"code" => "%uuidv4_pattern%",
"function" => [

View File

@@ -327,12 +327,11 @@ class SharingNgContext implements Context {
if ($shareType === "user") {
$shareeId = $this->featureContext->getAttributeOfCreatedUser($sharee, 'id');
if ($federatedShare) {
$shareeId = (
$this->featureContext->ocmContext->getAcceptedUserByName(
$user,
$sharee
)
)['user_id'];
$federatedUser = $this->featureContext->ocmContext->getAcceptedUserByName(
$user,
$sharee
);
$shareeId = $federatedUser['user_id'] . "@" . $federatedUser['idp'];
}
} elseif ($shareType === "group") {
$shareeId = $this->featureContext->getAttributeOfCreatedGroup($sharee, 'id');
@@ -403,7 +402,11 @@ class SharingNgContext implements Context {
if ($shareType === "user") {
$shareeId = $this->featureContext->getAttributeOfCreatedUser($sharee, 'id');
if ($federatedShare) {
$shareeId = ($this->featureContext->ocmContext->getAcceptedUserByName($user, $sharee))['user_id'];
$federatedUser = $this->featureContext->ocmContext->getAcceptedUserByName(
$user,
$sharee
);
$shareeId = $federatedUser['user_id'] . "@" . $federatedUser['idp'];
}
} elseif ($shareType === "group") {
$shareeId = $this->featureContext->getAttributeOfCreatedGroup($sharee, 'id');

View File

@@ -26,7 +26,7 @@ Feature: ocm well-known URI
"const": true
},
"apiVersion": {
"const": "1.1.0"
"const": "1.2.0"
},
"endPoint": {
"pattern": "^%base_url%/ocm"
@@ -73,10 +73,24 @@ Feature: ocm well-known URI
},
"capabilities": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"minItems": 4,
"maxItems": 4,
"uniqueItems": true,
"items": {
"const": "/invite-accepted"
"oneOf": [
{
"const": "invites"
},
{
"const": "webdav-uri"
},
{
"const": "protocol-object"
},
{
"const": "invite-wayf"
}
]
}
}
}

View File

@@ -68,7 +68,7 @@ Feature: search federation users
},
"issuerAssignedId": {
"type": "string",
"pattern": "^%identities_issuer_id_pattern%$"
"pattern": "^%federated_user_id_pattern%$"
}
}
}
@@ -130,7 +130,7 @@ Feature: search federation users
},
"issuerAssignedId": {
"type": "string",
"pattern": "^%identities_issuer_id_pattern%$"
"pattern": "^%federated_user_id_pattern%$"
}
}
}
@@ -198,7 +198,7 @@ Feature: search federation users
},
"issuerAssignedId": {
"type": "string",
"pattern": "^%identities_issuer_id_pattern%$"
"pattern": "^%federated_user_id_pattern%$"
}
}
}
@@ -260,7 +260,7 @@ Feature: search federation users
},
"issuerAssignedId": {
"type": "string",
"pattern": "^%identities_issuer_id_pattern%$"
"pattern": "^%federated_user_id_pattern%$"
}
}
}
@@ -484,7 +484,7 @@ Feature: search federation users
},
"issuerAssignedId": {
"type": "string",
"pattern": "^%identities_issuer_id_pattern%$"
"pattern": "^%uuidv4_pattern%$"
}
}
}
@@ -549,7 +549,7 @@ Feature: search federation users
},
"issuerAssignedId": {
"type": "string",
"pattern": "^%identities_issuer_id_pattern%$"
"pattern": "^%uuidv4_pattern%$"
}
}
}
@@ -696,7 +696,7 @@ Feature: search federation users
},
"issuerAssignedId": {
"type": "string",
"pattern": "^%identities_issuer_id_pattern%$"
"pattern": "^%uuidv4_pattern%$"
}
}
}

View File

@@ -62,16 +62,9 @@ func RunWithOptions(mainConf map[string]interface{}, pidFile string, opts ...Opt
type coreConf struct {
MaxCPUs string `mapstructure:"max_cpus"`
TracingEnabled bool `mapstructure:"tracing_enabled"`
TracingInsecure bool `mapstructure:"tracing_insecure"`
TracingExporter string `mapstructure:"tracing_exporter"`
TracingEndpoint string `mapstructure:"tracing_endpoint"`
TracingCollector string `mapstructure:"tracing_collector"`
TracesExporter string `mapstructure:"traces_exporter"`
TracingServiceName string `mapstructure:"tracing_service_name"`
// TracingService specifies the service. i.e OpenCensus, OpenTelemetry, OpenTracing...
TracingService string `mapstructure:"tracing_service"`
GracefulShutdownTimeout int `mapstructure:"graceful_shutdown_timeout"`
}
@@ -149,20 +142,8 @@ func initServers(mainConf map[string]interface{}, log *zerolog.Logger, tp trace.
}
func initTracing(conf *coreConf) trace.TracerProvider {
if conf.TracingEnabled {
opts := []rtrace.Option{
rtrace.WithExporter(conf.TracingExporter),
rtrace.WithEndpoint(conf.TracingEndpoint),
rtrace.WithCollector(conf.TracingCollector),
rtrace.WithServiceName(conf.TracingServiceName),
}
if conf.TracingEnabled {
opts = append(opts, rtrace.WithEnabled())
}
if conf.TracingInsecure {
opts = append(opts, rtrace.WithInsecure())
}
tp := rtrace.NewTracerProvider(opts...)
if conf.TracesExporter != "none" && conf.TracesExporter != "" {
tp := rtrace.NewTracerProvider(conf.TracingServiceName, conf.TracesExporter)
rtrace.SetDefaultTracerProvider(tp)
return tp
}
@@ -281,11 +262,9 @@ func parseCoreConfOrDie(v interface{}) *coreConf {
// tracing defaults to enabled if not explicitly configured
if v == nil {
c.TracingEnabled = true
c.TracingEndpoint = "localhost:6831"
} else if _, ok := v.(map[string]interface{})["tracing_enabled"]; !ok {
c.TracingEnabled = true
c.TracingEndpoint = "localhost:6831"
c.TracesExporter = "console"
} else if _, ok := v.(map[string]interface{})["traces_exporter"]; !ok {
c.TracesExporter = "console"
}
return c

View File

@@ -174,9 +174,9 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite
remoteUser, err := s.ocmClient.InviteAccepted(ctx, ocmEndpoint, &client.InviteAcceptedRequest{
Token: req.InviteToken.GetToken(),
RecipientProvider: s.conf.ProviderDomain,
// The UserID is only a string here. To not loose the IDP information we use the FederatedID encoding
// i.e. base64(UserID@IDP)
UserID: ocmuser.FederatedID(user.GetId(), "").GetOpaqueId(),
// The UserID is only a string here. To not lose the IDP information we use the LocalUserFederatedID encoding
// i.e. UserID@IDP
UserID: ocmuser.FormatOCMUser(user.GetId()),
Email: user.GetMail(),
Name: user.GetDisplayName(),
})
@@ -217,6 +217,9 @@ func (s *service) ForwardInvite(ctx context.Context, req *invitepb.ForwardInvite
OpaqueId: remoteUser.UserID,
}
// we need to use a unique identifier for federated users
remoteUserID = ocmuser.LocalUserFederatedID(remoteUserID, "")
if err := s.repo.AddRemoteUser(ctx, user.Id, &userpb.User{
Id: remoteUserID,
Mail: remoteUser.Email,
@@ -276,6 +279,8 @@ func (s *service) AcceptInvite(ctx context.Context, req *invitepb.AcceptInviteRe
}
remoteUser := req.GetRemoteUser()
// we need to use a unique identifier for federated users
remoteUser.Id = ocmuser.LocalUserFederatedID(remoteUser.Id, "")
if err := s.repo.AddRemoteUser(ctx, token.GetUserId(), remoteUser); err != nil {
if !errors.Is(err, invite.ErrUserAlreadyAccepted) {

View File

@@ -324,11 +324,11 @@ func (s *service) CreateOCMShare(ctx context.Context, req *ocm.CreateOCMShareReq
// 2.b replace outgoing user ids with ocm user ids
// unpack the federated user id
shareWith := ocmuser.FormatOCMUser(ocmuser.RemoteID(req.GetGrantee().GetUserId()))
shareWith := ocmuser.FormatOCMUser(ocmuser.LocalUserFederatedID(req.GetGrantee().GetUserId(), ""))
// wrap the local user id in a federated user id
owner := ocmuser.FormatOCMUser(ocmuser.FederatedID(info.Owner, s.conf.ProviderDomain))
sender := ocmuser.FormatOCMUser(ocmuser.FederatedID(user.Id, s.conf.ProviderDomain))
// wrap the local user id in a local federated user id
owner := ocmuser.FormatOCMUser(ocmuser.LocalUserFederatedID(info.Owner, s.conf.ProviderDomain))
sender := ocmuser.FormatOCMUser(ocmuser.LocalUserFederatedID(user.Id, s.conf.ProviderDomain))
newShareReq := &client.NewShareRequest{
ShareWith: shareWith,

View File

@@ -0,0 +1,148 @@
// Copyright 2018-2025 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package ocmd
import (
"context"
"crypto/tls"
"encoding/json"
"io"
"net/http"
"net/url"
"time"
"github.com/opencloud-eu/reva/v2/internal/http/services/wellknown"
"github.com/opencloud-eu/reva/v2/pkg/appctx"
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
"github.com/pkg/errors"
)
// OCMClient is the client for an OCM provider.
type OCMClient struct {
client *http.Client
}
// NewClient returns a new OCMClient.
func NewClient(timeout time.Duration, insecure bool) *OCMClient {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure},
}
return &OCMClient{
client: &http.Client{
Transport: tr,
Timeout: timeout,
},
}
}
// Discover returns the OCM discovery information for a remote endpoint.
// It tries /.well-known/ocm first, then falls back to /ocm-provider (legacy).
// https://cs3org.github.io/OCM-API/docs.html?branch=develop&repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get
func (c *OCMClient) Discover(ctx context.Context, endpoint string) (*wellknown.OcmDiscoveryData, error) {
log := appctx.GetLogger(ctx)
remoteurl, _ := url.JoinPath(endpoint, "/.well-known/ocm")
body, err := c.discover(ctx, remoteurl)
if err != nil || len(body) == 0 {
log.Debug().Err(err).Str("sender", remoteurl).Str("response", string(body)).
Msg("invalid or empty response, falling back to legacy discovery")
remoteurl, _ := url.JoinPath(endpoint, "/ocm-provider") // legacy discovery endpoint
body, err = c.discover(ctx, remoteurl)
if err != nil || len(body) == 0 {
log.Warn().Err(err).Str("sender", remoteurl).Str("response", string(body)).
Msg("invalid or empty response")
return nil, errtypes.InternalError("Invalid response on OCM discovery")
}
}
var disco wellknown.OcmDiscoveryData
err = json.Unmarshal(body, &disco)
if err != nil {
log.Warn().Err(err).Str("sender", remoteurl).Str("response", string(body)).
Msg("malformed response")
return nil, errtypes.InternalError("Invalid payload on OCM discovery")
}
log.Debug().Str("sender", remoteurl).Any("response", disco).Msg("discovery response")
return &disco, nil
}
func (c *OCMClient) discover(ctx context.Context, url string) ([]byte, error) {
log := appctx.GetLogger(ctx)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, errors.Wrap(err, "error creating OCM discovery request")
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.client.Do(req)
defer func() {
if resp != nil && resp.Body != nil {
_ = resp.Body.Close()
}
}()
if err != nil {
return nil, errors.Wrap(err, "error doing OCM discovery request")
}
defer func(body io.ReadCloser) {
err := body.Close()
if err != nil {
log.Warn().Err(err).Msg("error closing response body")
}
}(resp.Body)
if resp.StatusCode != http.StatusOK {
log.Warn().Str("sender", url).Int("status", resp.StatusCode).Msg("discovery returned")
return nil, errtypes.NewErrtypeFromHTTPStatusCode(resp.StatusCode, "Remote does not offer a valid OCM discovery endpoint")
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "malformed remote OCM discovery")
}
return body, nil
}
// GetDirectoryService fetches a directory service listing from the given URL per OCM spec Appendix C.
func (c *OCMClient) GetDirectoryService(ctx context.Context, directoryURL string) (*DirectoryService, error) {
log := appctx.GetLogger(ctx)
// TODO(@MahdiBaghbani): the discover() should be changed into a generic function that can be used to fetch any OCM endpoint. I'll do it in the security PR to minimize conflicts.
body, err := c.discover(ctx, directoryURL)
if err != nil {
return nil, errors.Wrap(err, "error fetching directory service")
}
var dirService DirectoryService
if err := json.Unmarshal(body, &dirService); err != nil {
log.Warn().Err(err).Str("url", directoryURL).Str("response", string(body)).Msg("malformed directory service response")
return nil, errors.Wrap(err, "invalid directory service payload")
}
// Validate required fields
if dirService.Federation == "" {
return nil, errtypes.InternalError("directory service missing required 'federation' field")
}
// Servers can be empty array, that's valid
log.Debug().Str("url", directoryURL).Str("federation", dirService.Federation).Int("servers", len(dirService.Servers)).Msg("fetched directory service")
return &dirService, nil
}

View File

@@ -60,7 +60,7 @@ type acceptInviteRequest struct {
Email string `json:"email"`
}
// AcceptInvite informs avout an accepted invitation so that the users
// AcceptInvite informs about an accepted invitation so that the users
// can initiate the OCM share creation.
func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
@@ -73,7 +73,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
}
if req.Token == "" || req.UserID == "" || req.RecipientProvider == "" {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipiendProvider must not be null", nil)
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipientProvider must not be null", nil)
return
}
@@ -146,7 +146,7 @@ func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
}
if err := json.NewEncoder(w).Encode(&user{
UserID: ocmuser.FederatedID(acceptInviteResponse.UserId, "").GetOpaqueId(),
UserID: ocmuser.FormatOCMUser(acceptInviteResponse.UserId),
Email: acceptInviteResponse.Email,
Name: acceptInviteResponse.DisplayName,
}); err != nil {

View File

@@ -0,0 +1,33 @@
// Copyright 2025 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package ocmd
// DirectoryService represents a directory service listing per OCM spec Appendix C.
type DirectoryService struct {
Federation string `json:"federation"`
Servers []DirectoryServiceServer `json:"servers"`
}
// DirectoryServiceServer represents a single OCM server in a directory service.
type DirectoryServiceServer struct {
DisplayName string `json:"displayName"`
URL string `json:"url"`
// Added after discovery, not in raw response
InviteAcceptDialog string `json:"inviteAcceptDialog,omitempty"`
}

View File

@@ -126,7 +126,7 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
return
}
shareWith, _, err := getIDAndMeshProvider(req.ShareWith)
shareWith, _, err := getLocalUserID(req.ShareWith)
if err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, err.Error(), nil)
return
@@ -196,6 +196,22 @@ func (h *sharesHandler) CreateShare(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusCreated)
}
func getLocalUserID(user string) (id, provider string, err error) {
idPart, provider, err := getIDAndMeshProvider(user)
if err != nil {
return "", "", err
}
// Handle nested @ in idPart (e.g. "user@idp@provider")
if inner := strings.LastIndex(idPart, "@"); inner != -1 {
id = idPart[:inner]
} else {
id = idPart
}
return id, provider, nil
}
func getUserIDFromOCMUser(user string) (*userpb.UserId, error) {
id, idp, err := getIDAndMeshProvider(user)
if err != nil {
@@ -209,13 +225,18 @@ func getUserIDFromOCMUser(user string) (*userpb.UserId, error) {
}, nil
}
func getIDAndMeshProvider(user string) (string, string, error) {
// the user is in the form of dimitri@apiwise.nl
split := strings.Split(user, "@")
if len(split) < 2 {
func getIDAndMeshProvider(user string) (id, provider string, err error) {
last := strings.LastIndex(user, "@")
if last == -1 {
return "", "", errors.New("not in the form <id>@<provider>")
}
return strings.Join(split[:len(split)-1], "@"), split[len(split)-1], nil
if len(user[:last]) == 0 {
return "", "", errors.New("empty id")
}
if len(user[last+1:]) == 0 {
return "", "", errors.New("empty provider")
}
return user[:last], user[last+1:], nil
}
func getCreateShareRequest(r *http.Request) (*createShareRequest, error) {

View File

@@ -244,13 +244,30 @@ func (h *Handler) mapUserIdsFederatedShare(ctx context.Context, gw gatewayv1beta
}
}
func getIDAndMeshProvider(user string) (id, provider string, err error) {
last := strings.LastIndex(user, "@")
if last == -1 {
return "", "", errors.New("not in the form <id>@<provider>")
}
if len(user[:last]) == 0 {
return "", "", errors.New("empty id")
}
if len(user[last+1:]) == 0 {
return "", "", errors.New("empty provider")
}
return user[:last], user[last+1:], nil
}
func (h *Handler) mustGetRemoteUser(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, id string) *userIdentifiers {
s := strings.SplitN(id, "@", 2)
opaqueID, idp := s[0], s[1]
id, provider, err := getIDAndMeshProvider(id)
if err != nil {
return &userIdentifiers{}
}
userRes, err := gw.GetAcceptedUser(ctx, &invitepb.GetAcceptedUserRequest{
RemoteUserId: &userpb.UserId{
Idp: idp,
OpaqueId: opaqueID,
Type: userpb.UserType_USER_TYPE_FEDERATED,
Idp: provider,
OpaqueId: id,
},
})
if err != nil {

View File

@@ -60,12 +60,15 @@ func (s *svc) Close() error {
}
type config struct {
Prefix string `mapstructure:"prefix"`
GatewaySvc string `mapstructure:"gatewaysvc" validate:"required"`
ProviderDomain string `mapstructure:"provider_domain" validate:"required"`
MeshDirectoryURL string `mapstructure:"mesh_directory_url"`
OCMMountPoint string `mapstructure:"ocm_mount_point"`
Events EventOptions `mapstructure:"events"`
Prefix string `mapstructure:"prefix"`
GatewaySvc string `mapstructure:"gatewaysvc" validate:"required"`
ProviderDomain string `mapstructure:"provider_domain" validate:"required"`
MeshDirectoryURL string `mapstructure:"mesh_directory_url"`
OCMMountPoint string `mapstructure:"ocm_mount_point"`
DirectoryServiceURLs string `mapstructure:"directory_service_urls"`
OCMClientTimeout int `mapstructure:"ocm_client_timeout"`
OCMClientInsecure bool `mapstructure:"ocm_client_insecure"`
Events EventOptions `mapstructure:"events"`
}
// EventOptions are the configurable options for events
@@ -86,6 +89,9 @@ func (c *config) ApplyDefaults() {
if c.OCMMountPoint == "" {
c.OCMMountPoint = "/ocm"
}
if c.OCMClientTimeout == 0 {
c.OCMClientTimeout = 10
}
c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc)
}
@@ -114,6 +120,11 @@ func (s *svc) routerInit() error {
return err
}
wayfHandler := new(wayfHandler)
if err := wayfHandler.init(s.conf); err != nil {
return err
}
s.router.Post("/generate-invite", tokenHandler.Generate)
s.router.Get("/list-invite", tokenHandler.ListInvite)
s.router.Post("/accept-invite", tokenHandler.AcceptInvite)
@@ -122,6 +133,8 @@ func (s *svc) routerInit() error {
s.router.Get("/list-providers", providersHandler.ListProviders)
s.router.Post("/create-share", sharesHandler.CreateShare)
s.router.Post("/open-in-app", appsHandler.OpenInApp)
s.router.Get("/federations", wayfHandler.GetFederations)
s.router.Post("/discover", wayfHandler.DiscoverProvider)
return nil
}
@@ -130,7 +143,7 @@ func (s *svc) Prefix() string {
}
func (s *svc) Unprotected() []string {
return nil
return []string{"/federations", "/discover"}
}
func (s *svc) Handler() http.Handler {

View File

@@ -0,0 +1,259 @@
// Copyright 2018-2024 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
package sciencemesh
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/opencloud-eu/reva/v2/internal/http/services/ocmd"
"github.com/opencloud-eu/reva/v2/internal/http/services/reqres"
"github.com/opencloud-eu/reva/v2/pkg/appctx"
)
type wayfHandler struct {
directoryServices []ocmd.DirectoryService
ocmClient *ocmd.OCMClient
}
type DiscoverRequest struct {
Domain string `json:"domain"`
}
type DiscoverResponse struct {
InviteAcceptDialog string `json:"inviteAcceptDialog"`
}
// makeAbsoluteURL takes a base URL and a path/URL and returns an absolute URL.
// If dialogURL is already absolute (has scheme and host), it returns it as-is.
// Otherwise, it joins the dialogURL with the baseURL to create an absolute URL.
func makeAbsoluteURL(baseURL, dialogURL string) (string, error) {
if dialogURL == "" {
return "", nil
}
parsed, err := url.Parse(dialogURL)
if err == nil && parsed.Scheme != "" && parsed.Host != "" {
return dialogURL, nil
}
return url.JoinPath(baseURL, dialogURL)
}
func (h *wayfHandler) init(c *config) error {
log := appctx.GetLogger(context.Background())
// Create OCM client for discovery from config
h.ocmClient = ocmd.NewClient(time.Duration(c.OCMClientTimeout)*time.Second, c.OCMClientInsecure)
log.Debug().
Int("timeout_seconds", c.OCMClientTimeout).
Bool("insecure", c.OCMClientInsecure).
Msg("Created OCM client for discovery")
urls := strings.Fields(c.DirectoryServiceURLs)
if len(urls) == 0 {
log.Info().Msg("No directory service URLs configured, starting with empty list")
h.directoryServices = []ocmd.DirectoryService{}
return nil
}
log.Debug().Int("url_count", len(urls)).Strs("urls", urls).Msg("Initializing WAYF handler with directory service URLs")
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
h.directoryServices = []ocmd.DirectoryService{}
discoveryErrors := 0
validServersCount := 0
fetchErrors := 0
for _, directoryURL := range urls {
log.Debug().Str("url", directoryURL).Msg("Fetching directory service")
directoryService, err := h.ocmClient.GetDirectoryService(ctx, directoryURL)
if err != nil {
log.Info().Err(err).Str("url", directoryURL).Msg("Failed to fetch directory service, skipping")
fetchErrors++
continue
}
log.Debug().Str("federation", directoryService.Federation).Int("servers_count", len(directoryService.Servers)).Msg("Processing directory service")
var validServers []ocmd.DirectoryServiceServer
for _, srv := range directoryService.Servers {
if srv.DisplayName == "" || srv.URL == "" {
log.Debug().Str("federation", directoryService.Federation).
Str("displayName", srv.DisplayName).
Str("url", srv.URL).
Msg("Skipping server with missing displayName or url")
continue
}
log.Debug().Str("federation", directoryService.Federation).Str("server", srv.DisplayName).Str("url", srv.URL).Msg("Discovering server")
// Discover inviteAcceptDialog from OCM endpoint
disco, err := h.ocmClient.Discover(ctx, srv.URL)
if err != nil {
log.Debug().Err(err).
Str("federation", directoryService.Federation).
Str("server", srv.DisplayName).
Str("url", srv.URL).
Msg("Failed to discover server, skipping")
discoveryErrors++
continue
}
inviteDialog := disco.InviteAcceptDialog
if inviteDialog != "" {
absoluteURL, err := makeAbsoluteURL(srv.URL, inviteDialog)
if err != nil {
log.Debug().Err(err).
Str("federation", directoryService.Federation).
Str("server", srv.DisplayName).
Str("url", srv.URL).
Str("inviteDialog", disco.InviteAcceptDialog).
Msg("Failed to construct absolute URL, skipping server")
continue
}
if absoluteURL != inviteDialog {
log.Debug().Str("original", inviteDialog).Str("absolute", absoluteURL).Msg("Converted to absolute URL")
}
inviteDialog = absoluteURL
}
validServers = append(validServers, ocmd.DirectoryServiceServer{
DisplayName: srv.DisplayName,
URL: srv.URL,
InviteAcceptDialog: inviteDialog,
})
validServersCount++
log.Debug().
Str("federation", directoryService.Federation).
Str("server", srv.DisplayName).
Str("inviteAcceptDialog", inviteDialog).
Msg("Successfully discovered server")
}
if len(validServers) > 0 {
h.directoryServices = append(h.directoryServices, ocmd.DirectoryService{
Federation: directoryService.Federation,
Servers: validServers,
})
log.Debug().Str("federation", directoryService.Federation).Int("valid_servers", len(validServers)).Msg("Added directory service with valid servers")
} else {
log.Info().Str("federation", directoryService.Federation).
Msg("Directory service has no valid servers, skipping entirely")
}
}
log.Info().
Int("directory_services", len(h.directoryServices)).
Int("valid_servers", validServersCount).
Int("fetch_errors", fetchErrors).
Int("discovery_errors", discoveryErrors).
Msg("WAYF handler initialization completed")
return nil
}
func (h *wayfHandler) GetFederations(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(h.directoryServices); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "error encoding response", err)
return
}
}
func (h *wayfHandler) DiscoverProvider(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
log := appctx.GetLogger(ctx)
var req DiscoverRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "Invalid request body", err)
return
}
if req.Domain == "" {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "Domain is required", nil)
return
}
domain := req.Domain
if !strings.HasPrefix(domain, "http://") && !strings.HasPrefix(domain, "https://") {
domain = "https://" + domain
}
parsedURL, err := url.Parse(domain)
if err != nil || parsedURL.Host == "" {
reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "Invalid domain format", err)
return
}
log.Debug().Str("domain", domain).Msg("Attempting OCM discovery")
disco, err := h.ocmClient.Discover(ctx, domain)
if err != nil {
log.Info().Err(err).Str("domain", domain).Msg("Discovery failed")
reqres.WriteError(w, r, reqres.APIErrorNotFound,
fmt.Sprintf("Provider at '%s' does not support OCM discovery", req.Domain), err)
return
}
inviteDialog := disco.InviteAcceptDialog
if inviteDialog == "" {
log.Info().Str("domain", domain).Msg("Provider does not provide invite accept dialog")
reqres.WriteError(w, r, reqres.APIErrorNotFound,
fmt.Sprintf("Provider at '%s' does not provide an invite accept dialog", req.Domain), nil)
return
}
inviteDialog, err = makeAbsoluteURL(domain, inviteDialog)
if err != nil {
log.Info().Err(err).Str("domain", domain).Str("inviteDialog", disco.InviteAcceptDialog).Msg("Failed to construct invite accept dialog URL")
reqres.WriteError(w, r, reqres.APIErrorServerError, "Failed to construct invite accept dialog URL", err)
return
}
response := DiscoverResponse{
InviteAcceptDialog: inviteDialog,
}
log.Info().
Str("domain", req.Domain).
Str("inviteAcceptDialog", inviteDialog).
Msg("Discovery successful")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(response); err != nil {
reqres.WriteError(w, r, reqres.APIErrorServerError, "Error encoding response", err)
return
}
}

View File

@@ -27,25 +27,27 @@ import (
"github.com/opencloud-eu/reva/v2/pkg/appctx"
)
const OCMAPIVersion = "1.1.0"
const OCMAPIVersion = "1.2.0"
type OcmProviderConfig struct {
OCMPrefix string `docs:"ocm;The prefix URL where the OCM API is served." mapstructure:"ocm_prefix"`
Endpoint string `docs:"This host's full URL. If it's not configured, it is assumed OCM is not available." mapstructure:"endpoint"`
Provider string `docs:"reva;A friendly name that defines this service." mapstructure:"provider"`
WebdavRoot string `docs:"/remote.php/dav/ocm;The root URL of the WebDAV endpoint to serve OCM shares." mapstructure:"webdav_root"`
WebappRoot string `docs:"/external/sciencemesh;The root URL to serve Web apps via OCM." mapstructure:"webapp_root"`
EnableWebapp bool `docs:"false;Whether web apps are enabled in OCM shares." mapstructure:"enable_webapp"`
EnableDatatx bool `docs:"false;Whether data transfers are enabled in OCM shares." mapstructure:"enable_datatx"`
OCMPrefix string `docs:"ocm;The prefix URL where the OCM API is served." mapstructure:"ocm_prefix"`
Endpoint string `docs:"This host's full URL. If it's not configured, it is assumed OCM is not available." mapstructure:"endpoint"`
Provider string `docs:"reva;A friendly name that defines this service." mapstructure:"provider"`
WebdavRoot string `docs:"/remote.php/dav/ocm;The root URL of the WebDAV endpoint to serve OCM shares." mapstructure:"webdav_root"`
WebappRoot string `docs:"/external/sciencemesh;The root URL to serve Web apps via OCM." mapstructure:"webapp_root"`
InviteAcceptDialog string `docs:"/open-cloud-mesh/accept-invite;The frontend URL where to land when receiving an invitation" mapstructure:"invite_accept_dialog"`
EnableWebapp bool `docs:"false;Whether web apps are enabled in OCM shares." mapstructure:"enable_webapp"`
EnableDatatx bool `docs:"false;Whether data transfers are enabled in OCM shares." mapstructure:"enable_datatx"`
}
type OcmDiscoveryData struct {
Enabled bool `json:"enabled" xml:"enabled"`
APIVersion string `json:"apiVersion" xml:"apiVersion"`
Endpoint string `json:"endPoint" xml:"endPoint"`
Provider string `json:"provider" xml:"provider"`
ResourceTypes []resourceTypes `json:"resourceTypes" xml:"resourceTypes"`
Capabilities []string `json:"capabilities" xml:"capabilities"`
Enabled bool `json:"enabled" xml:"enabled"`
APIVersion string `json:"apiVersion" xml:"apiVersion"`
Endpoint string `json:"endPoint" xml:"endPoint"`
Provider string `json:"provider" xml:"provider"`
ResourceTypes []resourceTypes `json:"resourceTypes" xml:"resourceTypes"`
Capabilities []string `json:"capabilities" xml:"capabilities"`
InviteAcceptDialog string `json:"inviteAcceptDialog" xml:"inviteAcceptDialog"`
}
type resourceTypes struct {
@@ -77,6 +79,9 @@ func (c *OcmProviderConfig) ApplyDefaults() {
if c.WebappRoot[len(c.WebappRoot)-1:] != "/" {
c.WebappRoot += "/"
}
if c.InviteAcceptDialog == "" {
c.InviteAcceptDialog = "/open-cloud-mesh/accept-invite"
}
}
func (h *wkocmHandler) init(c *OcmProviderConfig) {
@@ -123,12 +128,13 @@ func (h *wkocmHandler) init(c *OcmProviderConfig) {
ShareTypes: []string{"user"}, // so far we only support `user`
Protocols: rtProtos, // expose the protocols as per configuration
}}
// for now we hardcode the capabilities, as this is currently only advisory
d.Capabilities = []string{"/invite-accepted"}
// for now, we hardcoded the capabilities, as this is currently only advisory
d.Capabilities = []string{"invites", "webdav-uri", "protocol-object", "invite-wayf"}
d.InviteAcceptDialog, _ = url.JoinPath(c.Endpoint, c.InviteAcceptDialog)
h.data = d
}
// This handler implements the OCM discovery endpoint specified in
// Ocm handles the OCM discovery endpoint specified in
// https://cs3org.github.io/OCM-API/docs.html?repo=OCM-API&user=cs3org#/paths/~1ocm-provider/get
func (h *wkocmHandler) Ocm(w http.ResponseWriter, r *http.Request) {
log := appctx.GetLogger(r.Context())

View File

@@ -85,7 +85,19 @@ type (
// group defines the service type: One group will get exactly one copy of a event that is emitted
// NOTE: uses reflect on initialization
func Consume(s Consumer, group string, evs ...Unmarshaller) (<-chan Event, error) {
c, err := s.Consume(MainQueueName, events.WithGroup(group))
return ConsumeWithOptions(s, ConsumeOptions{Group: group}, evs...)
}
// ConsumeWithOptions returns a channel that will get all events that match the given evs
// opts defines the options for the consumer
func ConsumeWithOptions(s Consumer, opts ConsumeOptions, evs ...Unmarshaller) (<-chan Event, error) {
o := []events.ConsumeOption{
events.WithGroup(opts.Group),
}
if !opts.AutoAck {
o = append(o, events.WithAutoAck(false, opts.AckWait))
}
c, err := s.Consume(MainQueueName, o...)
if err != nil {
return nil, err
}
@@ -126,7 +138,18 @@ func Consume(s Consumer, group string, evs ...Unmarshaller) (<-chan Event, error
// ConsumeAll allows consuming all events. Note that unmarshalling must be done manually in this case, therefore Event.Event will always be of type []byte
func ConsumeAll(s Consumer, group string) (<-chan Event, error) {
c, err := s.Consume(MainQueueName, events.WithGroup(group))
return ConsumeAllWithOptions(s, ConsumeOptions{Group: group})
}
// ConsumeAllWithOptions allows consuming all events. Note that unmarshalling must be done manually in this case, therefore Event.Event will always be of type []byte
func ConsumeAllWithOptions(s Consumer, opts ConsumeOptions) (<-chan Event, error) {
o := []events.ConsumeOption{
events.WithGroup(opts.Group),
}
if !opts.AutoAck {
o = append(o, events.WithAutoAck(false, opts.AckWait))
}
c, err := s.Consume(MainQueueName, o...)
if err != nil {
return nil, err
}

View File

@@ -0,0 +1,12 @@
package events
import (
"time"
)
// ConsumeOptions contains all the options which can be provided when consuming events
type ConsumeOptions struct {
Group string
AutoAck bool
AckWait time.Duration
}

View File

@@ -22,6 +22,7 @@ import (
"context"
"fmt"
"strconv"
"strings"
grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
@@ -331,7 +332,11 @@ func (m *manager) ldapEntryToGroup(entry *ldap.Entry) (*grouppb.Group, error) {
func (m *manager) ldapEntryToGroupID(entry *ldap.Entry) (*grouppb.GroupId, error) {
var id string
if m.c.LDAPIdentity.Group.Schema.IDIsOctetString {
rawValue := entry.GetEqualFoldRawAttributeValue(m.c.LDAPIdentity.Group.Schema.ID)
attribute := m.c.LDAPIdentity.Group.Schema.ID
rawValue := entry.GetEqualFoldRawAttributeValue(attribute)
if strings.EqualFold(attribute, "objectguid") {
rawValue = ldapIdentity.SwapObjectGUIDBytes(rawValue)
}
if value, err := uuid.FromBytes(rawValue); err == nil {
id = value.String()
} else {
@@ -350,13 +355,16 @@ func (m *manager) ldapEntryToGroupID(entry *ldap.Entry) (*grouppb.GroupId, error
func (m *manager) ldapEntryToUserID(entry *ldap.Entry) (*userpb.UserId, error) {
var uid string
if m.c.LDAPIdentity.User.Schema.IDIsOctetString {
rawValue := entry.GetEqualFoldRawAttributeValue(m.c.LDAPIdentity.User.Schema.ID)
var value uuid.UUID
var err error
if value, err = uuid.FromBytes(rawValue); err != nil {
attribute := m.c.LDAPIdentity.User.Schema.ID
rawValue := entry.GetEqualFoldRawAttributeValue(attribute)
if strings.EqualFold(attribute, "objectguid") {
rawValue = ldapIdentity.SwapObjectGUIDBytes(rawValue)
}
if value, err := uuid.FromBytes(rawValue); err == nil {
uid = value.String()
} else {
return nil, err
}
uid = value.String()
} else {
uid = entry.GetEqualFoldAttributeValue(m.c.LDAPIdentity.User.Schema.ID)
}

View File

@@ -31,7 +31,6 @@ import (
"github.com/rs/zerolog"
"go-micro.dev/v4/broker"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/credentials"
)
// Option defines a single option function.
@@ -52,10 +51,7 @@ type Options struct {
FavoriteManager favorite.Manager
GatewaySelector pool.Selectable[gateway.GatewayAPIClient]
TracingEnabled bool
TracingInsecure bool
TracingEndpoint string
TracingTransportCredentials credentials.TransportCredentials
TracesExporter string
TraceProvider trace.TracerProvider
@@ -233,33 +229,10 @@ func LockSystem(val ocdav.LockSystem) Option {
}
}
// Tracing enables tracing
// Deprecated: use WithTracingEndpoint and WithTracingEnabled, Collector is unused
func Tracing(endpoint, collector string) Option {
// WithTracesExporter option
func WithTracesExporter(exporter string) Option {
return func(o *Options) {
o.TracingEnabled = true
o.TracingEndpoint = endpoint
}
}
// WithTracingEnabled option
func WithTracingEnabled(enabled bool) Option {
return func(o *Options) {
o.TracingEnabled = enabled
}
}
// WithTracingEndpoint option
func WithTracingEndpoint(endpoint string) Option {
return func(o *Options) {
o.TracingEndpoint = endpoint
}
}
// WithTracingInsecure option
func WithTracingInsecure() Option {
return func(o *Options) {
o.TracingInsecure = true
o.TracesExporter = exporter
}
}
@@ -269,13 +242,6 @@ func WithTracingExporter(exporter string) Option {
return func(o *Options) {}
}
// WithTracingTransportCredentials option
func WithTracingTransportCredentials(v credentials.TransportCredentials) Option {
return func(o *Options) {
o.TracingTransportCredentials = v
}
}
// WithTraceProvider option
func WithTraceProvider(provider trace.TracerProvider) Option {
return func(o *Options) {

View File

@@ -91,20 +91,7 @@ func Service(opts ...Option) (micro.Service, error) {
tp := sopts.TraceProvider
if tp == nil {
topts := []rtrace.Option{
rtrace.WithEndpoint(sopts.TracingEndpoint),
rtrace.WithServiceName(sopts.Name),
}
if sopts.TracingEnabled {
topts = append(topts, rtrace.WithEnabled())
}
if sopts.TracingInsecure {
topts = append(topts, rtrace.WithInsecure())
}
if sopts.TracingTransportCredentials != nil {
topts = append(topts, rtrace.WithTransportCredentials(sopts.TracingTransportCredentials))
}
tp = rtrace.NewTracerProvider(topts...)
tp = rtrace.NewTracerProvider(sopts.Name, sopts.TracesExporter)
}
if err := useMiddlewares(r, &sopts, revaService, tp); err != nil {
return nil, err
@@ -189,10 +176,7 @@ func useMiddlewares(r *chi.Mux, sopts *Options, svc global.Service, tp trace.Tra
}
// tracing
tm := func(h http.Handler) http.Handler { return h }
if sopts.TracingEnabled {
tm = traceHandler(tp, "ocdav")
}
tm := traceHandler(tp, "ocdav")
// metrics
pm := func(h http.Handler) http.Handler { return h }

View File

@@ -1,39 +1,44 @@
package user
import (
"encoding/base64"
"fmt"
"net/url"
"strings"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
)
// FederatedID creates a federated user id by
// LocalUserFederatedID creates a federated id for local users by
// 1. stripping the protocol from the domain and
// 2. base64 encoding the opaque id with the domain to get a unique identifier that cannot collide with other users
func FederatedID(id *userpb.UserId, domain string) *userpb.UserId {
opaqueId := base64.URLEncoding.EncodeToString([]byte(id.OpaqueId + "@" + id.Idp))
return &userpb.UserId{
Type: userpb.UserType_USER_TYPE_FEDERATED,
Idp: domain,
OpaqueId: opaqueId,
// 2. if the domain is different from the idp, add the idp to the opaque id
func LocalUserFederatedID(id *userpb.UserId, domain string) *userpb.UserId {
if u, err := url.Parse(domain); err == nil && u.Host != "" {
domain = u.Host
}
u := &userpb.UserId{
Type: userpb.UserType_USER_TYPE_FEDERATED,
Idp: id.GetIdp(),
OpaqueId: id.GetOpaqueId(),
}
if domain != "" && id.GetIdp() != domain {
if id.GetIdp() != "" {
u.OpaqueId = id.GetOpaqueId() + "@" + id.GetIdp()
}
u.Idp = domain
}
return u
}
// RemoteID creates a remote user id by
// 1. decoding the base64 encoded opaque id
// 2. splitting the opaque id at the last @ to get the opaque id and the domain
func RemoteID(id *userpb.UserId) *userpb.UserId {
// DecodeRemoteUserFederatedID decodes opaque id into remote user's federated id by
// splitting the opaque id at the last @ to get the opaque id and the domain
func DecodeRemoteUserFederatedID(id *userpb.UserId) *userpb.UserId {
remoteId := &userpb.UserId{
Type: userpb.UserType_USER_TYPE_PRIMARY,
Idp: id.Idp,
OpaqueId: id.OpaqueId,
}
bytes, err := base64.URLEncoding.DecodeString(id.GetOpaqueId())
if err != nil {
return remoteId
}
remote := string(bytes)
remote := id.OpaqueId
last := strings.LastIndex(remote, "@")
if last == -1 {
return remoteId
@@ -46,5 +51,8 @@ func RemoteID(id *userpb.UserId) *userpb.UserId {
// FormatOCMUser formats a user id in the form of <opaque-id>@<idp> used by the OCM API in shareWith, owner and creator fields
func FormatOCMUser(u *userpb.UserId) string {
if u.Idp == "" {
return u.OpaqueId
}
return fmt.Sprintf("%s@%s", u.OpaqueId, u.Idp)
}

View File

@@ -328,6 +328,10 @@ func (t *Tree) HandleFileDelete(path string, sendSSE bool) error {
t.log.Error().Err(err).Str("path", path).Msg("could not purge metadata")
}
if err = t.setDirty(filepath.Dir(path), true); err != nil {
t.log.Error().Err(err).Str("path", path).Msg("could not set dirty flag")
}
if !sendSSE {
return nil
}
@@ -705,6 +709,16 @@ assimilate:
attributes.SetInt64(prefixes.BlobsizeAttr, fi.Size())
attributes.SetInt64(prefixes.TypeAttr, int64(provider.ResourceType_RESOURCE_TYPE_FILE))
n = node.New(spaceID, id, parentID, filepath.Base(path), fi.Size(), blobID, provider.ResourceType_RESOURCE_TYPE_FILE, nil, t.lookup)
n.SpaceRoot = &node.Node{BaseNode: node.BaseNode{SpaceID: spaceID, ID: spaceID}}
prevBlobSize, err := previousAttribs.Int64(prefixes.BlobsizeAttr)
if err == nil && prevBlobSize != fi.Size() {
// file size changed, trigger propagation of tree size changes
err = t.Propagate(context.Background(), n, fi.Size()-prevBlobSize)
if err != nil {
t.log.Error().Err(err).Str("path", path).Msg("could not propagate tree size changes")
}
}
}
attributes.SetTime(prefixes.MTimeAttr, fi.ModTime())
@@ -772,6 +786,15 @@ assimilate:
return nil, nil, errors.Wrap(err, "failed to set attributes")
}
// clear the status attribute if it was set before, if there was any upload to this file in progress
// it needs notice that this file was changes meanwhile.
if _, ok := previousAttribs[prefixes.StatusPrefix]; ok {
err = t.lookup.MetadataBackend().Remove(context.Background(), bn, prefixes.StatusPrefix, false)
if err != nil {
return nil, nil, errors.Wrap(err, "failed to clear status attribute")
}
}
if err := t.lookup.CacheID(context.Background(), spaceID, id, path); err != nil {
t.log.Error().Err(err).Str("spaceID", spaceID).Str("id", id).Str("path", path).Msg("could not cache id")
}

View File

@@ -35,6 +35,7 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/golang-jwt/jwt/v5"
"github.com/pkg/errors"
"github.com/rogpeppe/go-internal/lockedfile"
tusd "github.com/tus/tusd/v2/pkg/handler"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
@@ -307,11 +308,13 @@ func (session *DecomposedFsSession) Finalize(ctx context.Context) (err error) {
}
// lock the node before writing the blob
unlock, err := session.store.lu.MetadataBackend().Lock(revisionNode)
lockedNode, err := lockedfile.OpenFile(session.store.lu.MetadataBackend().LockfilePath(revisionNode), os.O_RDWR|os.O_CREATE, 0600)
if err != nil {
return err
}
defer func() { _ = unlock() }()
defer func() {
_ = lockedNode.Close()
}()
isProcessing := revisionNode.IsProcessing(ctx)
var procssingID string
@@ -322,12 +325,18 @@ func (session *DecomposedFsSession) Finalize(ctx context.Context) (err error) {
// another upload on this node is in progress or has finished since we started
if !isProcessing || procssingID != session.ID() {
versionID := revisionNode.ID + node.RevisionIDDelimiter + session.MTime().UTC().Format(time.RFC3339Nano)
revisionNode, err = node.ReadNode(ctx, session.store.lu, session.SpaceID(), versionID, false, spaceRoot, false)
if err != nil {
return fmt.Errorf("failed to read revision node %s for upload finalization: %w", versionID, err)
}
if !revisionNode.Exists {
return fmt.Errorf("revision node %s for upload finalization does not exist", versionID)
// There should be a revision node (created by the other upload that finished before us), read it and upload our blob there.
existingRevisionNode, err := node.ReadNode(ctx, session.store.lu, session.SpaceID(), versionID, false, spaceRoot, false)
if err != nil || !existingRevisionNode.Exists {
// The revision node has not been created. Likely because the file on disk was modified externally and re-assilimated (watchfs == true)
// Let's create the revision node now and upload the blob to it.
revisionNode, err = session.createRevisionNodeForUpload(ctx, revisionNode, session.MTime().UTC().Format(time.RFC3339Nano), lockedNode)
if err != nil {
appctx.GetLogger(ctx).Debug().Err(err).Str("versionID", session.MTime().UTC().Format(time.RFC3339Nano)).Msg("failed to create revision node for upload finalization")
return err
}
} else {
revisionNode = existingRevisionNode
}
// lock this node as well, before writing the blob
revisionNodeUnlock, err := session.store.lu.MetadataBackend().Lock(revisionNode)
@@ -349,6 +358,47 @@ func (session *DecomposedFsSession) Finalize(ctx context.Context) (err error) {
return nil
}
func (session *DecomposedFsSession) createRevisionNodeForUpload(ctx context.Context, baseNode *node.Node, rev string, lockedNode *lockedfile.File) (*node.Node, error) {
versionID := baseNode.ID + node.RevisionIDDelimiter + rev
log := appctx.GetLogger(ctx)
_, err := session.store.tp.CreateRevision(ctx, baseNode, rev, lockedNode)
if err != nil {
log.Error().Err(err).Str("versionID", versionID).Msg("failed to create revision node for upload")
return nil, err
}
// FIXME: We already calculated the checksums in FinishUpload, we should maybe pass them via the session instead of recalculating them here
sha1h, md5h, adler32h, err := node.CalculateChecksums(ctx, session.binPath())
if err != nil {
return nil, err
}
// update checksums
attrs := node.Attributes{
prefixes.ChecksumPrefix + "sha1": sha1h.Sum(nil),
prefixes.ChecksumPrefix + "md5": md5h.Sum(nil),
prefixes.ChecksumPrefix + "adler32": adler32h.Sum(nil),
}
revisionNode, err := node.ReadNode(ctx, session.store.lu, session.SpaceID(), versionID, false, baseNode.SpaceRoot, false)
if err == nil {
mtime := session.MTime()
attrs.SetString(prefixes.BlobIDAttr, session.ID())
attrs.SetInt64(prefixes.BlobsizeAttr, session.Size())
revisionNode.BlobID = session.ID()
revisionNode.Blobsize = session.Size()
err = session.store.lu.TimeManager().OverrideMtime(ctx, revisionNode, &attrs, mtime)
if err != nil {
return nil, errors.Wrap(err, "Decomposedfs: failed to set the mtime")
}
err = revisionNode.SetXattrsWithContext(ctx, attrs, false)
if err != nil {
return nil, errors.Wrap(err, "Decomposedfs: failed to set node attributes")
}
}
return revisionNode, err
}
func checkHash(expected string, h hash.Hash) error {
shash := hex.EncodeToString(h.Sum(nil))
if expected != shash {
@@ -389,6 +439,7 @@ func (session *DecomposedFsSession) Cleanup(revertNodeMetadata, cleanBin, cleanI
if !revisionNode.Exists {
sublog.Error().Str("versionID", versionID).Msg("revision node does not exist")
return
}
// restore the revision
@@ -400,6 +451,7 @@ func (session *DecomposedFsSession) Cleanup(revertNodeMetadata, cleanBin, cleanI
if err := session.store.tp.RestoreRevision(ctx, revisionNode, n, mtime); err != nil {
sublog.Error().Err(err).Str("versionID", versionID).Msg("restoring revision node failed")
return
}
if err := os.RemoveAll(revisionNode.InternalPath()); err != nil {

View File

@@ -1,68 +0,0 @@
package trace
import "google.golang.org/grpc/credentials"
// Options for trace
type Options struct {
Enabled bool
Insecure bool
Exporter string
Collector string
Endpoint string
ServiceName string
TransportCredentials credentials.TransportCredentials
}
// Option for trace
type Option func(o *Options)
// WithEnabled option
func WithEnabled() Option {
return func(o *Options) {
o.Enabled = true
}
}
// WithExporter option
// Deprecated: unused
func WithExporter(v string) Option {
return func(o *Options) {
o.Exporter = v
}
}
// WithInsecure option
func WithInsecure() Option {
return func(o *Options) {
o.Insecure = true
}
}
// WithCollector option
// Deprecated: unused
func WithCollector(v string) Option {
return func(o *Options) {
o.Collector = v
}
}
// WithEndpoint option
func WithEndpoint(v string) Option {
return func(o *Options) {
o.Endpoint = v
}
}
// WithServiceName option
func WithServiceName(v string) Option {
return func(o *Options) {
o.ServiceName = v
}
}
// WithTransportCredentials option
func WithTransportCredentials(v credentials.TransportCredentials) Option {
return func(o *Options) {
o.TransportCredentials = v
}
}

View File

@@ -20,21 +20,17 @@ package trace
import (
"context"
"fmt"
"sync"
"time"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/trace/noop"
)
var (
@@ -48,28 +44,42 @@ type revaDefaultTracerProvider struct {
initialized bool
}
// NewTracerProvider returns a new TracerProvider, configure for the specified service
func NewTracerProvider(opts ...Option) trace.TracerProvider {
options := Options{}
// NewTracerProvider returns a new TracerProvider, configured for the specified service
func NewTracerProvider(serviceName, exporter string) trace.TracerProvider {
var tp *sdktrace.TracerProvider
if exporter == "otlp" {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
for _, o := range opts {
o(&options)
exporter, err := otlptracegrpc.New(ctx)
if err != nil {
return nil
}
resources, err := resource.New(
context.Background(),
resource.WithFromEnv(), // Reads OTEL_RESOURCE_ATTRIBUTES and OTEL_SERVICE_NAME
resource.WithAttributes(
attribute.String("service.name", serviceName),
attribute.String("library.language", "go"),
),
)
if err != nil {
return nil
}
tp = sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resources),
)
} else {
tp = sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.NeverSample()),
)
}
if options.TransportCredentials == nil {
options.TransportCredentials = credentials.NewClientTLSFromCert(nil, "")
}
if !options.Enabled {
return noop.NewTracerProvider()
}
// default to 'reva' as service name if not set
if options.ServiceName == "" {
options.ServiceName = "reva"
}
return getOtlpTracerProvider(options)
SetDefaultTracerProvider(tp)
return tp
}
// SetDefaultTracerProvider sets the default trace provider
@@ -80,21 +90,6 @@ func SetDefaultTracerProvider(tp trace.TracerProvider) {
defaultProvider.initialized = true
}
// InitDefaultTracerProvider initializes a global default jaeger TracerProvider at a package level.
//
// Deprecated: Use NewTracerProvider and SetDefaultTracerProvider to properly initialize a tracer provider with options
func InitDefaultTracerProvider(collector, endpoint string) {
defaultProvider.mutex.Lock()
defer defaultProvider.mutex.Unlock()
if !defaultProvider.initialized {
SetDefaultTracerProvider(getOtlpTracerProvider(Options{
Endpoint: endpoint,
ServiceName: "reva default otlp provider",
Insecure: true,
}))
}
}
// DefaultProvider returns the "global" default TracerProvider
// Currently used by the pool to get the global tracer
func DefaultProvider() trace.TracerProvider {
@@ -102,42 +97,3 @@ func DefaultProvider() trace.TracerProvider {
defer defaultProvider.mutex.RUnlock()
return otel.GetTracerProvider()
}
// getOtelTracerProvider returns a new TracerProvider, configure for the specified service
func getOtlpTracerProvider(options Options) trace.TracerProvider {
transportCredentials := options.TransportCredentials
if options.Insecure {
transportCredentials = insecure.NewCredentials()
}
conn, err := grpc.NewClient(options.Endpoint,
grpc.WithTransportCredentials(transportCredentials),
)
if err != nil {
panic(fmt.Errorf("failed to create gRPC connection to endpoint: %w", err))
}
exporter, err := otlptracegrpc.New(
context.Background(),
otlptracegrpc.WithGRPCConn(conn),
)
if err != nil {
panic(err)
}
resources, err := resource.New(
context.Background(),
resource.WithAttributes(
attribute.String("service.name", options.ServiceName),
attribute.String("library.language", "go"),
),
)
if err != nil {
panic(err)
}
return sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(resources),
)
}

View File

@@ -22,6 +22,7 @@ import (
"context"
"fmt"
"strconv"
"strings"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/go-ldap/ldap/v3"
@@ -270,7 +271,11 @@ func (m *manager) ldapEntryToUser(entry *ldap.Entry) (*userpb.User, error) {
func (m *manager) ldapEntryToUserID(entry *ldap.Entry) (*userpb.UserId, error) {
var uid string
if m.c.LDAPIdentity.User.Schema.IDIsOctetString {
rawValue := entry.GetEqualFoldRawAttributeValue(m.c.LDAPIdentity.User.Schema.ID)
attribute := m.c.LDAPIdentity.User.Schema.ID
rawValue := entry.GetEqualFoldRawAttributeValue(attribute)
if strings.EqualFold(attribute, "objectguid") {
rawValue = ldapIdentity.SwapObjectGUIDBytes(rawValue)
}
if value, err := uuid.FromBytes(rawValue); err == nil {
uid = value.String()
} else {

View File

@@ -405,15 +405,19 @@ func (i *Identity) GetLDAPUserGroups(ctx context.Context, lc ldap.Client, userEn
// FIXME 1. use the memberof or members attribute of a user to get the groups
// FIXME 2. ook up the id for each group
var groupID string
attribute := i.Group.Schema.ID
if i.Group.Schema.IDIsOctetString {
raw := entry.GetEqualFoldRawAttributeValue(i.Group.Schema.ID)
value, err := uuid.FromBytes(raw)
rawValue := entry.GetEqualFoldRawAttributeValue(attribute)
if strings.EqualFold(attribute, "objectguid") {
rawValue = SwapObjectGUIDBytes(rawValue)
}
value, err := uuid.FromBytes(rawValue)
if err != nil {
return nil, err
}
groupID = value.String()
} else {
groupID = entry.GetEqualFoldAttributeValue(i.Group.Schema.ID)
groupID = entry.GetEqualFoldAttributeValue(attribute)
}
groups = append(groups, groupID)
@@ -556,17 +560,26 @@ func filterEscapeAttribute(attribute string, binary bool, id string) (string, er
return escaped, nil
}
// swapObjectGUIDBytes converts between AD's mixed-endian objectGUID format and standard UUID byte order
// AD stores objectGUID with mixed endianness 🤪 - swap first 3 components
func SwapObjectGUIDBytes(value []byte) []byte {
if len(value) != 16 {
return value
}
return []byte{
value[3], value[2], value[1], value[0], // First component (4 bytes) - reverse
value[5], value[4], // Second component (2 bytes) - reverse
value[7], value[6], // Third component (2 bytes) - reverse
value[8], value[9], value[10], value[11], value[12], value[13], value[14], value[15], // Last 8 bytes - keep as-is
}
}
func filterEscapeBinaryUUID(attribute string, value uuid.UUID) string {
bytes := value[:]
// AD stores objectGUID with mixed endianness 🤪 - swap first 3 components
if strings.EqualFold(attribute, "objectguid") {
bytes = []byte{
value[3], value[2], value[1], value[0], // First component (4 bytes) - reverse
value[5], value[4], // Second component (2 bytes) - reverse
value[7], value[6], // Third component (2 bytes) - reverse
value[8], value[9], value[10], value[11], value[12], value[13], value[14], value[15], // Last 8 bytes - keep as-is
}
bytes = SwapObjectGUIDBytes(bytes)
}
var filtered strings.Builder
@@ -656,10 +669,18 @@ func (i *Identity) getUserFindFilter(query, tenantID string) string {
for _, attr := range searchAttrs {
filter = fmt.Sprintf("%s(%s=%s)", filter, attr, squery)
}
// substring search for UUID is not possible
filter = fmt.Sprintf("(|%s(%s=%s))", filter, i.User.Schema.ID, ldap.EscapeFilter(query))
if i.Group.Schema.IDIsOctetString {
// try parsing query as uuid
idFilter, err := filterEscapeAttribute(i.User.Schema.ID, i.User.Schema.IDIsOctetString, query)
if err == nil {
filter = fmt.Sprintf("%s(%s=%s)", filter, i.User.Schema.ID, idFilter)
}
} else {
// substring search for UUID is not possible
filter = fmt.Sprintf("%s(%s=%s)", filter, i.User.Schema.ID, ldap.EscapeFilter(query))
}
return fmt.Sprintf("(&%s(objectclass=%s)%s%s)",
return fmt.Sprintf("(&%s(objectclass=%s)%s(|%s))",
i.User.Filter,
i.User.Objectclass,
i.tenantFilter(tenantID),
@@ -687,8 +708,16 @@ func (i *Identity) getGroupFindFilter(query string) string {
for _, attr := range searchAttrs {
filter = fmt.Sprintf("%s(%s=%s)", filter, attr, squery)
}
// substring search for UUID is not possible
filter = fmt.Sprintf("%s(%s=%s)", filter, i.Group.Schema.ID, ldap.EscapeFilter(query))
if i.Group.Schema.IDIsOctetString {
// try parsing query as uuid
idFilter, err := filterEscapeAttribute(i.Group.Schema.ID, i.Group.Schema.IDIsOctetString, query)
if err == nil {
filter = fmt.Sprintf("%s(%s=%s)", filter, i.Group.Schema.ID, idFilter)
}
} else {
// substring search for UUID is not possible
filter = fmt.Sprintf("%s(%s=%s)", filter, i.Group.Schema.ID, ldap.EscapeFilter(query))
}
return fmt.Sprintf("(&%s(objectclass=%s)(|%s))",
i.Group.Filter,

View File

@@ -26,7 +26,7 @@ import (
var (
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
MinClusterVersion = "3.0.0"
Version = "3.6.5"
Version = "3.6.6"
APIVersion = "unknown"
// Git SHA Value will be set during build

8
vendor/modules.txt vendored
View File

@@ -1370,7 +1370,7 @@ github.com/opencloud-eu/icap-client
# github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76
## explicit; go 1.18
github.com/opencloud-eu/libre-graph-api-go
# github.com/opencloud-eu/reva/v2 v2.39.3
# github.com/opencloud-eu/reva/v2 v2.40.1
## explicit; go 1.24.1
github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace
github.com/opencloud-eu/reva/v2/cmd/revad/runtime
@@ -2246,7 +2246,7 @@ go.etcd.io/bbolt
go.etcd.io/bbolt/errors
go.etcd.io/bbolt/internal/common
go.etcd.io/bbolt/internal/freelist
# go.etcd.io/etcd/api/v3 v3.6.5
# go.etcd.io/etcd/api/v3 v3.6.6
## explicit; go 1.24
go.etcd.io/etcd/api/v3/authpb
go.etcd.io/etcd/api/v3/etcdserverpb
@@ -2255,7 +2255,7 @@ go.etcd.io/etcd/api/v3/mvccpb
go.etcd.io/etcd/api/v3/v3rpc/rpctypes
go.etcd.io/etcd/api/v3/version
go.etcd.io/etcd/api/v3/versionpb
# go.etcd.io/etcd/client/pkg/v3 v3.6.5
# go.etcd.io/etcd/client/pkg/v3 v3.6.6
## explicit; go 1.24
go.etcd.io/etcd/client/pkg/v3/fileutil
go.etcd.io/etcd/client/pkg/v3/logutil
@@ -2264,7 +2264,7 @@ go.etcd.io/etcd/client/pkg/v3/tlsutil
go.etcd.io/etcd/client/pkg/v3/transport
go.etcd.io/etcd/client/pkg/v3/types
go.etcd.io/etcd/client/pkg/v3/verify
# go.etcd.io/etcd/client/v3 v3.6.5
# go.etcd.io/etcd/client/v3 v3.6.6
## explicit; go 1.24
go.etcd.io/etcd/client/v3
go.etcd.io/etcd/client/v3/credentials