Compare commits

..

104 Commits

Author SHA1 Message Date
OpenCloud Devops
b53b4ef1de 🎉 Release 3.7.0 (#1723)
* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0

* 🎉 Release 3.7.0
2025-11-03 16:27:10 +01:00
Viktor Scharf
c05c740fa6 bump web 4.2.0 (#1765) 2025-11-03 15:55:36 +01:00
Artur Neumann
5b98860585 check status of postprocessing before accesing the file (#1762) 2025-11-03 14:13:46 +01:00
Benedikt Kulmann
a3c3b6a07c Merge pull request #1755 from opencloud-eu/update-gh-labels
chore: update labels
2025-11-03 13:43:44 +01:00
opencloudeu
790c6b165f [tx] updated from transifex 2025-11-02 00:03:10 +00:00
opencloudeu
a2935abe3d [tx] updated from transifex 2025-11-01 00:02:51 +00:00
Benedikt Kulmann
a4856b4a80 chore: update labels 2025-10-31 15:50:26 +01:00
Ralf Haferkamp
b5b15f29de bump reva
fixes: #1747
2025-10-30 17:17:27 +01:00
opencloudeu
e270cdbfd2 [tx] updated from transifex 2025-10-29 00:03:02 +00:00
Ralf Haferkamp
e2441696c2 graph(education): 'primaryRole' and 'identities' should be optional
Related: #1597
2025-10-28 12:56:42 +01:00
Ralf Haferkamp
28ec9c3282 graph(education): Make 'schoolNumber' attribute optional
It's already optional in the spec. For mulit-tenant provisioning
we want it to be optional as well.

Related: #1597
2025-10-28 12:56:42 +01:00
Shawn Wilsher
920a6916c4 fix: only search LDAP group by name 2025-10-28 10:22:54 +01:00
Thomas Schweiger
10e77768a5 Merge pull request #1708 from opencloud-eu/schweigisito/issue1698
fix: fix #1698 - Notification email doesn't contain Message-Id header
2025-10-27 20:59:06 +01:00
Thomas Schweiger
e7a4cbaae5 fix: fix #1698 - Notification email doesn't contain Message-ID header 2025-10-27 18:56:37 +01:00
OpenCloud Devops
e62e2e0f12 🎉 Release 3.6.0 (#1537)
* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.5.1

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0

* 🎉 Release 3.6.0
2025-10-27 16:26:38 +01:00
dependabot[bot]
9cb973baac build(deps): bump github.com/onsi/ginkgo/v2 from 2.26.0 to 2.27.1
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.26.0 to 2.27.1.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.26.0...v2.27.1)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-version: 2.27.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 16:16:33 +01:00
Viktor Scharf
9e16bb9e29 bump-version-v3.6.0 (#1719) 2025-10-27 15:03:02 +01:00
Jörn Friedrich Dreyer
641dac0a88 Merge pull request #1718 from opencloud-eu/revaBump-2.39.1
revaBump-2.39.1
2025-10-27 14:12:01 +01:00
Viktor Scharf
570ec0bf97 revaBump-2.39.1 2025-10-27 13:30:13 +01:00
Jörn Friedrich Dreyer
aaaf5cf5c4 Merge pull request #1622 from opencloud-eu/shutdownorder
allow specifying a shutdown order
2025-10-27 13:13:04 +01:00
Florian Schade
fb8af22073 chore: bump reva (#1701)
* chore: bump reva

* enhancement(test): add postprocessing wait helper
2025-10-27 12:01:27 +01:00
Jörn Friedrich Dreyer
8c9f266ded allow specifying a shutdown order
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
2025-10-27 11:58:14 +01:00
Viktor Scharf
f04f6ad470 [full-ci] feat: implement OIDC authentication option (#1676)
* feat: implement Bearer Token authentication option

* fix
2025-10-27 11:17:44 +01:00
opencloudeu
c887947a85 [tx] updated from transifex 2025-10-27 00:01:43 +00:00
opencloudeu
ac8be264f0 [tx] updated from transifex 2025-10-26 00:01:09 +00:00
Thomas Schweiger
2c18d5b010 fix: apply changes from other fixes in compose repo (#1707)
* fix: apply changes from other fixes in compose repo

* temporarily disabled e2e navigation step

---------

Co-authored-by: Viktor Scharf <v.scharf@opencloud.eu>
2025-10-24 22:10:27 +02:00
Viktor Scharf
44ee182aa3 apiTest-coverage for #1523 (#1660)
* apiTest-coverage for #1523

* check propfind contans correct files name

* bump reva for getting #381
2025-10-24 09:45:03 +02:00
dependabot[bot]
d76cacd99f build(deps): bump github.com/kovidgoyal/imaging from 1.6.4 to 1.7.2
Bumps [github.com/kovidgoyal/imaging](https://github.com/kovidgoyal/imaging) from 1.6.4 to 1.7.2.
- [Release notes](https://github.com/kovidgoyal/imaging/releases)
- [Changelog](https://github.com/kovidgoyal/imaging/blob/master/.goreleaser.yaml)
- [Commits](https://github.com/kovidgoyal/imaging/compare/v1.6.4...v1.7.2)

---
updated-dependencies:
- dependency-name: github.com/kovidgoyal/imaging
  dependency-version: 1.7.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-23 17:48:43 +02:00
dependabot[bot]
fb94f34a1f build(deps): bump github.com/blevesearch/bleve/v2 from 2.5.3 to 2.5.4
Bumps [github.com/blevesearch/bleve/v2](https://github.com/blevesearch/bleve) from 2.5.3 to 2.5.4.
- [Release notes](https://github.com/blevesearch/bleve/releases)
- [Commits](https://github.com/blevesearch/bleve/compare/v2.5.3...v2.5.4)

---
updated-dependencies:
- dependency-name: github.com/blevesearch/bleve/v2
  dependency-version: 2.5.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-23 17:47:05 +02:00
dependabot[bot]
0b4c9becfb build(deps): bump golang.org/x/oauth2 from 0.31.0 to 0.32.0
Bumps [golang.org/x/oauth2](https://github.com/golang/oauth2) from 0.31.0 to 0.32.0.
- [Commits](https://github.com/golang/oauth2/compare/v0.31.0...v0.32.0)

---
updated-dependencies:
- dependency-name: golang.org/x/oauth2
  dependency-version: 0.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-23 10:54:58 +02:00
dependabot[bot]
c362d84f11 build(deps): bump golang.org/x/net from 0.44.0 to 0.46.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.44.0 to 0.46.0.
- [Commits](https://github.com/golang/net/compare/v0.44.0...v0.46.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.46.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-23 09:56:50 +02:00
opencloudeu
6e4e533e2c [tx] updated from transifex 2025-10-23 00:01:41 +00:00
Alex
f12a433b85 chore: add groupware capabilities (#1661) 2025-10-21 22:31:45 +02:00
Viktor Scharf
9108188e8a revaBumb: add groupware capabilities (#1689) 2025-10-21 14:27:26 +02:00
Viktor Scharf
18a6927b79 revaUpdate: adding groupware capabilities (#1659) 2025-10-20 19:19:12 +02:00
opencloudeu
3874c3e0d3 [tx] updated from transifex 2025-10-20 00:02:20 +00:00
opencloudeu
254f999382 [tx] updated from transifex 2025-10-16 08:04:58 +00:00
Ralf Haferkamp
b099dcdf6e fix: 'readyz' enpdoint check only required service
The readyz endpoint contained unconditional checks for the LDAP and nats
endpoints. Depending on configuration neihter LDAP nor NATS might be
required.
2025-10-14 16:49:46 +02:00
Ralf Haferkamp
d1a6cc22c1 graph: Allow the service to run without a NatsJS server
For running the Graph Education API we want to keep it possible
to run the service standalone. With an LDAP server as the only
external dependency.
2025-10-14 16:49:46 +02:00
Viktor Scharf
6c387336e1 chore/bump-web-4.1.0 (#1652)
CI shows a false failure. merge it
2025-10-13 16:09:44 +02:00
Ralf Haferkamp
805bd4305e bump reva to lastest main
for https://github.com/opencloud-eu/reva/pull/372
2025-10-13 15:22:00 +02:00
opencloudeu
d080d7415e [tx] updated from transifex 2025-10-13 00:01:42 +00:00
opencloudeu
4b2e6e4695 [tx] updated from transifex 2025-10-12 00:01:38 +00:00
Viktor Scharf
c916528788 [full-ci] deleted unused step definitions (#1639)
* deleted unused step definitions

* fix flaky tests. rearange ine numbers
2025-10-10 11:34:43 +02:00
opencloudeu
ba7aad174f [tx] updated from transifex 2025-10-09 00:05:33 +00:00
Ralf Haferkamp
e9a2ba8afc fix(settings): env var precedence
Fix the ordering of the env vars for the 'set_default_assignments'
setting. The service specific variable ('SETTINGS_SETUP_DEFAULT_ASSIGNMENTS')
should take precedence over other variable ('IDM_CREATE_DEMO_USERS' in
this case).
2025-10-08 18:06:35 +02:00
fschade
c0244fc977 enhancement(graph): resolve review feedback such as, use fmt for error wrapping, make use of store auth options, use a dedicated jetstream package 2025-10-08 16:45:16 +02:00
Christian Richter
2ca88e66da add mocks for natskv
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
53e2398f7a set server loglevel to error
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
bcafd97e31 Catch bucket not found error
Co-authored-by: Jörn Dreyer <jfd@butonic.de>

Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
006051322f set server loglevel to debug
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
351f4e6be2 Mock nats & adapt tests
Co-authored-by: Florian Schade <f.schade@opencloud.eu>

Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
5225b66f65 Move keyvalue initialisation to options
Co-authored-by: Florian Schade <f.schade@opencloud.eu>

Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Viktor Scharf
07a8fef80e fix clicommand test 2025-10-08 16:45:16 +02:00
Viktor Scharf
0399398bc8 do not save edited users 2025-10-08 16:45:16 +02:00
Viktor Scharf
681ed49dc4 deleting user by userId in test 2025-10-08 16:45:16 +02:00
Christian Richter
098ed082c8 attempt to fix broken soft delete
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
813edc4a59 use standard errors package
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
f7454e576a remove obsolete properties
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
800c7bc863 revert faulty replaces
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
ef920b040a add missing pointer
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
b815a6e0a1 respect ldap settings, add comments
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
cd295dfd9e add persistance function & userstate
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
Christian Richter
07a9308c4c add nats-js-kv connection to graph
Signed-off-by: Christian Richter <c.richter@opencloud.eu>

# Conflicts:
#	services/graph/pkg/service/v0/service.go
2025-10-08 16:45:16 +02:00
Christian Richter
63f976cac1 add nats-js-kv persistance to graph
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-10-08 16:45:16 +02:00
dependabot[bot]
0298e1cead build(deps): bump google.golang.org/grpc from 1.75.1 to 1.76.0
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.75.1 to 1.76.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.75.1...v1.76.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-version: 1.76.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-08 14:25:43 +02:00
dependabot[bot]
ef507b1241 build(deps): bump github.com/coreos/go-oidc/v3 from 3.15.0 to 3.16.0
Bumps [github.com/coreos/go-oidc/v3](https://github.com/coreos/go-oidc) from 3.15.0 to 3.16.0.
- [Release notes](https://github.com/coreos/go-oidc/releases)
- [Commits](https://github.com/coreos/go-oidc/compare/v3.15.0...v3.16.0)

---
updated-dependencies:
- dependency-name: github.com/coreos/go-oidc/v3
  dependency-version: 3.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-08 11:35:44 +02:00
dependabot[bot]
32ebeb1997 build(deps): bump github.com/grpc-ecosystem/grpc-gateway/v2
Bumps [github.com/grpc-ecosystem/grpc-gateway/v2](https://github.com/grpc-ecosystem/grpc-gateway) from 2.27.2 to 2.27.3.
- [Release notes](https://github.com/grpc-ecosystem/grpc-gateway/releases)
- [Changelog](https://github.com/grpc-ecosystem/grpc-gateway/blob/main/.goreleaser.yml)
- [Commits](https://github.com/grpc-ecosystem/grpc-gateway/compare/v2.27.2...v2.27.3)

---
updated-dependencies:
- dependency-name: github.com/grpc-ecosystem/grpc-gateway/v2
  dependency-version: 2.27.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-07 08:23:20 +02:00
dependabot[bot]
8b35fa46f2 build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.11 to 3.4.12
Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.11 to 3.4.12.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.11...v3.4.12)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-version: 3.4.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-07 08:22:49 +02:00
Viktor Scharf
2fba3c5cdd check thumbnails in the share with me response (#1605)
* check thumbnails in the share with me response

* check preview in report response
2025-10-07 07:43:46 +02:00
opencloudeu
38b1a0feb0 [tx] updated from transifex 2025-10-07 00:01:20 +00:00
Prashant Gurung
d5eadeccda fix restore browsers cache workflow (#1615)
Signed-off-by: prashant-gurung899 <prasantgrg777@gmail.com>
2025-10-06 15:40:34 +02:00
Ralf Haferkamp
9ec532da93 deps: Bump reva to latest main
for getting https://github.com/opencloud-eu/reva/pull/360
2025-10-06 11:21:57 +02:00
Ralf Haferkamp
f096285769 feat(groups): Only allow the "null" driver for multi-tenant setups 2025-10-06 11:21:57 +02:00
Ralf Haferkamp
736fb9db1f fix: make storage system user a service account
The reva auth-middleware blocks users without a tenant id, expect
system users.
2025-10-06 11:21:57 +02:00
Ralf Haferkamp
7b5c59e827 feat(reva): Pass the multi-tenancy flag to reva services
This allows to pass the multi-tenant enablement flag as a shared config
option to the reva service. This needs to be done for all reva services
since it ends up in a global variable in reva that is only initialized
once, by the service that is the first to parse its config.
See https://github.com/opencloud-eu/opencloud/issues/1563 for details.
2025-10-06 11:21:57 +02:00
Ralf Haferkamp
8cea8c8cfd feat(proxy): account_resolver multi-tenancy
Make the account resolve reject users without a tenantid, when
multi-tenancy is enabled.
2025-10-06 11:21:57 +02:00
Ralf Haferkamp
b1c50ea5a0 feat(graph): validate identity backend value 2025-10-06 11:21:57 +02:00
Ralf Haferkamp
7e86d85d62 feat: Add a global flag to enable multi-tenant support
When enabled the graph service refuses to start with the "ldap" backend.
Additional enforcements will follow in subsequent commits.
2025-10-06 11:21:57 +02:00
opencloudeu
bbf30b5802 [tx] updated from transifex 2025-10-05 00:02:32 +00:00
dependabot[bot]
4649c6ec42 build(deps): bump google.golang.org/protobuf from 1.36.9 to 1.36.10
Bumps google.golang.org/protobuf from 1.36.9 to 1.36.10.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-version: 1.36.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-02 17:10:56 +02:00
dependabot[bot]
4c00db867c build(deps): bump github.com/onsi/ginkgo/v2 from 2.25.3 to 2.26.0
Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.25.3 to 2.26.0.
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.25.3...v2.26.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-version: 2.26.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-02 17:10:28 +02:00
opencloudeu
4e06b0c376 [tx] updated from transifex 2025-10-02 00:02:45 +00:00
Ralf Haferkamp
0cb62fd685 Change status from proposed to approved 2025-10-01 10:03:45 +02:00
Ralf Haferkamp
7945229d15 adr: Add clarification about auto-provisioning 2025-10-01 10:03:45 +02:00
Ralf Haferkamp
c5861eb75f Apply suggestions from code review
Co-authored-by: Jörn Friedrich Dreyer <jfd@butonic.de>
Co-authored-by: Michael Barz <michael.barz@zeitgestalten.eu>
2025-10-01 10:03:45 +02:00
Ralf Haferkamp
5595e1696d adr: use eduation api for multi-tenancy provisioning 2025-10-01 10:03:45 +02:00
Michael Barz
3b27d8f580 change: use 404 as status when thumbnail can not be fetched (#1582) 2025-09-30 20:40:31 +02:00
Florian Schade
d4752382d5 Merge pull request #1589 from fschade/fix-1561-bump-icap-client
fix(antivirus): update icap-client library which fixes tcp socket reuse
2025-09-30 18:47:41 +02:00
dependabot[bot]
0ff15c5ce4 build(deps): bump github.com/nats-io/nats.go from 1.46.0 to 1.46.1
Bumps [github.com/nats-io/nats.go](https://github.com/nats-io/nats.go) from 1.46.0 to 1.46.1.
- [Release notes](https://github.com/nats-io/nats.go/releases)
- [Commits](https://github.com/nats-io/nats.go/compare/v1.46.0...v1.46.1)

---
updated-dependencies:
- dependency-name: github.com/nats-io/nats.go
  dependency-version: 1.46.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-30 17:08:30 +02:00
fschade
1d038e87c7 fix(antivirus): update icap-client library which fixes tcp socket reuse 2025-09-30 15:42:51 +02:00
Viktor Scharf
25246782b2 [full-ci] Enhance getSpaceByName: check local cache before Graph API calls (#1574)
* Enhance getSpaceByName: check local cache before Graph API calls

* Update API endpoint for regular user drives
2025-09-30 13:08:21 +02:00
dependabot[bot]
f4eaa8bd5b build(deps): bump github.com/olekukonko/tablewriter from 1.0.9 to 1.1.0
Bumps [github.com/olekukonko/tablewriter](https://github.com/olekukonko/tablewriter) from 1.0.9 to 1.1.0.
- [Commits](https://github.com/olekukonko/tablewriter/compare/v1.0.9...v1.1.0)

---
updated-dependencies:
- dependency-name: github.com/olekukonko/tablewriter
  dependency-version: 1.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-30 13:07:46 +02:00
tammi-23
d05d5bdc6f Merge pull request #1588 from opencloud-eu/issues/889
fix: use valid autocomplete values (axe autocomplete-valid)
2025-09-30 12:48:10 +02:00
tammi-23
b6c95b3526 fix: use valid autocomplete values (axe autocomplete-valid)
Fix is needed for https://github.com/opencloud-eu/web/issues/889
2025-09-30 12:08:27 +02:00
opencloudeu
c4156bb447 [tx] updated from transifex 2025-09-30 00:02:18 +00:00
Alex
48591d98a1 feat: add dedicated logo (web) for mobile view to theme followup (#1581) 2025-09-29 19:17:59 +02:00
Alex
075689244c feat: add dedicated logo (web) for mobile view to theme (#1579)
* feat: add dedicated logo (web) for mobile view to theme

* add svg files

* add svg files

* add svg files
2025-09-29 15:16:06 +02:00
dependabot[bot]
d1ebbde760 build(deps): bump github.com/open-policy-agent/opa from 1.8.0 to 1.9.0
Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 1.8.0 to 1.9.0.
- [Release notes](https://github.com/open-policy-agent/opa/releases)
- [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-policy-agent/opa/compare/v1.8.0...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/open-policy-agent/opa
  dependency-version: 1.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 11:13:42 +02:00
dependabot[bot]
703b8dd084 build(deps): bump github.com/nats-io/nats-server/v2
Bumps [github.com/nats-io/nats-server/v2](https://github.com/nats-io/nats-server) from 2.11.9 to 2.12.0.
- [Release notes](https://github.com/nats-io/nats-server/releases)
- [Changelog](https://github.com/nats-io/nats-server/blob/main/.goreleaser.yml)
- [Commits](https://github.com/nats-io/nats-server/compare/v2.11.9...v2.12.0)

---
updated-dependencies:
- dependency-name: github.com/nats-io/nats-server/v2
  dependency-version: 2.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 11:04:16 +02:00
Michael Barz
4a0cc1004f Fix collaboration service name (#1577)
* fix: collaboration service name

* change: do not use app name in service name

* feat: make collaboration service name configurable

* test: fix test config
2025-09-29 10:06:05 +02:00
Thomas Schweiger
754ac7a699 fix: fix typo in struct 2025-09-29 08:58:16 +02:00
Thomas Schweiger
61bfd04cb9 fix: remove deprecated web ui feature 2025-09-29 08:58:16 +02:00
Viktor Scharf
723340dba6 [full-ci] getting personal space by userId instead of userName (#1553)
* getting personal space by userId instead of userName

* delete geting userId via api call

* add new created user id to user list

* fix after review
2025-09-26 10:51:41 +02:00
637 changed files with 37080 additions and 9607 deletions

View File

@@ -1 +1,4 @@
_extends: gh-labels

View File

@@ -1,4 +1,4 @@
# The test runner source for UI tests
WEB_COMMITID=1abc9f6c9bf8b5fe6c8e9cb8418dab7911edaec7
WEB_COMMITID=6abffcc9cff31c46a341105eb6030fec56338126
WEB_BRANCH=main

View File

@@ -318,6 +318,7 @@ config = {
"USE_PREPARED_LDAP_USERS": True,
},
"extraServerEnvironment": {
"OC_MULTI_TENANT_ENABLED": True,
"OC_LDAP_USER_SCHEMA_TENANT_ID": "departmentNumber",
"OC_LDAP_URI": "ldaps://ldap-server:1636",
"OC_LDAP_INSECURE": True,
@@ -333,9 +334,11 @@ config = {
"GRAPH_LDAP_SERVER_UUID": True,
"GRAPH_LDAP_GROUP_CREATE_BASE_DN": "ou=custom,ou=groups,dc=opencloud,dc=eu",
"GRAPH_LDAP_REFINT_ENABLED": True,
"GROUPS_DRIVER": "null",
"FRONTEND_READONLY_USER_ATTRIBUTES": "user.onPremisesSamAccountName,user.displayName,user.mail,user.passwordProfile,user.accountEnabled,user.appRoleAssignments",
"OC_LDAP_SERVER_WRITE_ENABLED": False,
"OC_EXCLUDE_RUN_SERVICES": "idm",
"OC_LDAP_USER_ENABLED_ATTRIBUTE": "",
},
},
},
@@ -348,7 +351,7 @@ config = {
"part": {
"skip": False,
"totalParts": 4, # divide and run all suites in parts (divide pipelines)
"xsuites": ["search", "app-provider", "app-provider-onlyOffice", "app-store", "keycloak", "oidc", "ocm", "a11y", "mobile-view"], # suites to skip
"xsuites": ["search", "app-provider", "app-provider-onlyOffice", "app-store", "keycloak", "oidc", "ocm", "a11y", "mobile-view", "navigation"], # suites to skip
},
"search": {
"skip": False,
@@ -1074,6 +1077,7 @@ def localApiTests(name, suites, storage = "decomposed", extra_environment = {},
"WITH_REMOTE_PHP": with_remote_php,
"COLLABORATION_SERVICE_URL": "http://wopi-fakeoffice:9300",
"OC_STORAGE_PATH": "$HOME/.opencloud/storage/users",
"USE_BEARER_TOKEN": True,
}
for item in extra_environment:
@@ -2702,6 +2706,7 @@ def generateWebPnpmCache(ctx):
def cacheBrowsers(ctx):
e2e_trigger = [
event["base"],
event["cron"],
{
"event": "pull_request",
"path": {
@@ -2727,8 +2732,10 @@ def cacheBrowsers(ctx):
}]
webPnpmCacheSteps = restoreWebPnpmCache(extra_commands = [
"cd %s" % dirs["web"],
". ./.woodpecker.env",
"if $BROWSER_CACHE_FOUND; then exit 0; fi",
"cd %s" % dirs["base"],
])
browser_cache_steps = [
@@ -2739,9 +2746,9 @@ def cacheBrowsers(ctx):
"PLAYWRIGHT_BROWSERS_PATH": ".playwright",
},
"commands": [
"cd %s" % dirs["web"],
". ./.woodpecker.env",
"if $BROWSER_CACHE_FOUND; then exit 0; fi",
"cd %s" % dirs["web"],
"pnpm exec playwright install --with-deps",
"pnpm exec playwright install --list",
"tar -czf %s .playwright" % dirs["playwrightBrowsersArchive"],
@@ -2752,9 +2759,9 @@ def cacheBrowsers(ctx):
"image": MINIO_MC,
"environment": MINIO_MC_ENV,
"commands": [
"cd %s" % dirs["web"],
". ./.woodpecker.env",
"if $BROWSER_CACHE_FOUND; then exit 0; fi",
"cd %s" % dirs["web"],
"playwright_version=$(bash tests/woodpecker/script.sh get_playwright_version)",
"mc alias set s3 $MC_HOST $AWS_ACCESS_KEY_ID $AWS_SECRET_ACCESS_KEY",
"mc cp -r -a %s s3/$CACHE_BUCKET/web/browsers-cache/$playwright_version/" % dirs["playwrightBrowsersArchive"],
@@ -2973,11 +2980,13 @@ def wopiCollaborationService(name):
environment["COLLABORATION_APP_ADDR"] = "https://collabora:9980"
environment["COLLABORATION_APP_ICON"] = "https://collabora:9980/favicon.ico"
elif name == "onlyoffice":
environment["COLLABORATION_SERVICE_NAME"] = "collboration-onlyoffice"
environment["COLLABORATION_APP_NAME"] = "OnlyOffice"
environment["COLLABORATION_APP_PRODUCT"] = "OnlyOffice"
environment["COLLABORATION_APP_ADDR"] = "https://onlyoffice"
environment["COLLABORATION_APP_ICON"] = "https://onlyoffice/web-apps/apps/documenteditor/main/resources/img/favicon.ico"
elif name == "fakeoffice":
environment["COLLABORATION_SERVICE_NAME"] = "collboration-fakeoficce"
environment["COLLABORATION_APP_NAME"] = "FakeOffice"
environment["COLLABORATION_APP_PRODUCT"] = "Microsoft"
environment["COLLABORATION_APP_ADDR"] = "http://fakeoffice:8080"

View File

@@ -1,5 +1,103 @@
# Changelog
## [3.7.0](https://github.com/opencloud-eu/opencloud/releases/tag/v3.7.0) - 2025-11-03
### ❤️ Thanks to all contributors! ❤️
@ScharfViktor, @individual-it, @kulmann, @rhafer, @schweigisito, @sdwilsh
### ✅ Tests
- check status of postprocessing before accesing the file [[#1762](https://github.com/opencloud-eu/opencloud/pull/1762)]
### 📈 Enhancement
- multi-tenancy: Optional attributes on provision API [[#1663](https://github.com/opencloud-eu/opencloud/pull/1663)]
- fix: fix #1698 - Notification email doesn't contain Message-Id header [[#1708](https://github.com/opencloud-eu/opencloud/pull/1708)]
### 🐛 Bug Fixes
- fix: only search LDAP group by name [[#1724](https://github.com/opencloud-eu/opencloud/pull/1724)]
### 📦️ Dependencies
- [full-ci] bump web 4.2.0 and opencloud 3.7.0 version [[#1765](https://github.com/opencloud-eu/opencloud/pull/1765)]
## [3.6.0](https://github.com/opencloud-eu/opencloud/releases/tag/v3.6.0) - 2025-10-27
### ❤️ Thanks to all contributors! ❤️
@AlexAndBear, @ScharfViktor, @butonic, @dragonchaser, @fschade, @micbar, @prashant-gurung899, @rhafer, @schweigisito, @tammi-23
### 📈 Enhancement
- allow specifying a shutdown order [[#1622](https://github.com/opencloud-eu/opencloud/pull/1622)]
- change: use 404 as status when thumbnail can not be fetched [[#1582](https://github.com/opencloud-eu/opencloud/pull/1582)]
- feat: add dedicated logo (web) for mobile view to theme [[#1579](https://github.com/opencloud-eu/opencloud/pull/1579)]
- feat: make it possible to start the collaboration service in the single process [[#1569](https://github.com/opencloud-eu/opencloud/pull/1569)]
- introduce AppURLs helper for atomic backgroud updates [[#1542](https://github.com/opencloud-eu/opencloud/pull/1542)]
- chore: add config for capability CheckForUpdates [[#1556](https://github.com/opencloud-eu/opencloud/pull/1556)]
### ✅ Tests
- [full-ci] feat: implement OIDC authentication option [[#1676](https://github.com/opencloud-eu/opencloud/pull/1676)]
- apiTest-coverage for #1523 [[#1660](https://github.com/opencloud-eu/opencloud/pull/1660)]
- [full-ci] deleted unused step definitions [[#1639](https://github.com/opencloud-eu/opencloud/pull/1639)]
- check thumbnails in the share with me response [[#1605](https://github.com/opencloud-eu/opencloud/pull/1605)]
- [full-ci][tests-only] fix restore browsers cache workflow [[#1615](https://github.com/opencloud-eu/opencloud/pull/1615)]
- [full-ci] Enhance getSpaceByName: check local cache before Graph API calls [[#1574](https://github.com/opencloud-eu/opencloud/pull/1574)]
- [full-ci] getting personal space by userId instead of userName [[#1553](https://github.com/opencloud-eu/opencloud/pull/1553)]
- apiTest-flaky: sync share before checking [[#1550](https://github.com/opencloud-eu/opencloud/pull/1550)]
- [decomposed] use Alpine for opencloud starting [[#1547](https://github.com/opencloud-eu/opencloud/pull/1547)]
### 🐛 Bug Fixes
- fix: apply changes from other fixes in compose repo [[#1707](https://github.com/opencloud-eu/opencloud/pull/1707)]
- fix(settings): env var precedence [[#1625](https://github.com/opencloud-eu/opencloud/pull/1625)]
- fix(antivirus): update icap-client library which fixes tcp socket reuse [[#1589](https://github.com/opencloud-eu/opencloud/pull/1589)]
- fix: use valid autocomplete values (axe autocomplete-valid) [[#1588](https://github.com/opencloud-eu/opencloud/pull/1588)]
- Fix collaboration service name [[#1577](https://github.com/opencloud-eu/opencloud/pull/1577)]
- let the runtime always create a cancel context [[#1565](https://github.com/opencloud-eu/opencloud/pull/1565)]
- Bump reva and cs3apis [[#1538](https://github.com/opencloud-eu/opencloud/pull/1538)]
- use correct endpoint in nats check [[#1533](https://github.com/opencloud-eu/opencloud/pull/1533)]
### 📚 Documentation
- adr: use eduation api for multi-tenancy provisioning [[#1548](https://github.com/opencloud-eu/opencloud/pull/1548)]
- fix: remove deprecated web ui feature "OpenAppsInTab" [[#1575](https://github.com/opencloud-eu/opencloud/pull/1575)]
### 📦️ Dependencies
- build(deps): bump github.com/onsi/ginkgo/v2 from 2.26.0 to 2.27.1 [[#1705](https://github.com/opencloud-eu/opencloud/pull/1705)]
- [decomposed] bump-version-v3.6.0 [[#1719](https://github.com/opencloud-eu/opencloud/pull/1719)]
- revaBump-2.39.1 [[#1718](https://github.com/opencloud-eu/opencloud/pull/1718)]
- chore: bump reva [[#1701](https://github.com/opencloud-eu/opencloud/pull/1701)]
- build(deps): bump github.com/kovidgoyal/imaging from 1.6.4 to 1.7.2 [[#1696](https://github.com/opencloud-eu/opencloud/pull/1696)]
- build(deps): bump github.com/blevesearch/bleve/v2 from 2.5.3 to 2.5.4 [[#1697](https://github.com/opencloud-eu/opencloud/pull/1697)]
- build(deps): bump golang.org/x/oauth2 from 0.31.0 to 0.32.0 [[#1634](https://github.com/opencloud-eu/opencloud/pull/1634)]
- build(deps): bump golang.org/x/net from 0.44.0 to 0.46.0 [[#1638](https://github.com/opencloud-eu/opencloud/pull/1638)]
- revaBumb: add groupware capabilities [[#1689](https://github.com/opencloud-eu/opencloud/pull/1689)]
- revaUpdate: adding groupware capabilities [[#1659](https://github.com/opencloud-eu/opencloud/pull/1659)]
- chore/bump-web-4.1.0 [[#1652](https://github.com/opencloud-eu/opencloud/pull/1652)]
- build(deps): bump google.golang.org/grpc from 1.75.1 to 1.76.0 [[#1628](https://github.com/opencloud-eu/opencloud/pull/1628)]
- build(deps): bump github.com/coreos/go-oidc/v3 from 3.15.0 to 3.16.0 [[#1627](https://github.com/opencloud-eu/opencloud/pull/1627)]
- build(deps): bump github.com/grpc-ecosystem/grpc-gateway/v2 from 2.27.2 to 2.27.3 [[#1608](https://github.com/opencloud-eu/opencloud/pull/1608)]
- build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.11 to 3.4.12 [[#1609](https://github.com/opencloud-eu/opencloud/pull/1609)]
- build(deps): bump google.golang.org/protobuf from 1.36.9 to 1.36.10 [[#1604](https://github.com/opencloud-eu/opencloud/pull/1604)]
- build(deps): bump github.com/onsi/ginkgo/v2 from 2.25.3 to 2.26.0 [[#1603](https://github.com/opencloud-eu/opencloud/pull/1603)]
- build(deps): bump github.com/nats-io/nats.go from 1.46.0 to 1.46.1 [[#1590](https://github.com/opencloud-eu/opencloud/pull/1590)]
- build(deps): bump github.com/olekukonko/tablewriter from 1.0.9 to 1.1.0 [[#1584](https://github.com/opencloud-eu/opencloud/pull/1584)]
- build(deps): bump github.com/open-policy-agent/opa from 1.8.0 to 1.9.0 [[#1576](https://github.com/opencloud-eu/opencloud/pull/1576)]
- build(deps): bump github.com/nats-io/nats-server/v2 from 2.11.9 to 2.12.0 [[#1568](https://github.com/opencloud-eu/opencloud/pull/1568)]
- build(deps): bump golang.org/x/net from 0.43.0 to 0.44.0 [[#1567](https://github.com/opencloud-eu/opencloud/pull/1567)]
- reva bump. getting #327 [[#1555](https://github.com/opencloud-eu/opencloud/pull/1555)]
- build(deps): bump golang.org/x/image from 0.30.0 to 0.31.0 [[#1552](https://github.com/opencloud-eu/opencloud/pull/1552)]
- build(deps): bump github.com/nats-io/nats.go from 1.45.0 to 1.46.0 [[#1551](https://github.com/opencloud-eu/opencloud/pull/1551)]
- build(deps): bump golang.org/x/crypto from 0.41.0 to 0.42.0 [[#1545](https://github.com/opencloud-eu/opencloud/pull/1545)]
- build(deps): bump github.com/testcontainers/testcontainers-go/modules/opensearch from 0.38.0 to 0.39.0 [[#1544](https://github.com/opencloud-eu/opencloud/pull/1544)]
- build(deps): bump github.com/open-policy-agent/opa from 1.6.0 to 1.8.0 [[#1510](https://github.com/opencloud-eu/opencloud/pull/1510)]
- build(deps): bump google.golang.org/grpc from 1.75.0 to 1.75.1 [[#1534](https://github.com/opencloud-eu/opencloud/pull/1534)]
## [3.5.0](https://github.com/opencloud-eu/opencloud/releases/tag/v3.5.0) - 2025-09-22
### ❤️ Thanks to all contributors! ❤️

View File

@@ -663,6 +663,7 @@
"profile",
"roles",
"groups",
"OpenCloudUnique_ID",
"basic",
"email"
],
@@ -2308,7 +2309,7 @@
"always"
],
"usePasswordModifyExtendedOp": [
"false"
"true"
],
"trustEmail": [
"false"

View File

@@ -0,0 +1,79 @@
---
title: "Use the graph education API for multi-tenant user provisioning"
---
* Status: approved
* Deciders: [@micbar, @butonic, @rhafer]
* Date: 2025-09-23
Reference: https://github.com/opencloud-eu/opencloud/issues/877
## Context and Problem Statement
With the current multi-tenancy implementation, the user-management is mostly external
to the OpenCloud instance. Up to [now](../0001-simple-multi-tenancy-using-a-single-opencloud-instance.md)
we relied on some external LDAP server providing the users including their tenant assignment.
We'd like multi-tenancy to also work in environments where no such LDAP server is available.
## Decision Drivers
* Multi-tenancy must work without some existing external (as in not managed by us) LDAP server
* keep the implementation effort low
* allow integration with existing (de)provisioning systems
## Considered Options
### Use the auto-provisioning feature of OpenCloud
We already have basic auto-provsioning features implemented in OpenCloud.
Currently this is not tenant-aware, but it could be extended to support that.
This would require some changes in the way that the users are managed by the
auto-proviosioning code.
The auto-provisioning code does currently use the "normal" graph API to create
users. That API is not tenant-aware and would need to be significantly changed
to support multi-tenancy. However currently there is no real need to put
tenant-awareness into that API (and it would drive us even further a away from
compatibility with the MS Graph API). We could also switch away from the Graph API
for auto-provisioning and use some direct calls to the underlying LDAP server.
Also, using the auto-provisioning feature means that users are only created
when they first login. This means it is not possible to share files with users that
have not yet logged in. This is a significant limitation.
Also we don't currently have any de-provisioning features implemented.
### Use the existing Eudcation API of the Graph Service
We already implemented the Graph Education API in OpenCloud (based on the MS Graph Education API).
This, apart from the somewhat different naming, does already bring most of what is needed
for provisioning users in a multi-tenant environment.
The customer would just need to hookup their existing (de)provisioning system to call the
Education API to create/delete users and assign them to tenants (schools/classes).
The main drawback of this approach is that the customer needs to create some code to
hookup their existing system to the Education API.
The main advantage is that it would give the customer much more control over the users' lifecycle.
## Decision Outcome
Use the existing Education API of the Graph Service.
* Allows integration with existing (de)provisioning systems
* hopefully keeps the implementation effort low
Note: For now this means that the auto-provisioning feature will not be available for
multi-tenant setups. We might want to revisit this in the future.
### Implementation Steps
* re-vive the existing Education API implementation and run it as a separate service
* (maybe) allow to create tenants with a customer specified ID. The tenant id might also be
part of the user's claims (provided by the customer's identity provider). It would be better
if the tenant ids in our system match the tenant ids in the customer's identity provider.
* For de-provisioning to work we need to implement a way to lookup users by an external ID as
that is only unique identfier the customer's system knows for a user. While the MS Graph API
already provides an `externalId` Attribute we don't currently support that on our APIs.

93
go.mod
View File

@@ -11,20 +11,19 @@ require (
github.com/Nerzal/gocloak/v13 v13.9.0
github.com/bbalet/stopwords v1.0.0
github.com/beevik/etree v1.6.0
github.com/blevesearch/bleve/v2 v2.5.3
github.com/blevesearch/bleve/v2 v2.5.4
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.15.0
github.com/coreos/go-oidc/v3 v3.16.0
github.com/cs3org/go-cs3apis v0.0.0-20250908152307-4ca807afe54e
github.com/davidbyttow/govips/v2 v2.16.0
github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1
github.com/gabriel-vasile/mimetype v1.4.10
github.com/ggwhite/go-masker v1.1.0
github.com/go-chi/chi/v5 v5.2.3
github.com/go-chi/render v1.0.3
github.com/go-jose/go-jose/v3 v3.0.4
github.com/go-ldap/ldap/v3 v3.4.11
github.com/go-ldap/ldap/v3 v3.4.12
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3
github.com/go-micro/plugins/v4/client/grpc v1.2.1
github.com/go-micro/plugins/v4/logger/zerolog v1.2.0
@@ -34,7 +33,7 @@ require (
github.com/go-micro/plugins/v4/store/nats-js-kv v0.0.0-20240726082623-6831adfdcdc4
github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus v1.2.0
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0
github.com/go-playground/validator/v10 v10.27.0
github.com/go-playground/validator/v10 v10.28.0
github.com/gofrs/uuid v4.4.0+incompatible
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/golang/protobuf v1.5.4
@@ -43,29 +42,30 @@ require (
github.com/google/uuid v1.6.0
github.com/gookit/config/v2 v2.2.7
github.com/gorilla/mux v1.8.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3
github.com/invopop/validation v0.8.0
github.com/jellydator/ttlcache/v2 v2.11.1
github.com/jellydator/ttlcache/v3 v3.4.0
github.com/jinzhu/now v1.1.5
github.com/justinas/alice v1.2.0
github.com/kovidgoyal/imaging v1.6.4
github.com/kovidgoyal/imaging v1.7.2
github.com/leonelquinteros/gotext v1.7.2
github.com/libregraph/idm v0.5.0
github.com/libregraph/lico v0.66.0
github.com/mitchellh/mapstructure v1.5.0
github.com/mna/pigeon v1.3.0
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/nats-io/nats-server/v2 v2.11.9
github.com/nats-io/nats.go v1.46.0
github.com/nats-io/nats-server/v2 v2.12.0
github.com/nats-io/nats.go v1.47.0
github.com/oklog/run v1.2.0
github.com/olekukonko/tablewriter v1.0.9
github.com/olekukonko/tablewriter v1.1.0
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.25.3
github.com/onsi/ginkgo/v2 v2.27.1
github.com/onsi/gomega v1.38.2
github.com/open-policy-agent/opa v1.8.0
github.com/open-policy-agent/opa v1.9.0
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.38.1-0.20250924125540-eaa2437c36b2
github.com/opencloud-eu/reva/v2 v2.39.2-0.20251030154544-cac8a0257da6
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
@@ -76,7 +76,7 @@ require (
github.com/rogpeppe/go-internal v1.14.1
github.com/rs/cors v1.11.1
github.com/rs/zerolog v1.34.0
github.com/sirupsen/logrus v1.9.3
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.1
github.com/stretchr/testify v1.11.1
@@ -102,17 +102,17 @@ require (
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0
go.opentelemetry.io/otel/sdk v1.38.0
go.opentelemetry.io/otel/trace v1.38.0
golang.org/x/crypto v0.42.0
golang.org/x/crypto v0.43.0
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
golang.org/x/image v0.31.0
golang.org/x/net v0.44.0
golang.org/x/oauth2 v0.31.0
golang.org/x/image v0.32.0
golang.org/x/net v0.46.0
golang.org/x/oauth2 v0.32.0
golang.org/x/sync v0.17.0
golang.org/x/term v0.35.0
golang.org/x/text v0.29.0
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5
google.golang.org/grpc v1.75.1
google.golang.org/protobuf v1.36.9
golang.org/x/term v0.36.0
golang.org/x/text v0.30.0
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4
google.golang.org/grpc v1.76.0
google.golang.org/protobuf v1.36.10
gopkg.in/yaml.v2 v2.4.0
gotest.tools/v3 v3.5.2
stash.kopano.io/kgol/rndm v1.1.2
@@ -140,13 +140,13 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bitly/go-simplejson v0.5.0 // indirect
github.com/bits-and-blooms/bitset v1.22.0 // indirect
github.com/blevesearch/bleve_index_api v1.2.8 // indirect
github.com/blevesearch/bleve_index_api v1.2.10 // indirect
github.com/blevesearch/geo v0.2.4 // indirect
github.com/blevesearch/go-faiss v1.0.25 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect
github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.3.10 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.3.12 // indirect
github.com/blevesearch/segment v0.9.1 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
@@ -156,7 +156,7 @@ require (
github.com/blevesearch/zapx/v13 v13.4.2 // indirect
github.com/blevesearch/zapx/v14 v14.4.2 // indirect
github.com/blevesearch/zapx/v15 v15.4.2 // indirect
github.com/blevesearch/zapx/v16 v16.2.4 // indirect
github.com/blevesearch/zapx/v16 v16.2.6 // indirect
github.com/bluele/gcache v0.0.2 // indirect
github.com/bombsimon/logrusr/v3 v3.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
@@ -205,7 +205,7 @@ require (
github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/go-git/go-git/v5 v5.13.2 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.1 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
@@ -228,8 +228,8 @@ require (
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.2.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.12.0 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/gofrs/flock v0.13.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
@@ -257,11 +257,14 @@ require (
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.11 // indirect
github.com/kovidgoyal/go-parallel v1.0.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
github.com/lestrrat-go/dsig v1.0.0 // indirect
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc/v3 v3.0.0 // indirect
github.com/lestrrat-go/jwx/v3 v3.0.10 // indirect
github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect
github.com/lestrrat-go/jwx/v3 v3.0.11 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
github.com/libregraph/oidc-go v1.1.0 // indirect
@@ -296,7 +299,7 @@ require (
github.com/morikuni/aec v1.0.0 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/jwt/v2 v2.7.4 // indirect
github.com/nats-io/jwt/v2 v2.8.0 // indirect
github.com/nats-io/nkeys v0.4.11 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
@@ -318,13 +321,14 @@ require (
github.com/prometheus/alertmanager v0.28.1 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/prometheus/procfs v0.17.0 // indirect
github.com/prometheus/statsd_exporter v0.22.8 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russellhaering/goxmldsig v1.5.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/segmentio/kafka-go v0.4.49 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
@@ -332,13 +336,13 @@ require (
github.com/sergi/go-diff v1.4.0 // indirect
github.com/sethvargo/go-diceware v0.5.0 // indirect
github.com/sethvargo/go-password v0.3.1 // indirect
github.com/shamaton/msgpack/v2 v2.3.1 // indirect
github.com/shamaton/msgpack/v2 v2.4.0 // indirect
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/studio-b12/gowebdav v0.9.0 // indirect
github.com/tchap/go-patricia/v2 v2.3.3 // indirect
@@ -359,9 +363,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.4 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect
go.etcd.io/etcd/client/v3 v3.6.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.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
@@ -372,13 +376,12 @@ require (
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.27.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/mod v0.28.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/time v0.13.0 // indirect
golang.org/x/tools v0.36.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
golang.org/x/tools v0.37.0 // indirect
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
@@ -388,8 +391,6 @@ require (
replace github.com/studio-b12/gowebdav => github.com/kobergj/gowebdav v0.0.0-20250102091030-aa65266db202
replace github.com/egirna/icap-client => github.com/fschade/icap-client v0.0.0-20240802074440-aade4a234387
replace github.com/unrolled/secure => github.com/DeepDiver1975/secure v0.0.0-20240611112133-abc838fb797c
replace go-micro.dev/v4 => github.com/butonic/go-micro/v4 v4.11.1-0.20241115112658-b5d4de5ed9b3

203
go.sum
View File

@@ -108,8 +108,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e h1:4dAU9FXIyQktpoUAgOJK3OTFc/xug0PCXYCqU0FgDKI=
github.com/alexbrainman/sspi v0.0.0-20250919150558-7d374ff0d59e/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHcQQP0w=
github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.976/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
@@ -151,10 +151,10 @@ github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blevesearch/bleve/v2 v2.5.3 h1:9l1xtKaETv64SZc1jc4Sy0N804laSa/LeMbYddq1YEM=
github.com/blevesearch/bleve/v2 v2.5.3/go.mod h1:Z/e8aWjiq8HeX+nW8qROSxiE0830yQA071dwR3yoMzw=
github.com/blevesearch/bleve_index_api v1.2.8 h1:Y98Pu5/MdlkRyLM0qDHostYo7i+Vv1cDNhqTeR4Sy6Y=
github.com/blevesearch/bleve_index_api v1.2.8/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
github.com/blevesearch/bleve/v2 v2.5.4 h1:1iur8e+PHsxtncV2xIVuqlQme/V8guEDO2uV6Wll3lQ=
github.com/blevesearch/bleve/v2 v2.5.4/go.mod h1:yB4PnV4N2q5rTEpB2ndG8N2ISexBQEFIYgwx4ztfvoo=
github.com/blevesearch/bleve_index_api v1.2.10 h1:FMFmZCmTX6PdoLLvwUnKF2RsmILFFwO3h0WPevXY9fE=
github.com/blevesearch/bleve_index_api v1.2.10/go.mod h1:rKQDl4u51uwafZxFrPD1R7xFOwKnzZW7s/LSeK4lgo0=
github.com/blevesearch/geo v0.2.4 h1:ECIGQhw+QALCZaDcogRTNSJYQXRtC8/m8IKiA706cqk=
github.com/blevesearch/geo v0.2.4/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8=
github.com/blevesearch/go-faiss v1.0.25 h1:lel1rkOUGbT1CJ0YgzKwC7k+XH0XVBHnCVWahdCXk4U=
@@ -165,8 +165,8 @@ github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZG
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
github.com/blevesearch/scorch_segment_api/v2 v2.3.10 h1:Yqk0XD1mE0fDZAJXTjawJ8If/85JxnLd8v5vG/jWE/s=
github.com/blevesearch/scorch_segment_api/v2 v2.3.10/go.mod h1:Z3e6ChN3qyN35yaQpl00MfI5s8AxUJbpTR/DL8QOQ+8=
github.com/blevesearch/scorch_segment_api/v2 v2.3.12 h1:GGZc2qwbyRBwtckPPkHkLyXw64mmsLJxdturBI1cM+c=
github.com/blevesearch/scorch_segment_api/v2 v2.3.12/go.mod h1:JBRGAneqgLSI2+jCNjtwMqp2B7EBF3/VUzgDPIU33MM=
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
@@ -185,8 +185,8 @@ github.com/blevesearch/zapx/v14 v14.4.2 h1:2SGHakVKd+TrtEqpfeq8X+So5PShQ5nW6GNxT
github.com/blevesearch/zapx/v14 v14.4.2/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8=
github.com/blevesearch/zapx/v15 v15.4.2 h1:sWxpDE0QQOTjyxYbAVjt3+0ieu8NCE0fDRaFxEsp31k=
github.com/blevesearch/zapx/v15 v15.4.2/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw=
github.com/blevesearch/zapx/v16 v16.2.4 h1:tGgfvleXTAkwsD5mEzgM3zCS/7pgocTCnO1oyAUjlww=
github.com/blevesearch/zapx/v16 v16.2.4/go.mod h1:Rti/REtuuMmzwsI8/C/qIzRaEoSK/wiFYw5e5ctUKKs=
github.com/blevesearch/zapx/v16 v16.2.6 h1:OHuUl2GhM+FpBq9RwNsJ4k/QodqbMMHoQEgn/IHYpu8=
github.com/blevesearch/zapx/v16 v16.2.6/go.mod h1:cuAPB+YoIyRngNhno1S1GPr9SfMk+x/SgAHBLXSIq3k=
github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw=
github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
@@ -237,8 +237,8 @@ github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsW
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc/v3 v3.15.0 h1:R6Oz8Z4bqWR7VFQ+sPSvZPQv4x8M+sJkDO5ojgwlyAg=
github.com/coreos/go-oidc/v3 v3.15.0/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU=
github.com/coreos/go-oidc/v3 v3.16.0 h1:qRQUCFstKpXwmEjDQTIbyY/5jF00+asXzSkmkoa/mow=
github.com/coreos/go-oidc/v3 v3.16.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
@@ -345,8 +345,6 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/fschade/icap-client v0.0.0-20240802074440-aade4a234387 h1:Y3wZgTr29sLxWSMz4KF91o0x87EaJF6FIPNJFepRIiw=
github.com/fschade/icap-client v0.0.0-20240802074440-aade4a234387/go.mod h1:HpntrRsQA6RKNXy2Nbr4kVj+NO3OYWpAQUVxeya+3sU=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
@@ -359,6 +357,12 @@ github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s
github.com/ggwhite/go-masker v1.1.0 h1:kN/KIvktu2U+hd3KWrSlLj7xBGD1iBfc9/xdbVgFbRc=
github.com/ggwhite/go-masker v1.1.0/go.mod h1:xnTRHwrIU9FtBADwEjUC5Dy/BVedvoTxyOE7/d3CNwY=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs=
github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo=
github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M=
github.com/gkampitakis/go-diff v1.3.2/go.mod h1:LLgOrpqleQe26cte8s36HTWcTmMEur6OPYerdAAS9tk=
github.com/gkampitakis/go-snaps v0.5.15 h1:amyJrvM1D33cPHwVrjo9jQxX8g/7E2wYdZ+01KS3zGE=
github.com/gkampitakis/go-snaps v0.5.15/go.mod h1:HNpx/9GoKisdhw9AFOBT1N7DBs9DiHo/hGheFGBZ+mc=
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/go-acme/lego/v4 v4.4.0 h1:uHhU5LpOYQOdp3aDU+XY2bajseu8fuExphTL1Ss6/Fc=
@@ -390,8 +394,8 @@ github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
@@ -399,8 +403,8 @@ github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q=
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM=
github.com/go-ldap/ldap/v3 v3.4.12 h1:1b81mv7MagXZ7+1r7cLTWmyuTqVqdwbtJSjC0DAp9s4=
github.com/go-ldap/ldap/v3 v3.4.12/go.mod h1:+SPAGcTtOfmGsCb3h1RFiq4xpp4N636G75OEace8lNo=
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3 h1:sfz1YppV05y4sYaW7kXZtrocU/+vimnIWt4cxAYh7+o=
github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3/go.mod h1:ZXFhGda43Z2TVbfGZefXyMJzsDHhCh0go3bZUcwTx7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@@ -443,8 +447,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
@@ -473,11 +477,11 @@ github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM=
github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
@@ -610,8 +614,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vb
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
@@ -689,6 +693,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfC
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE=
github.com/joshdk/go-junit v1.0.0/go.mod h1:TiiV0PqkaNfFXjEiyjWM3XXrhVyCa1K4Zfga6W52ung=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -723,8 +729,10 @@ github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXH
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kovidgoyal/imaging v1.6.4 h1:K0idhRPXnRrJBKnBYcTfI1HTWSNDeAn7hYDvf9I0dCk=
github.com/kovidgoyal/imaging v1.6.4/go.mod h1:bEIgsaZmXlvFfkv/CUxr9rJook6AQkJnpB5EPosRfRY=
github.com/kovidgoyal/go-parallel v1.0.1 h1:nYUjN+EdpbmQjTg3N5eTUInuXTB3/1oD2vHdaMfuHoI=
github.com/kovidgoyal/go-parallel v1.0.1/go.mod h1:BJNIbe6+hxyFWv7n6oEDPj3PA5qSw5OCtf0hcVxWJiw=
github.com/kovidgoyal/imaging v1.7.2 h1:mmT6k6Az3mC6dbqdZ6Q9KQCdZFWTAQ+q97NyGZgJ/2c=
github.com/kovidgoyal/imaging v1.7.2/go.mod h1:GdkCORjfZMMGFY0Pb7TDmRhj7PDhxF/QShKukSCj0VU=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -747,12 +755,16 @@ github.com/leonelquinteros/gotext v1.7.2 h1:bDPndU8nt+/kRo1m4l/1OXiiy2v7Z7dfPQ9+
github.com/leonelquinteros/gotext v1.7.2/go.mod h1:9/haCkm5P7Jay1sxKDGJ5WIg4zkz8oZKw4ekNpALob8=
github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38=
github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo=
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY=
github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc/v3 v3.0.0 h1:nZUx/zFg5uc2rhlu1L1DidGr5Sj02JbXvGSpnY4LMrc=
github.com/lestrrat-go/httprc/v3 v3.0.0/go.mod h1:k2U1QIiyVqAKtkffbg+cUmsyiPGQsb9aAfNQiNFuQ9Q=
github.com/lestrrat-go/jwx/v3 v3.0.10 h1:XuoCBhZBncRIjMQ32HdEc76rH0xK/Qv2wq5TBouYJDw=
github.com/lestrrat-go/jwx/v3 v3.0.10/go.mod h1:kNMedLgTpHvPJkK5EMVa1JFz+UVyY2dMmZKu3qjl/Pk=
github.com/lestrrat-go/httprc/v3 v3.0.1 h1:3n7Es68YYGZb2Jf+k//llA4FTZMl3yCwIjFIk4ubevI=
github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk=
github.com/lestrrat-go/jwx/v3 v3.0.11 h1:yEeUGNUuNjcez/Voxvr7XPTYNraSQTENJgtVTfwvG/w=
github.com/lestrrat-go/jwx/v3 v3.0.11/go.mod h1:XSOAh2SiXm0QgRe3DulLZLyt+wUuEdFo81zuKTLcvgQ=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
@@ -778,6 +790,8 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo=
github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg=
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
@@ -815,6 +829,8 @@ github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b h1:Q53idHrTuQD
github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b/go.mod h1:KirJrATYGbTyUwVR26xIkaipRqRcMRXBf8N5dacvGus=
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 h1:Z/i1e+gTZrmcGeZyWckaLfucYG6KYOXLWo4co8pZYNY=
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103/go.mod h1:o9YPB5aGP8ob35Vy6+vyq3P3bWe7NQWzf+JLiXCiMaE=
github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE=
github.com/mfridman/tparse v0.18.0/go.mod h1:gEvqZTuCgEhPbYk/2lS3Kcxg1GmTxxU7kTC8DvP0i/A=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
@@ -881,12 +897,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
github.com/nats-io/jwt/v2 v2.7.4 h1:jXFuDDxs/GQjGDZGhNgH4tXzSUK6WQi2rsj4xmsNOtI=
github.com/nats-io/jwt/v2 v2.7.4/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
github.com/nats-io/nats-server/v2 v2.11.9 h1:k7nzHZjUf51W1b08xiQih63Rdxh0yr5O4K892Mx5gQA=
github.com/nats-io/nats-server/v2 v2.11.9/go.mod h1:1MQgsAQX1tVjpf3Yzrk3x2pzdsZiNL/TVP3Amhp3CR8=
github.com/nats-io/nats.go v1.46.0 h1:iUcX+MLT0HHXskGkz+Sg20sXrPtJLsOojMDTDzOHSb8=
github.com/nats-io/nats.go v1.46.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g=
github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA=
github.com/nats-io/nats-server/v2 v2.12.0 h1:OIwe8jZUqJFrh+hhiyKu8snNib66qsx806OslqJuo74=
github.com/nats-io/nats-server/v2 v2.12.0/go.mod h1:nr8dhzqkP5E/lDwmn+A2CvQPMd1yDKXQI7iGg3lAvww=
github.com/nats-io/nats.go v1.47.0 h1:YQdADw6J/UfGUd2Oy6tn4Hq6YHxCaJrVKayxxFqYrgM=
github.com/nats-io/nats.go v1.47.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g=
github.com/nats-io/nkeys v0.4.11 h1:q44qGV008kYd9W1b1nEBkNzvnWxtRSQ7A8BoqRrcfa0=
github.com/nats-io/nkeys v0.4.11/go.mod h1:szDimtgmfOi9n25JpfIdGw12tZFYXqhGxjhVxsatHVE=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@@ -910,28 +926,30 @@ github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXI
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/olekukonko/tablewriter v1.0.9 h1:XGwRsYLC2bY7bNd93Dk51bcPZksWZmLYuaTHR0FqfL8=
github.com/olekukonko/tablewriter v1.0.9/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.25.3 h1:Ty8+Yi/ayDAGtk4XxmmfUy4GabvM+MegeB4cDLRi6nw=
github.com/onsi/ginkgo/v2 v2.25.3/go.mod h1:43uiyQC4Ed2tkOzLsEYm7hnrb7UJTWHYNsuy3bG/snE=
github.com/onsi/ginkgo/v2 v2.27.1 h1:0LJC8MpUSQnfnp4n/3W3GdlmJP3ENGF0ZPzjQGLPP7s=
github.com/onsi/ginkgo/v2 v2.27.1/go.mod h1:wmy3vCqiBjirARfVhAqFpYt8uvX0yaFe+GudAqqcCqA=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k=
github.com/open-policy-agent/opa v1.8.0 h1:4JdYuZcANeUF1v/87NGpirocpaZzJA0PcuL7xfmsMNM=
github.com/open-policy-agent/opa v1.8.0/go.mod h1:vOVZuIJQISnaYcZtQ58yTDkVCp1FmGPwK43pO9qPDqM=
github.com/open-policy-agent/opa v1.9.0 h1:QWFNwbcc29IRy0xwD3hRrMc/RtSersLY1Z6TaID3vgI=
github.com/open-policy-agent/opa v1.9.0/go.mod h1:72+lKmTda0O48m1VKAxxYl7MjP/EWFZu9fxHQK2xihs=
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a h1:Sakl76blJAaM6NxylVkgSzktjo2dS504iDotEFJsh3M=
github.com/opencloud-eu/go-micro-plugins/v4/store/nats-js-kv v0.0.0-20250512152754-23325793059a/go.mod h1:pjcozWijkNPbEtX5SIQaxEW/h8VAVZYTLx+70bmB3LY=
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+lP5lUUIzjRGDg93WrQfZJZCaV1ZP3KeyXi8bzY=
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI=
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.38.1-0.20250924125540-eaa2437c36b2 h1:e3B6KbWMjloKpqoTwTwvBLoCETRyyCDkQsqwRQMUdxc=
github.com/opencloud-eu/reva/v2 v2.38.1-0.20250924125540-eaa2437c36b2/go.mod h1:8mGCM9tLIPsC5aEKS022Z5u89u6jKuOl0znK0gNFReM=
github.com/opencloud-eu/reva/v2 v2.39.2-0.20251030154544-cac8a0257da6 h1:BUrCUrRqBg04MJuhnIK4H1KNK4aebK6H/AYcHjQ0DM4=
github.com/opencloud-eu/reva/v2 v2.39.2-0.20251030154544-cac8a0257da6/go.mod h1:Qm0CibFYrFc096OhWWL14nsGiFoE6g/4oMFHV5CqU+Q=
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=
@@ -1031,8 +1049,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI=
github.com/prometheus/statsd_exporter v0.22.8 h1:Qo2D9ZzaQG+id9i5NYNGmbf1aa/KxKbB9aKfMS+Yib0=
github.com/prometheus/statsd_exporter v0.22.8/go.mod h1:/DzwbTEaFTE0Ojz5PqcSk6+PFHOPWGxdXVr6yC8eFOM=
@@ -1041,8 +1059,8 @@ github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0=
github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I=
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ=
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg=
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/riandyrn/otelchi v0.12.2 h1:6QhGv0LVw/dwjtPd12mnNrl0oEQF4ZAlmHcnlTYbeAg=
github.com/riandyrn/otelchi v0.12.2/go.mod h1:weZZeUJURvtCcbWsdb7Y6F8KFZGedJlSrgUjq9VirV8=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -1063,6 +1081,8 @@ github.com/russellhaering/goxmldsig v1.5.0/go.mod h1:x98CjQNFJcWfMxeOrMnMKg70lvD
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
@@ -1081,8 +1101,8 @@ github.com/sethvargo/go-diceware v0.5.0 h1:exrQ7GpaBo00GqRVM1N8ChXSsi3oS7tjQiIeh
github.com/sethvargo/go-diceware v0.5.0/go.mod h1:Lg1SyPS7yQO6BBgTN5r4f2MUDkqGfLWsOjHPY0kA8iw=
github.com/sethvargo/go-password v0.3.1 h1:WqrLTjo7X6AcVYfC6R7GtSyuUQR9hGyAj/f1PYQZCJU=
github.com/sethvargo/go-password v0.3.1/go.mod h1:rXofC1zT54N7R8K/h1WDUdkf9BOx5OptoxrMBcrXzvs=
github.com/shamaton/msgpack/v2 v2.3.1 h1:R3QNLIGA/tbdczNMZ5PCRxrXvy+fnzsIaHG4kKMgWYo=
github.com/shamaton/msgpack/v2 v2.3.1/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8Oi/4=
github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
@@ -1096,8 +1116,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0=
github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
@@ -1124,8 +1144,9 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -1240,12 +1261,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.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo=
go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0=
go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI=
go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A=
go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo=
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.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=
@@ -1272,8 +1293,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZF
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
@@ -1326,8 +1347,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1343,8 +1364,8 @@ golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScy
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/image v0.31.0 h1:mLChjE2MV6g1S7oqbXC0/UcKijjm5fnJLUYKIYrLESA=
golang.org/x/image v0.31.0/go.mod h1:R9ec5Lcp96v9FTF+ajwaH3uGxPH4fKfHHAVbUILxghA=
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1369,8 +1390,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1424,8 +1445,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1433,8 +1454,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1537,8 +1558,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -1550,8 +1571,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1566,8 +1587,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1630,14 +1651,14 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
@@ -1695,10 +1716,10 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4 h1:8XJ4pajGwOlasW+L13MnEGA8W4115jJySQtVfS2/IBU=
google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.mod h1:NnuHhy+bxcg30o7FnVAZbXsPHUDQ9qKWAQKCD7VxFtk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4 h1:i8QOKZfYg6AbGVZzUAY3LrNWCKF8O6zFisU9Wl9RER4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -1714,8 +1735,8 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e h1:m7aQHHqd0q89mRwhwS9Bx2rjyl/hsFAeta+uGrHsQaU=
google.golang.org/grpc/examples v0.0.0-20211102180624-670c133e568e/go.mod h1:gID3PKrg7pWKntu9Ss6zTLJ0ttC0X9IHgREOCZwbCVU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -1732,8 +1753,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=

View File

@@ -28,7 +28,7 @@ dev-docker-multiarch:
docker buildx rm opencloudbuilder || true
docker buildx create --platform linux/arm64,linux/amd64 --name opencloudbuilder
docker buildx use opencloudbuilder
docker buildx build --platform linux/arm64,linux/amd64 --output type=docker --file docker/Dockerfile.multiarch --tag opencloudeu/opencloud:dev-multiarch ../..
cd .. && docker buildx build --platform linux/arm64,linux/amd64 --output type=docker --file opencloud/docker/Dockerfile.multiarch --tag opencloudeu/opencloud:dev-multiarch .
docker buildx rm opencloudbuilder
.PHONY: debug-docker

View File

@@ -7,11 +7,11 @@ ARG STRING
RUN apk add bash make git curl gcc musl-dev libc-dev binutils-gold inotify-tools vips-dev
WORKDIR /opencloud
RUN --mount=type=bind,target=/opencloud,rw\
RUN --mount=type=bind,target=/opencloud \
--mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache \
GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH:-amd64}" ; \
cd opencloud && make -C opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
make -C opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
FROM alpine:3.21
ARG VERSION

View File

@@ -521,6 +521,24 @@ func trapShutdownCtx(s *Service, srv *http.Server, ctx context.Context) error {
s.Log.Debug().Msg("runtime listener shutdown done")
}()
// shutdown services in the order defined in the config
// any services not listed will be shutdown in parallel afterwards
for _, sName := range s.cfg.Runtime.ShutdownOrder {
if _, ok := s.serviceToken[sName]; !ok {
s.Log.Warn().Str("service", sName).Msg("unknown service for ordered shutdown, skipping")
continue
}
for i := range s.serviceToken[sName] {
if err := s.Supervisor.RemoveAndWait(s.serviceToken[sName][i], _defaultShutdownTimeoutDuration); err != nil && !errors.Is(err, suture.ErrSupervisorNotRunning) {
s.Log.Error().Err(err).Str("service", sName).Msg("could not shutdown service in order, skipping to next")
// continue shutting down other services
continue
}
s.Log.Debug().Str("service", sName).Msg("graceful ordered shutdown for service done")
}
delete(s.serviceToken, sName)
}
for sName := range s.serviceToken {
for i := range s.serviceToken[sName] {
wg.Add(1)

View File

@@ -50,11 +50,12 @@ type Mode int
// Runtime configures the OpenCloud runtime when running in supervised mode.
type Runtime struct {
Port string `yaml:"port" env:"OC_RUNTIME_PORT" desc:"The TCP port at which OpenCloud will be available" introductionVersion:"1.0.0"`
Host string `yaml:"host" env:"OC_RUNTIME_HOST" desc:"The host at which OpenCloud will be available" introductionVersion:"1.0.0"`
Services []string `yaml:"services" env:"OC_RUN_EXTENSIONS;OC_RUN_SERVICES" desc:"A comma-separated list of service names. Will start only the listed services." introductionVersion:"1.0.0"`
Disabled []string `yaml:"disabled_services" env:"OC_EXCLUDE_RUN_SERVICES" desc:"A comma-separated list of service names. Will start all default services except of the ones listed. Has no effect when OC_RUN_SERVICES is set." introductionVersion:"1.0.0"`
Additional []string `yaml:"add_services" env:"OC_ADD_RUN_SERVICES" desc:"A comma-separated list of service names. Will add the listed services to the default configuration. Has no effect when OC_RUN_SERVICES is set. Note that one can add services not started by the default list and exclude services from the default list by using both envvars at the same time." introductionVersion:"1.0.0"`
Port string `yaml:"port" env:"OC_RUNTIME_PORT" desc:"The TCP port at which OpenCloud will be available" introductionVersion:"1.0.0"`
Host string `yaml:"host" env:"OC_RUNTIME_HOST" desc:"The host at which OpenCloud will be available" introductionVersion:"1.0.0"`
Services []string `yaml:"services" env:"OC_RUN_EXTENSIONS;OC_RUN_SERVICES" desc:"A comma-separated list of service names. Will start only the listed services." introductionVersion:"1.0.0"`
Disabled []string `yaml:"disabled_services" env:"OC_EXCLUDE_RUN_SERVICES" desc:"A comma-separated list of service names. Will start all default services except of the ones listed. Has no effect when OC_RUN_SERVICES is set." introductionVersion:"1.0.0"`
Additional []string `yaml:"add_services" env:"OC_ADD_RUN_SERVICES" desc:"A comma-separated list of service names. Will add the listed services to the default configuration. Has no effect when OC_RUN_SERVICES is set. Note that one can add services not started by the default list and exclude services from the default list by using both envvars at the same time." introductionVersion:"1.0.0"`
ShutdownOrder []string `yaml:"shutdown_order" env:"OC_SHUTDOWN_ORDER" desc:"A comma-separated list of service names defining the order in which services are shut down. Services not listed will be stopped after the listed ones in random order." introductionVersion:"%%NEXT%%"`
}
// Config combines all available configuration parts.

View File

@@ -50,8 +50,9 @@ func DefaultConfig() *Config {
return &Config{
OpenCloudURL: "https://localhost:9200",
Runtime: Runtime{
Port: "9250",
Host: "localhost",
Port: "9250",
Host: "localhost",
ShutdownOrder: []string{"proxy"},
},
Reva: &shared.Reva{
Address: "eu.opencloud.api.gateway",

View File

@@ -69,20 +69,21 @@ type Cache struct {
// Commons holds configuration that are common to all extensions. Each extension can then decide whether
// to overwrite its values.
type Commons struct {
Log *Log `yaml:"log"`
Tracing *Tracing `yaml:"tracing"`
Cache *Cache `yaml:"cache"`
GRPCClientTLS *GRPCClientTLS `yaml:"grpc_client_tls"`
GRPCServiceTLS *GRPCServiceTLS `yaml:"grpc_service_tls"`
HTTPServiceTLS HTTPServiceTLS `yaml:"http_service_tls"`
OpenCloudURL string `yaml:"opencloud_url" env:"OC_URL" desc:"URL, where OpenCloud is reachable for users." introductionVersion:"1.0.0"`
TokenManager *TokenManager `mask:"struct" yaml:"token_manager"`
Reva *Reva `yaml:"reva"`
MachineAuthAPIKey string `mask:"password" yaml:"machine_auth_api_key" env:"OC_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary for the access to resources from other services." introductionVersion:"1.0.0"`
TransferSecret string `mask:"password" yaml:"transfer_secret,omitempty" env:"REVA_TRANSFER_SECRET" desc:"The secret used for signing the requests towards the data gateway for up- and downloads." introductionVersion:"1.0.0"`
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID" desc:"ID of the OpenCloud storage-system system user. Admins need to set the ID for the storage-system system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
SystemUserAPIKey string `mask:"password" yaml:"system_user_api_key" env:"SYSTEM_USER_API_KEY" desc:"API key for all system users." introductionVersion:"1.0.0"`
AdminUserID string `yaml:"admin_user_id" env:"OC_ADMIN_USER_ID" desc:"ID of a user, that should receive admin privileges. Consider that the UUID can be encoded in some LDAP deployment configurations like in .ldif files. These need to be decoded beforehand." introductionVersion:"1.0.0"`
Log *Log `yaml:"log"`
Tracing *Tracing `yaml:"tracing"`
Cache *Cache `yaml:"cache"`
GRPCClientTLS *GRPCClientTLS `yaml:"grpc_client_tls"`
GRPCServiceTLS *GRPCServiceTLS `yaml:"grpc_service_tls"`
HTTPServiceTLS HTTPServiceTLS `yaml:"http_service_tls"`
OpenCloudURL string `yaml:"opencloud_url" env:"OC_URL" desc:"URL, where OpenCloud is reachable for users." introductionVersion:"1.0.0"`
TokenManager *TokenManager `mask:"struct" yaml:"token_manager"`
Reva *Reva `yaml:"reva"`
MachineAuthAPIKey string `mask:"password" yaml:"machine_auth_api_key" env:"OC_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary for the access to resources from other services." introductionVersion:"1.0.0"`
TransferSecret string `mask:"password" yaml:"transfer_secret,omitempty" env:"REVA_TRANSFER_SECRET" desc:"The secret used for signing the requests towards the data gateway for up- and downloads." introductionVersion:"1.0.0"`
SystemUserID string `yaml:"system_user_id" env:"OC_SYSTEM_USER_ID" desc:"ID of the OpenCloud storage-system system user. Admins need to set the ID for the storage-system system user in this config option which is then used to reference the user. Any reasonable long string is possible, preferably this would be an UUIDv4 format." introductionVersion:"1.0.0"`
SystemUserAPIKey string `mask:"password" yaml:"system_user_api_key" env:"SYSTEM_USER_API_KEY" desc:"API key for all system users." introductionVersion:"1.0.0"`
AdminUserID string `yaml:"admin_user_id" env:"OC_ADMIN_USER_ID" desc:"ID of a user, that should receive admin privileges. Consider that the UUID can be encoded in some LDAP deployment configurations like in .ldif files. These need to be decoded beforehand." introductionVersion:"1.0.0"`
MultiTenantEnabled bool `yaml:"multi_tenant_enabled" env:"OC_MULTI_TENANT_ENABLED" desc:"Set this to true to enable multi-tenant support." introductionVersion:"%%NEXT%%"`
// NOTE: you will not fing GRPCMaxReceivedMessageSize size being used in the code. The envvar is actually extracted in revas `pool` package: https://github.com/cs3org/reva/blob/edge/pkg/rgrpc/todo/pool/connection.go
// It is mentioned here again so it is documented

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 = "3.5.0+dev"
LatestTag = "3.7.0+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

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-11 00:02+0000\n"
"POT-Creation-Date: 2025-10-23 00:01+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-11 00:02+0000\n"
"POT-Creation-Date: 2025-10-23 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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

@@ -11,7 +11,7 @@ import (
"github.com/opencloud-eu/reva/v2/pkg/mime"
ic "github.com/egirna/icap-client"
ic "github.com/opencloud-eu/icap-client"
)
// Scanner is the interface that wraps the basic Do method

View File

@@ -9,7 +9,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
ic "github.com/egirna/icap-client"
ic "github.com/opencloud-eu/icap-client"
"github.com/opencloud-eu/opencloud/services/antivirus/pkg/scanners"
"github.com/opencloud-eu/opencloud/services/antivirus/pkg/scanners/mocks"
)

View File

@@ -5,8 +5,8 @@
package mocks
import (
"github.com/egirna/icap-client"
mock "github.com/stretchr/testify/mock"
"github.com/opencloud-eu/icap-client"
"github.com/stretchr/testify/mock"
)
// NewScanner creates a new instance of Scanner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.

View File

@@ -9,9 +9,10 @@ import (
func AppProviderConfigFromStruct(cfg *config.Config) map[string]interface{} {
rcfg := map[string]interface{}{
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -17,9 +17,10 @@ func AppRegistryConfigFromStruct(cfg *config.Config, logger log.Logger) map[stri
"tracing_service_name": cfg.Service.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -25,6 +25,7 @@ func AuthAppConfigFromStruct(cfg *config.Config) map[string]interface{} {
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -12,6 +12,7 @@ func AuthBasicConfigFromStruct(cfg *config.Config) map[string]interface{} {
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -13,6 +13,7 @@ func AuthBearerConfigFromStruct(cfg *config.Config) map[string]interface{} {
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -12,6 +12,7 @@ func AuthMachineConfigFromStruct(cfg *config.Config) map[string]interface{} {
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -15,9 +15,10 @@ func AuthMachineConfigFromStruct(cfg *config.Config) map[string]interface{} {
"tracing_service_name": cfg.Service.Name,
},
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -25,14 +25,14 @@ func Version(cfg *config.Config) *cli.Command {
fmt.Println("")
reg := registry.GetRegistry()
services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name + "." + cfg.App.Name)
services, err := reg.GetService(cfg.HTTP.Namespace + "." + cfg.Service.Name)
if err != nil {
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name+"."+cfg.App.Name, err))
fmt.Println(fmt.Errorf("could not get %s services from the registry: %v", cfg.Service.Name, err))
return err
}
if len(services) == 0 {
fmt.Println("No running " + cfg.Service.Name + "." + cfg.App.Name + " service found.")
fmt.Println("No running " + cfg.Service.Name + " service found.")
return nil
}

View File

@@ -2,5 +2,5 @@ package config
// Service defines the available service configuration.
type Service struct {
Name string `yaml:"-"`
Name string `yaml:"name" env:"COLLABORATION_SERVICE_NAME" desc:"The name of the service which is registered. You only need to change this when more than one collaboration service is needed." introductionVersion:"3.6.0"`
}

View File

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

View File

@@ -22,7 +22,7 @@ func Server(opts ...Option) (*http.Server, error) {
return debug.NewService(
debug.Logger(options.Logger),
debug.Name(options.Config.Service.Name+"."+options.Config.App.Name),
debug.Name(options.Config.Service.Name),
debug.Version(version.GetString()),
debug.Address(options.Config.Debug.Addr),
debug.Token(options.Config.Debug.Token),

View File

@@ -25,7 +25,7 @@ func Server(opts ...Option) (http.Service, error) {
http.TLSConfig(options.Config.HTTP.TLS),
http.Logger(options.Logger),
http.Namespace(options.Config.HTTP.Namespace),
http.Name(options.Config.Service.Name+"."+options.Config.App.Name),
http.Name(options.Config.Service.Name),
http.Version(version.GetString()),
http.Address(options.Config.HTTP.Addr),
http.Context(options.Context),
@@ -41,7 +41,7 @@ func Server(opts ...Option) (http.Service, error) {
middlewares := []func(stdhttp.Handler) stdhttp.Handler{
chimiddleware.RequestID,
middleware.Version(
options.Config.Service.Name+"."+options.Config.App.Name,
options.Config.Service.Name,
version.GetString(),
),
colabmiddleware.AccessLog(
@@ -69,7 +69,7 @@ func Server(opts ...Option) (http.Service, error) {
mux.Use(
otelchi.Middleware(
options.Config.Service.Name+"."+options.Config.App.Name,
options.Config.Service.Name,
otelchi.WithChiRoutes(mux),
otelchi.WithTracerProvider(options.TracerProvider),
otelchi.WithPropagators(tracing.GetPropagator()),

View File

@@ -47,7 +47,7 @@ func NewHandler(opts ...Option) (*Service, func(), error) {
}
return &Service{
id: options.Config.GRPC.Namespace + "." + options.Config.Service.Name + "." + options.Config.App.Name,
id: options.Config.GRPC.Namespace + "." + options.Config.Service.Name,
appURLs: options.AppURLs,
logger: options.Logger,
config: options.Config,

View File

@@ -62,6 +62,8 @@ type Config struct {
ConfigurableNotifications bool `yaml:"configurable_notifications" env:"FRONTEND_CONFIGURABLE_NOTIFICATIONS" desc:"Allow configuring notifications via web client." introductionVersion:"1.0.0"`
Groupware Groupware `yaml:"groupware"`
Context context.Context `yaml:"-"`
}
@@ -195,3 +197,7 @@ type PasswordPolicy struct {
MinSpecialCharacters int `yaml:"min_special_characters" env:"OC_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS;FRONTEND_PASSWORD_POLICY_MIN_SPECIAL_CHARACTERS" desc:"Define the minimum number of characters from the special characters list to be present. Defaults to 1 if not set." introductionVersion:"1.0.0"`
BannedPasswordsList string `yaml:"banned_passwords_list" env:"OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST;FRONTEND_PASSWORD_POLICY_BANNED_PASSWORDS_LIST" desc:"Path to the 'banned passwords list' file. This only impacts public link password validation. See the documentation for more details." introductionVersion:"1.0.0"`
}
type Groupware struct {
Enabled bool `yaml:"enabled" env:"FRONTEND_GROUPWARE_ENABLED" desc:"Enable groupware features. Defaults to false." introductionVersion:"3.7.0"`
}

View File

@@ -139,6 +139,9 @@ func DefaultConfig() *config.Config {
MinDigits: 1,
MinSpecialCharacters: 1,
},
Groupware: config.Groupware{
Enabled: false,
},
}
}

View File

@@ -93,6 +93,7 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string
"gatewaysvc": cfg.Reva.Address, // Todo or address?
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"http": map[string]interface{}{
"network": cfg.HTTP.Protocol,
@@ -338,6 +339,9 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string
"endpoints": []string{"list", "get", "delete"},
"configurable": cfg.ConfigurableNotifications,
},
"groupware": map[string]interface{}{
"enabled": cfg.Groupware.Enabled,
},
},
"version": map[string]interface{}{
"product": "OpenCloud",

View File

@@ -28,6 +28,7 @@ func GatewayConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]i
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -45,3 +45,9 @@ packages:
Client:
config:
filename: ldapclient.go
github.com/nats-io/nats.go/jetstream:
config:
dir: mocks
interfaces:
KeyValue: {}
KeyValueEntry: {}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,349 @@
// Code generated by mockery; DO NOT EDIT.
// github.com/vektra/mockery
// template: testify
package mocks
import (
"time"
"github.com/nats-io/nats.go/jetstream"
mock "github.com/stretchr/testify/mock"
)
// NewKeyValueEntry creates a new instance of KeyValueEntry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewKeyValueEntry(t interface {
mock.TestingT
Cleanup(func())
}) *KeyValueEntry {
mock := &KeyValueEntry{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// KeyValueEntry is an autogenerated mock type for the KeyValueEntry type
type KeyValueEntry struct {
mock.Mock
}
type KeyValueEntry_Expecter struct {
mock *mock.Mock
}
func (_m *KeyValueEntry) EXPECT() *KeyValueEntry_Expecter {
return &KeyValueEntry_Expecter{mock: &_m.Mock}
}
// Bucket provides a mock function for the type KeyValueEntry
func (_mock *KeyValueEntry) Bucket() string {
ret := _mock.Called()
if len(ret) == 0 {
panic("no return value specified for Bucket")
}
var r0 string
if returnFunc, ok := ret.Get(0).(func() string); ok {
r0 = returnFunc()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// KeyValueEntry_Bucket_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bucket'
type KeyValueEntry_Bucket_Call struct {
*mock.Call
}
// Bucket is a helper method to define mock.On call
func (_e *KeyValueEntry_Expecter) Bucket() *KeyValueEntry_Bucket_Call {
return &KeyValueEntry_Bucket_Call{Call: _e.mock.On("Bucket")}
}
func (_c *KeyValueEntry_Bucket_Call) Run(run func()) *KeyValueEntry_Bucket_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *KeyValueEntry_Bucket_Call) Return(s string) *KeyValueEntry_Bucket_Call {
_c.Call.Return(s)
return _c
}
func (_c *KeyValueEntry_Bucket_Call) RunAndReturn(run func() string) *KeyValueEntry_Bucket_Call {
_c.Call.Return(run)
return _c
}
// Created provides a mock function for the type KeyValueEntry
func (_mock *KeyValueEntry) Created() time.Time {
ret := _mock.Called()
if len(ret) == 0 {
panic("no return value specified for Created")
}
var r0 time.Time
if returnFunc, ok := ret.Get(0).(func() time.Time); ok {
r0 = returnFunc()
} else {
r0 = ret.Get(0).(time.Time)
}
return r0
}
// KeyValueEntry_Created_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Created'
type KeyValueEntry_Created_Call struct {
*mock.Call
}
// Created is a helper method to define mock.On call
func (_e *KeyValueEntry_Expecter) Created() *KeyValueEntry_Created_Call {
return &KeyValueEntry_Created_Call{Call: _e.mock.On("Created")}
}
func (_c *KeyValueEntry_Created_Call) Run(run func()) *KeyValueEntry_Created_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *KeyValueEntry_Created_Call) Return(time1 time.Time) *KeyValueEntry_Created_Call {
_c.Call.Return(time1)
return _c
}
func (_c *KeyValueEntry_Created_Call) RunAndReturn(run func() time.Time) *KeyValueEntry_Created_Call {
_c.Call.Return(run)
return _c
}
// Delta provides a mock function for the type KeyValueEntry
func (_mock *KeyValueEntry) Delta() uint64 {
ret := _mock.Called()
if len(ret) == 0 {
panic("no return value specified for Delta")
}
var r0 uint64
if returnFunc, ok := ret.Get(0).(func() uint64); ok {
r0 = returnFunc()
} else {
r0 = ret.Get(0).(uint64)
}
return r0
}
// KeyValueEntry_Delta_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delta'
type KeyValueEntry_Delta_Call struct {
*mock.Call
}
// Delta is a helper method to define mock.On call
func (_e *KeyValueEntry_Expecter) Delta() *KeyValueEntry_Delta_Call {
return &KeyValueEntry_Delta_Call{Call: _e.mock.On("Delta")}
}
func (_c *KeyValueEntry_Delta_Call) Run(run func()) *KeyValueEntry_Delta_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *KeyValueEntry_Delta_Call) Return(v uint64) *KeyValueEntry_Delta_Call {
_c.Call.Return(v)
return _c
}
func (_c *KeyValueEntry_Delta_Call) RunAndReturn(run func() uint64) *KeyValueEntry_Delta_Call {
_c.Call.Return(run)
return _c
}
// Key provides a mock function for the type KeyValueEntry
func (_mock *KeyValueEntry) Key() string {
ret := _mock.Called()
if len(ret) == 0 {
panic("no return value specified for Key")
}
var r0 string
if returnFunc, ok := ret.Get(0).(func() string); ok {
r0 = returnFunc()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// KeyValueEntry_Key_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Key'
type KeyValueEntry_Key_Call struct {
*mock.Call
}
// Key is a helper method to define mock.On call
func (_e *KeyValueEntry_Expecter) Key() *KeyValueEntry_Key_Call {
return &KeyValueEntry_Key_Call{Call: _e.mock.On("Key")}
}
func (_c *KeyValueEntry_Key_Call) Run(run func()) *KeyValueEntry_Key_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *KeyValueEntry_Key_Call) Return(s string) *KeyValueEntry_Key_Call {
_c.Call.Return(s)
return _c
}
func (_c *KeyValueEntry_Key_Call) RunAndReturn(run func() string) *KeyValueEntry_Key_Call {
_c.Call.Return(run)
return _c
}
// Operation provides a mock function for the type KeyValueEntry
func (_mock *KeyValueEntry) Operation() jetstream.KeyValueOp {
ret := _mock.Called()
if len(ret) == 0 {
panic("no return value specified for Operation")
}
var r0 jetstream.KeyValueOp
if returnFunc, ok := ret.Get(0).(func() jetstream.KeyValueOp); ok {
r0 = returnFunc()
} else {
r0 = ret.Get(0).(jetstream.KeyValueOp)
}
return r0
}
// KeyValueEntry_Operation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Operation'
type KeyValueEntry_Operation_Call struct {
*mock.Call
}
// Operation is a helper method to define mock.On call
func (_e *KeyValueEntry_Expecter) Operation() *KeyValueEntry_Operation_Call {
return &KeyValueEntry_Operation_Call{Call: _e.mock.On("Operation")}
}
func (_c *KeyValueEntry_Operation_Call) Run(run func()) *KeyValueEntry_Operation_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *KeyValueEntry_Operation_Call) Return(keyValueOp jetstream.KeyValueOp) *KeyValueEntry_Operation_Call {
_c.Call.Return(keyValueOp)
return _c
}
func (_c *KeyValueEntry_Operation_Call) RunAndReturn(run func() jetstream.KeyValueOp) *KeyValueEntry_Operation_Call {
_c.Call.Return(run)
return _c
}
// Revision provides a mock function for the type KeyValueEntry
func (_mock *KeyValueEntry) Revision() uint64 {
ret := _mock.Called()
if len(ret) == 0 {
panic("no return value specified for Revision")
}
var r0 uint64
if returnFunc, ok := ret.Get(0).(func() uint64); ok {
r0 = returnFunc()
} else {
r0 = ret.Get(0).(uint64)
}
return r0
}
// KeyValueEntry_Revision_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Revision'
type KeyValueEntry_Revision_Call struct {
*mock.Call
}
// Revision is a helper method to define mock.On call
func (_e *KeyValueEntry_Expecter) Revision() *KeyValueEntry_Revision_Call {
return &KeyValueEntry_Revision_Call{Call: _e.mock.On("Revision")}
}
func (_c *KeyValueEntry_Revision_Call) Run(run func()) *KeyValueEntry_Revision_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *KeyValueEntry_Revision_Call) Return(v uint64) *KeyValueEntry_Revision_Call {
_c.Call.Return(v)
return _c
}
func (_c *KeyValueEntry_Revision_Call) RunAndReturn(run func() uint64) *KeyValueEntry_Revision_Call {
_c.Call.Return(run)
return _c
}
// Value provides a mock function for the type KeyValueEntry
func (_mock *KeyValueEntry) Value() []byte {
ret := _mock.Called()
if len(ret) == 0 {
panic("no return value specified for Value")
}
var r0 []byte
if returnFunc, ok := ret.Get(0).(func() []byte); ok {
r0 = returnFunc()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]byte)
}
}
return r0
}
// KeyValueEntry_Value_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Value'
type KeyValueEntry_Value_Call struct {
*mock.Call
}
// Value is a helper method to define mock.On call
func (_e *KeyValueEntry_Expecter) Value() *KeyValueEntry_Value_Call {
return &KeyValueEntry_Value_Call{Call: _e.mock.On("Value")}
}
func (_c *KeyValueEntry_Value_Call) Run(run func()) *KeyValueEntry_Value_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *KeyValueEntry_Value_Call) Return(bytes []byte) *KeyValueEntry_Value_Call {
_c.Call.Return(bytes)
return _c
}
func (_c *KeyValueEntry_Value_Call) RunAndReturn(run func() []byte) *KeyValueEntry_Value_Call {
_c.Call.Return(run)
return _c
}

View File

@@ -5,6 +5,11 @@ import (
"fmt"
"os/signal"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
"github.com/opencloud-eu/opencloud/pkg/runner"
"github.com/opencloud-eu/opencloud/pkg/tracing"
@@ -15,7 +20,6 @@ import (
"github.com/opencloud-eu/opencloud/services/graph/pkg/metrics"
"github.com/opencloud-eu/opencloud/services/graph/pkg/server/debug"
"github.com/opencloud-eu/opencloud/services/graph/pkg/server/http"
"github.com/urfave/cli/v2"
)
// Server is the entrypoint for the server command.
@@ -44,6 +48,39 @@ func Server(cfg *config.Config) *cli.Command {
mtrcs := metrics.New()
mtrcs.BuildInfo.WithLabelValues(version.GetString()).Set(1)
var kv jetstream.KeyValue
// Allow to run without a NATS store (e.g. for the standalone Education provisioning service)
if len(cfg.Store.Nodes) > 0 {
//Connect to NATS servers
natsOptions := nats.Options{
Servers: cfg.Store.Nodes,
User: cfg.Store.AuthUsername,
Password: cfg.Store.AuthPassword,
}
conn, err := natsOptions.Connect()
if err != nil {
return err
}
js, err := jetstream.New(conn)
if err != nil {
return err
}
kv, err = js.KeyValue(ctx, cfg.Store.Database)
if err != nil {
if !errors.Is(err, jetstream.ErrBucketNotFound) {
return fmt.Errorf("failed to get bucket (%s): %w", cfg.Store.Database, err)
}
kv, err = js.CreateKeyValue(ctx, jetstream.KeyValueConfig{
Bucket: cfg.Store.Database,
})
if err != nil {
return fmt.Errorf("failed to create bucket (%s): %w", cfg.Store.Database, err)
}
}
}
gr := runner.NewGroup()
{
server, err := http.Server(
@@ -52,6 +89,7 @@ func Server(cfg *config.Config) *cli.Command {
http.Config(cfg),
http.Metrics(mtrcs),
http.TraceProvider(traceProvider),
http.NatsKeyValue(kv),
)
if err != nil {
logger.Error().Err(err).Str("transport", "http").Msg("Failed to initialize server")

View File

@@ -42,6 +42,8 @@ type Config struct {
Metadata Metadata `yaml:"metadata_config"`
UserSoftDeleteRetentionTime time.Duration `yaml:"user_soft_delete_retention_time" env:"GRAPH_USER_SOFT_DELETE_RETENTION_TIME" desc:"The time after which a soft-deleted user is permanently deleted. If set to 0 (default), there is no soft delete retention time and users are deleted immediately after being soft-deleted. If set to a positive value, the user will be kept in the system for that duration before being permanently deleted." introductionVersion:"%%NEXT%%"`
Store Store `yaml:"store"`
}
type Spaces struct {
@@ -168,3 +170,11 @@ type Metadata struct {
SystemUserIDP string `yaml:"system_user_idp" env:"OC_SYSTEM_USER_IDP;GRAPH_SYSTEM_USER_IDP" desc:"IDP of the OpenCloud STORAGE-SYSTEM system user." introductionVersion:"%%NEXT%%"`
SystemUserAPIKey string `yaml:"system_user_api_key" env:"OC_SYSTEM_USER_API_KEY" desc:"API key for the STORAGE-SYSTEM system user." introductionVersion:"%%NEXT%%"`
}
// Store configures the store to use
type Store struct {
Nodes []string `yaml:"nodes" env:"OC_PERSISTENT_STORE_NODES;GRAPH_STORE_NODES" desc:"A list of nodes to access the configured store. This has no effect when 'memory' store is configured. Note that the behaviour how nodes are used is dependent on the library of the configured store. See the Environment Variable Types description for more details." introductionVersion:"1.0.0"`
Database string `yaml:"database" env:"GRAPH_STORE_DATABASE" desc:"The database name the configured store should use." introductionVersion:"1.0.0"`
AuthUsername string `yaml:"username" env:"OC_PERSISTENT_STORE_AUTH_USERNAME;GRAPH_STORE_AUTH_USERNAME" desc:"The username to authenticate with the store. Only applies when store type 'nats-js-kv' is configured." introductionVersion:"1.0.0"`
AuthPassword string `yaml:"password" env:"OC_PERSISTENT_STORE_AUTH_PASSWORD;GRAPH_STORE_AUTH_PASSWORD" desc:"The password to authenticate with the store. Only applies when store type 'nats-js-kv' is configured." introductionVersion:"1.0.0"`
}

View File

@@ -131,6 +131,10 @@ func DefaultConfig() *config.Config {
SystemUserIDP: "internal",
},
UserSoftDeleteRetentionTime: 0,
Store: config.Store{
Nodes: []string{"127.0.0.1:9233"},
Database: "graph",
},
}
}

View File

@@ -3,6 +3,7 @@ package parser
import (
"errors"
"fmt"
"slices"
"github.com/go-ldap/ldap/v3"
@@ -42,6 +43,14 @@ func Validate(cfg *config.Config) error {
return shared.MissingJWTTokenError(cfg.Service.Name)
}
if !slices.Contains([]string{"ldap", "cs3"}, cfg.Identity.Backend) {
return fmt.Errorf("'%s' is not a valid identity backend for the 'graph' service", cfg.Identity.Backend)
}
// ensure that the "cs3" identity backend is used in multi-tenant setups
if cfg.Commons.MultiTenantEnabled && cfg.Identity.Backend != "cs3" {
return fmt.Errorf("Multi-tenant support is enabled. The identity backend must be set to 'cs3' for the 'graph' service.")
}
if cfg.Identity.Backend == "ldap" {
if err := validateLDAPSettings(cfg); err != nil {
return err

View File

@@ -0,0 +1,69 @@
package parser_test
import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/opencloud-eu/opencloud/pkg/shared"
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/defaults"
"github.com/opencloud-eu/opencloud/services/graph/pkg/config/parser"
)
var _ = Describe("Validate", func() {
var cfg *config.Config
BeforeEach(func() {
cfg = defaults.DefaultConfig()
cfg.Application.ID = "graph-app-id"
cfg.ServiceAccount.ServiceAccountID = "graph-service-account"
cfg.ServiceAccount.ServiceAccountSecret = "graph-service-password"
cfg.Commons = &shared.Commons{
TokenManager: &shared.TokenManager{
JWTSecret: "jwt-secret",
},
}
defaults.EnsureDefaults(cfg)
})
When("multi-tenant support is disabled", func() {
It("should accept a setup with the 'cs3' identity backend", func() {
cfg.Identity.Backend = "cs3"
err := parser.Validate(cfg)
Expect(err).ToNot(HaveOccurred())
})
It("should accept a setup with the 'ldap' identity backend", func() {
cfg.Identity.Backend = "ldap"
// we need to set a password to pass validation
cfg.Identity.LDAP.BindPassword = "bind-password"
err := parser.Validate(cfg)
Expect(err).ToNot(HaveOccurred())
})
})
When("multi-tenant support is disabled", func() {
BeforeEach(func() {
cfg.Commons.MultiTenantEnabled = true
})
It("should accept a setup with the 'cs3' identity backend", func() {
cfg.Identity.Backend = "cs3"
err := parser.Validate(cfg)
Expect(err).ToNot(HaveOccurred())
})
It("should reject a setup with the 'ldap' identity backend", func() {
cfg.Identity.Backend = "ldap"
cfg.Identity.LDAP.BindPassword = "bind-password"
err := parser.Validate(cfg)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(ContainSubstring("The identity backend must be set to 'cs3' for the 'graph' service.")))
})
})
It("rejcts a setup with an invalid identity backend", func() {
cfg.Identity.Backend = "invalid-backend"
err := parser.Validate(cfg)
Expect(err).To(HaveOccurred())
Expect(err).To(MatchError(ContainSubstring("is not a valid identity backend")))
})
})

View File

@@ -0,0 +1,13 @@
package parser_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestParser(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Parser Suite")
}

View File

@@ -8,10 +8,10 @@ import (
"github.com/go-ldap/ldap/v3"
"github.com/gofrs/uuid"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
)
type educationConfig struct {
@@ -119,16 +119,18 @@ func (i *LDAP) CreateEducationSchool(ctx context.Context, school libregraph.Educ
}
// Check that the school number is not already used
_, err := i.getSchoolByNumber(school.GetSchoolNumber())
switch err {
case nil:
logger.Debug().Err(errSchoolNumberExists).Str("schoolNumber", school.GetSchoolNumber()).Msg("duplicate school number")
return nil, errSchoolNumberExists
case ErrNotFound:
break
default:
logger.Error().Err(err).Str("schoolNumber", school.GetSchoolNumber()).Msg("error looking up school by number")
return nil, errorcode.New(errorcode.GeneralException, "error looking up school by number")
if school.HasSchoolNumber() {
_, err := i.getSchoolByNumber(school.GetSchoolNumber())
switch err {
case nil:
logger.Debug().Err(errSchoolNumberExists).Str("schoolNumber", school.GetSchoolNumber()).Msg("duplicate school number")
return nil, errSchoolNumberExists
case ErrNotFound:
break
default:
logger.Error().Err(err).Str("schoolNumber", school.GetSchoolNumber()).Msg("error looking up school by number")
return nil, errorcode.New(errorcode.GeneralException, "error looking up school by number")
}
}
attributeTypeAndValue := ldap.AttributeTypeAndValue{
@@ -142,7 +144,9 @@ func (i *LDAP) CreateEducationSchool(ctx context.Context, school libregraph.Educ
)
ar := ldap.NewAddRequest(dn, nil)
ar.Attribute(i.educationConfig.schoolAttributeMap.displayName, []string{school.GetDisplayName()})
ar.Attribute(i.educationConfig.schoolAttributeMap.schoolNumber, []string{school.GetSchoolNumber()})
if school.HasSchoolNumber() {
ar.Attribute(i.educationConfig.schoolAttributeMap.schoolNumber, []string{school.GetSchoolNumber()})
}
if !i.useServerUUID {
ar.Attribute(i.educationConfig.schoolAttributeMap.id, []string{uuid.Must(uuid.NewV4()).String()})
}
@@ -723,18 +727,22 @@ func (i *LDAP) createSchoolModelFromLDAP(e *ldap.Entry) *libregraph.EducationSch
if err != nil && !errors.Is(err, errNotSet) {
i.logger.Error().Err(err).Str("dn", e.DN).Msg("Error reading termination date for LDAP entry")
}
if id != "" && displayName != "" && schoolNumber != "" {
school := libregraph.NewEducationSchool()
school.SetDisplayName(displayName)
school.SetSchoolNumber(schoolNumber)
school.SetId(id)
if t != nil {
school.SetTerminationDate(*t)
}
return school
if id == "" || displayName == "" {
i.logger.Warn().Str("dn", e.DN).Str("id", id).Str("displayName", displayName).Msg("Invalid School. Missing required attribute")
return nil
}
i.logger.Warn().Str("dn", e.DN).Str("id", id).Str("displayName", displayName).Str("schoolNumber", schoolNumber).Msg("Invalid School. Missing required attribute")
return nil
school := libregraph.NewEducationSchool()
school.SetDisplayName(displayName)
school.SetId(id)
if schoolNumber != "" {
school.SetSchoolNumber(schoolNumber)
}
if t != nil {
school.SetTerminationDate(*t)
}
return school
}
func (i *LDAP) getSchoolNumber(e *ldap.Entry) string {

View File

@@ -83,9 +83,8 @@ func (i *LDAP) GetGroups(ctx context.Context, oreq *godata.GoDataRequest) ([]*li
if search != "" {
search = ldap.EscapeFilter(search)
groupFilter = fmt.Sprintf(
"(|(%s=*%s*)(%s=*%s*))",
"(%s=*%s*)",
i.groupAttributeMap.name, search,
i.groupAttributeMap.id, search,
)
}
groupFilter = fmt.Sprintf("(&%s(objectClass=%s)%s)", i.groupFilter, i.groupObjectClass, groupFilter)

View File

@@ -305,7 +305,7 @@ func TestGetGroupsSearch(t *testing.T) {
// only match if the filter contains the search term unquoted
lm.On("Search", mock.MatchedBy(
func(req *ldap.SearchRequest) bool {
return req.Filter == "(&(objectClass=groupOfNames)(|(cn=*term*)(entryUUID=*term*)))"
return req.Filter == "(&(objectClass=groupOfNames)(cn=*term*))"
})).
Return(&ldap.SearchResult{}, nil)
b, _ := getMockedBackend(lm, lconfig, &logger)

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-15 00:01+0000\n"
"POT-Creation-Date: 2025-10-26 00:00+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-21 00:01+0000\n"
"POT-Creation-Date: 2025-11-01 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-09-26 00:01+0000\n"
"POT-Creation-Date: 2025-10-16 08:04+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: LinkinWires <darkinsonic13@gmail.com>, 2025\n"
"Language-Team: Ukrainian (https://app.transifex.com/opencloud-eu/teams/204053/uk/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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

@@ -18,13 +18,23 @@ func Server(opts ...Option) (*http.Server, error) {
WithLogger(options.Logger).
WithCheck("web reachability", checks.NewHTTPCheck(options.Config.HTTP.Addr))
u, err := url.Parse(options.Config.Identity.LDAP.URI)
if err != nil {
return nil, err
readyHandlerConfiguration := healthHandlerConfiguration
// Check for LDAP reachability, when we're using the LDAP backend
if options.Config.Identity.Backend == "ldap" {
u, err := url.Parse(options.Config.Identity.LDAP.URI)
if err != nil {
return nil, err
}
readyHandlerConfiguration = readyHandlerConfiguration.
WithCheck("ldap reachability", checks.NewTCPCheck(u.Host))
}
// only check nats if really needed
if options.Config.Events.Endpoint != "" {
readyHandlerConfiguration = readyHandlerConfiguration.
WithCheck("nats reachability", checks.NewNatsCheck(options.Config.Events.Endpoint))
}
readyHandlerConfiguration := healthHandlerConfiguration.
WithCheck("nats reachability", checks.NewNatsCheck(options.Config.Events.Endpoint)).
WithCheck("ldap reachability", checks.NewTCPCheck(u.Host))
return debug.NewService(
debug.Logger(options.Logger),

View File

@@ -3,11 +3,13 @@ package http
import (
"context"
"github.com/nats-io/nats.go/jetstream"
"github.com/urfave/cli/v2"
"go.opentelemetry.io/otel/trace"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
"github.com/opencloud-eu/opencloud/services/graph/pkg/metrics"
"github.com/urfave/cli/v2"
"go.opentelemetry.io/otel/trace"
)
// Option defines a single option function.
@@ -22,6 +24,7 @@ type Options struct {
Flags []cli.Flag
Namespace string
TraceProvider trace.TracerProvider
NatsKeyValue jetstream.KeyValue
}
// newOptions initializes the available default options.
@@ -83,3 +86,10 @@ func TraceProvider(val trace.TracerProvider) Option {
o.TraceProvider = val
}
}
// NatsKeyValue provides a function to set the NatsKeyValue option.
func NatsKeyValue(val jetstream.KeyValue) Option {
return func(o *Options) {
o.NatsKeyValue = val
}
}

View File

@@ -178,6 +178,7 @@ func Server(opts ...Option) (http.Service, error) {
svc.KeycloakClient(keyCloakClient),
svc.EventHistoryClient(hClient),
svc.TraceProvider(options.TraceProvider),
svc.WithNatsKeyValue(options.NatsKeyValue),
)
if err != nil {

View File

@@ -74,12 +74,6 @@ func (g Graph) PostEducationSchool(w http.ResponseWriter, r *http.Request) {
return
}
if _, ok := school.GetSchoolNumberOk(); !ok {
logger.Debug().Interface("school", school).Msg("could not create school: missing required attribute")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "Missing Required Attribute")
return
}
// validate terminationDate attribute, needs to be "far enough" in the future, terminationDate can be nil (means
// termination date is to be deleted
if terminationDate, ok := school.GetTerminationDateOk(); ok && terminationDate != nil {

View File

@@ -232,18 +232,6 @@ var _ = Describe("Schools", func() {
Expect(rr.Code).To(Equal(http.StatusBadRequest))
})
It("handles missing school number", func() {
newSchool = libregraph.NewEducationSchool()
newSchool.SetDisplayName("New School")
newSchoolJson, err := json.Marshal(newSchool)
Expect(err).ToNot(HaveOccurred())
r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/education/schools/", bytes.NewBuffer(newSchoolJson))
svc.PostEducationSchool(rr, r)
Expect(rr.Code).To(Equal(http.StatusBadRequest))
})
It("disallows school create ids", func() {
newSchool = libregraph.NewEducationSchool()
newSchool.SetId("disallowed")

View File

@@ -76,18 +76,7 @@ func (g Graph) PostEducationUser(w http.ResponseWriter, r *http.Request) {
return
}
identities, ok := u.GetIdentitiesOk()
if !ok {
logger.Debug().Err(err).Interface("user", u).Msg("could not create education user: missing required Collection: 'identities'")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing required Attribute: 'identities'")
return
}
if len(identities) < 1 {
logger.Debug().Err(err).Interface("user", u).Msg("could not create education user: missing entry in Collection: 'identities'")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing required Collection: 'identities'")
return
}
for i, identity := range identities {
for i, identity := range u.GetIdentities() {
if _, ok := identity.GetIssuerOk(); !ok {
logger.Debug().Err(err).Interface("user", u).Msgf("could not create education user: missing Attribute in 'identities' Collection Entry %d: 'issuer'", i)
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, fmt.Sprintf("missing Attribute in 'identities' Collection Entry %d: 'issuer'", i))
@@ -130,12 +119,6 @@ func (g Graph) PostEducationUser(w http.ResponseWriter, r *http.Request) {
u.SetUserType("Member")
}
if _, ok := u.GetPrimaryRoleOk(); !ok {
logger.Debug().Err(err).Interface("user", u).Msg("could not create education user: missing required Attribute: 'primaryRole'")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing required Attribute: 'primaryRole'")
return
}
logger.Debug().Interface("user", u).Msg("calling create education user on backend")
if u, err = g.identityEducationBackend.CreateEducationUser(r.Context(), *u); err != nil {
logger.Debug().Err(err).Msg("could not create education user: backend error")

View File

@@ -12,6 +12,7 @@ import (
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/go-chi/chi/v5"
"github.com/jellydator/ttlcache/v3"
"github.com/nats-io/nats.go/jetstream"
"go-micro.dev/v4/client"
"go.opentelemetry.io/otel/trace"
"google.golang.org/protobuf/types/known/emptypb"
@@ -67,6 +68,7 @@ type Graph struct {
keycloakClient keycloak.Client
historyClient ehsvc.EventHistoryService
traceProvider trace.TracerProvider
natskv jetstream.KeyValue
}
// ServeHTTP implements the Service interface.

View File

@@ -5,6 +5,7 @@ import (
"net/http"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
"github.com/nats-io/nats.go/jetstream"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
"go.opentelemetry.io/otel/trace"
@@ -43,6 +44,7 @@ type Options struct {
KeycloakClient keycloak.Client
EventHistoryClient ehsvc.EventHistoryService
TraceProvider trace.TracerProvider
NatsKeyValue jetstream.KeyValue
}
// newOptions initializes the available default options.
@@ -112,6 +114,13 @@ func WithIdentityEducationBackend(val identity.EducationBackend) Option {
}
}
// WithNatsKeyValue provides a function to set the NatsKeyValue option.
func WithNatsKeyValue(val jetstream.KeyValue) Option {
return func(o *Options) {
o.NatsKeyValue = val
}
}
// WithRoleService provides a function to set the RoleService option.
func WithRoleService(val RoleService) Option {
return func(o *Options) {

View File

@@ -198,6 +198,7 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
historyClient: options.EventHistoryClient,
traceProvider: options.TraceProvider,
valueService: options.ValueService,
natskv: options.NatsKeyValue,
}
if err := setIdentityBackends(options, &svc); err != nil {

View File

@@ -2,6 +2,7 @@ package svc
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -22,18 +23,21 @@ import (
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/google/uuid"
"github.com/nats-io/nats.go/jetstream"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
"github.com/opencloud-eu/reva/v2/pkg/utils"
settingsmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/settings/v0"
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
"github.com/opencloud-eu/opencloud/services/graph/pkg/userstate"
ocsettingssvc "github.com/opencloud-eu/opencloud/services/settings/pkg/service/v0"
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
"github.com/opencloud-eu/reva/v2/pkg/utils"
)
// GetMe implements the Service interface.
@@ -642,7 +646,30 @@ func (g Graph) DeleteUser(w http.ResponseWriter, r *http.Request) {
return
}
if g.config.UserSoftDeleteRetentionTime > 0 && purgeUser && user.GetAccountEnabled() {
us, err := g.getUserStateFromNatsKeyValue(r.Context(), userID)
if err != nil {
logger.Error().Err(err).Str("id", userID).Msg("could not get user state")
us = userstate.UserState{
UserId: userID,
State: userstate.UserStateUnspecified,
}
}
if us.State == userstate.UserStateHardDeleted {
logger.Debug().Str("id", userID).Msg("could not delete user: user already hard deleted")
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, "user not found")
return
}
if us.State == userstate.UserStateUnspecified {
if user.GetAccountEnabled() {
us.State = userstate.UserStateEnabled
} else {
us.State = userstate.UserStateSoftDeleted
}
}
if g.config.UserSoftDeleteRetentionTime > 0 && purgeUser && us.State == userstate.UserStateEnabled {
logger.Debug().Msg("could not delete user: purgeUser is set but user is still enabled")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "user should be hard deleted, but is still enabled, please soft delete first")
return
@@ -684,7 +711,9 @@ func (g Graph) DeleteUser(w http.ResponseWriter, r *http.Request) {
return
}
for _, sp := range lspr.GetStorageSpaces() {
if !(sp.SpaceType == _spaceTypePersonal && sp.Owner.Id.OpaqueId == user.GetId()) {
// if the spacetype equals _spaceTypePersonal and the owner id equals the user id
// then we found the personal space of the user to be deleted
if !(sp.GetSpaceType() == _spaceTypePersonal && sp.Owner.GetId().GetOpaqueId() == user.GetId()) {
continue
}
// TODO: check if request contains a homespace and if, check if requesting user has the privilege to
@@ -706,7 +735,7 @@ func (g Graph) DeleteUser(w http.ResponseWriter, r *http.Request) {
}
}
// the space will if the system does not have a UserSoftDeleteRetentionTime configured, e.g. SoftDelete disabled
if g.config.UserSoftDeleteRetentionTime == 0 || (purgeUser && !user.GetAccountEnabled()) {
if g.config.UserSoftDeleteRetentionTime == 0 || (purgeUser && us.State == userstate.UserStateSoftDeleted) {
purgeSpaceFlag := utils.AppendPlainToOpaque(nil, "purge", "")
_, err := client.DeleteStorageSpace(r.Context(), &storageprovider.DeleteStorageSpaceRequest{
Opaque: purgeSpaceFlag,
@@ -725,24 +754,41 @@ func (g Graph) DeleteUser(w http.ResponseWriter, r *http.Request) {
}
}
if g.config.UserSoftDeleteRetentionTime == 0 || (purgeUser && !user.GetAccountEnabled()) {
if (g.config.UserSoftDeleteRetentionTime > 0 && us.State == userstate.UserStateSoftDeleted && purgeUser) ||
(g.config.UserSoftDeleteRetentionTime == 0) {
logger.Debug().Str("id", user.GetId()).Msg("calling delete user on backend")
err = g.identityBackend.DeleteUser(r.Context(), user.GetId())
if err != nil {
logger.Debug().Err(err).Msg("could not delete user: backend error")
errorcode.RenderError(w, r, err)
return
}
us.State = userstate.UserStateHardDeleted
err = g.setUserStateToNatsKeyValue(r.Context(), userID, us)
if err != nil {
logger.Error().Err(err).Str("id", userID).Msg("could not set user state")
errorcode.RenderError(w, r, err)
}
} else {
logger.Debug().Str("id", user.GetId()).Msg("calling soft delete user on backend")
userUpdate := *libregraph.NewUserUpdate()
userUpdate.AccountEnabled = libregraph.PtrBool(false)
us.State = userstate.UserStateSoftDeleted
us.RetentionPeriod = g.config.UserSoftDeleteRetentionTime
us.Reason = "User soft deleted via Graph API" // TODO: this needs a proper implementation through the request
us.TimeStamp = time.Now()
err = g.setUserStateToNatsKeyValue(r.Context(), userID, us)
if err != nil {
logger.Error().Err(err).Str("id", userID).Msg("could not set user state")
errorcode.RenderError(w, r, err)
return
}
g.identityBackend.UpdateUser(r.Context(), user.GetId(), userUpdate)
}
if g.config.UserSoftDeleteRetentionTime == 0 ||
(g.config.UserSoftDeleteRetentionTime > 0 && purgeUser && !user.GetAccountEnabled()) {
(g.config.UserSoftDeleteRetentionTime > 0 && purgeUser && us.State == userstate.UserStateSoftDeleted) {
e := events.UserDeleted{UserID: user.GetId()}
e.Executant = currentUser.GetId()
g.publishEvent(r.Context(), e)
@@ -1103,3 +1149,62 @@ func (g Graph) searchOCMAcceptedUsers(ctx context.Context, odataReq *godata.GoDa
}
return users, nil
}
// getUserStateFromNatsKeyValue gets the user state from the nats key value store.
func (g Graph) getUserStateFromNatsKeyValue(ctx context.Context, userID string) (userstate.UserState, error) {
logger := g.logger.SubloggerWithRequestID(ctx)
if g.natskv == nil {
logger.Debug().Msg("nats connection or user state key value store not configured")
return userstate.UserState{}, errors.New("nats connection or user state key value store not configured")
}
entry, err := g.natskv.Get(ctx, userID)
if err != nil {
if errors.Is(err, jetstream.ErrKeyNotFound) {
logger.Debug().Str("userid", userID).Msg("no user state found in nats key value store")
return userstate.UserState{
UserId: userID,
State: userstate.UserStateUnspecified,
}, nil
}
logger.Error().Err(err).Str("userid", userID).Msg("error getting user state from nats key value store")
return userstate.UserState{}, err
}
userState := userstate.UserState{}
v := entry.Value()
if err := json.Unmarshal(v, &userState); err != nil {
logger.Error().Err(err).Str("userid", userID).Msg("error unmarshalling user state from nats key value store")
return userstate.UserState{}, err
}
return userState, nil
}
// setUserStateToNatsKeyValue sets the user state in the nats key value store.
func (g Graph) setUserStateToNatsKeyValue(ctx context.Context, userID string, us userstate.UserState) error {
logger := g.logger.SubloggerWithRequestID(ctx)
if ok, err := userstate.IsValidUserState(&us); !ok {
logger.Debug().Str("userid", userID).Msg("invalid user state")
return fmt.Errorf("invalid user state: %w", err)
}
if g.natskv == nil {
logger.Debug().Msg("nats connection or user state key value store not configured")
return nil
}
data, err := json.Marshal(us)
if err != nil {
logger.Error().Err(err).Str("userid", userID).Msg("error marshalling user state to nats key value store")
return err
}
if _, err := g.natskv.Put(ctx, userID, data); err != nil {
logger.Error().Err(err).Str("userid", userID).Msg("error putting user state to nats key value store")
return err
}
return nil
}

View File

@@ -16,6 +16,7 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/go-chi/chi/v5"
"github.com/nats-io/nats.go/jetstream"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
@@ -27,6 +28,8 @@ import (
"go-micro.dev/v4/client"
"google.golang.org/grpc"
"github.com/opencloud-eu/opencloud/services/graph/pkg/userstate"
"github.com/opencloud-eu/opencloud/pkg/shared"
settingsmsg "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/settings/v0"
settings "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
@@ -54,6 +57,7 @@ var _ = Describe("Users", func() {
valueService *settingsmocks.ValueService
permissionService *mocks.Permissions
identityBackend *identitymocks.Backend
natsKeyValueMock *mocks.KeyValue
rr *httptest.ResponseRecorder
@@ -79,6 +83,7 @@ var _ = Describe("Users", func() {
identityBackend = &identitymocks.Backend{}
roleService = &mocks.RoleService{}
natsKeyValueMock = &mocks.KeyValue{}
valueService = &settingsmocks.ValueService{}
permissionService = &mocks.Permissions{}
@@ -105,6 +110,7 @@ var _ = Describe("Users", func() {
service.WithRoleService(roleService),
service.WithValueService(valueService),
service.PermissionService(permissionService),
service.WithNatsKeyValue(natsKeyValueMock),
)
Expect(err).ToNot(HaveOccurred())
})
@@ -968,6 +974,25 @@ var _ = Describe("Users", func() {
lu.SetId(currentUser.Id.OpaqueId)
identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(&lu, nil)
natsKeyValueMock.EXPECT().Get(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string) (jetstream.KeyValueEntry, error) {
byteRep, _ := json.Marshal(userstate.UserState{
UserId: lu.GetId(),
State: userstate.UserStateSoftDeleted,
TimeStamp: time.Now().UTC(),
RetentionPeriod: 5 * time.Minute,
Reason: "unit test",
})
kve := &mocks.KeyValueEntry{}
kve.On("Value").Return(byteRep)
return kve, nil
}).Once()
natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string, val []byte) (uint64, error) {
return 1, nil
}).Once()
r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil)
rctx := chi.NewRouteContext()
rctx.URLParams.Add("userID", currentUser.Id.OpaqueId)
@@ -1004,6 +1029,25 @@ var _ = Describe("Users", func() {
},
}, nil)
natsKeyValueMock.EXPECT().Get(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string) (jetstream.KeyValueEntry, error) {
byteRep, _ := json.Marshal(userstate.UserState{
UserId: lu.GetId(),
State: userstate.UserStateSoftDeleted,
TimeStamp: time.Now().UTC(),
RetentionPeriod: 5 * time.Minute,
Reason: "unit test",
})
kve := &mocks.KeyValueEntry{}
kve.On("Value").Return(byteRep)
return kve, nil
}).Once()
natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string, val []byte) (uint64, error) {
return 1, nil
}).Once()
r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil)
rctx := chi.NewRouteContext()
rctx.URLParams.Add("userID", lu.GetId())
@@ -1047,7 +1091,7 @@ var _ = Describe("Users", func() {
lu := libregraph.User{}
lu.SetId(otheruser.Id.OpaqueId)
identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(&lu, nil)
identityBackend.On("DeleteUser", mock.Anything, mock.Anything).Return(nil)
//identityBackend.On("DeleteUser", mock.Anything, mock.Anything).Return(nil)
identityBackend.On("UpdateUser", mock.Anything, mock.Anything, mock.Anything).Return(&lu, nil)
gatewayClient.On("DeleteStorageSpace", mock.Anything, mock.Anything).Return(&provider.DeleteStorageSpaceResponse{
Status: status.NewOK(ctx),
@@ -1065,6 +1109,24 @@ var _ = Describe("Users", func() {
},
}, nil)
natsKeyValueMock.EXPECT().Get(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string) (jetstream.KeyValueEntry, error) {
byteRep, _ := json.Marshal(userstate.UserState{
UserId: lu.GetId(),
State: userstate.UserStateSoftDeleted,
TimeStamp: time.Now().UTC(),
RetentionPeriod: 5 * time.Minute,
Reason: "unit test",
})
kve := &mocks.KeyValueEntry{}
kve.On("Value").Return(byteRep)
return kve, nil
}).Once()
natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string, val []byte) (uint64, error) {
return 1, nil
}).Once()
r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil)
rctx := chi.NewRouteContext()
rctx.URLParams.Add("userID", lu.GetId())
@@ -1104,6 +1166,25 @@ var _ = Describe("Users", func() {
},
}, nil)
natsKeyValueMock.EXPECT().Get(mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string) (jetstream.KeyValueEntry, error) {
byteRep, _ := json.Marshal(userstate.UserState{
UserId: lu.GetId(),
State: userstate.UserStateSoftDeleted,
TimeStamp: time.Now().UTC(),
RetentionPeriod: 5 * time.Minute,
Reason: "unit test",
})
kve := &mocks.KeyValueEntry{}
kve.On("Value").Return(byteRep)
return kve, nil
}).Once()
natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(_ context.Context, key string, val []byte) (uint64, error) {
return 1, nil
}).Once()
r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil)
r.Header.Set("Prefer", "purge") // this header is used to indicate a hard delete
rctx := chi.NewRouteContext()

View File

@@ -0,0 +1,37 @@
package userstate
import (
"fmt"
"time"
)
const (
_ = iota
UserStateUnspecified
UserStateEnabled
UserStateDisabled
UserStateSoftDeleted
UserStateHardDeleted
)
// UserState represents the state of a user account.
// Note: This does not reflect state changes, these need to be red from the audit logs.
type UserState struct {
UserId string `json:"userid"`
State uint8 `json:"state"`
TimeStamp time.Time `json:"timestamp,omitempty"`
RetentionPeriod time.Duration `json:"retentionPeriod,omitempty"`
Reason string `json:"reason,omitempty,omitempty"`
}
func IsValidUserState(us *UserState) (bool, error) {
if us.State == UserStateSoftDeleted {
if us.RetentionPeriod <= 0 {
return false, fmt.Errorf("retention period must be greater than 0 for soft deleted users")
}
if us.Reason == "" {
return false, fmt.Errorf("reason must be provided for soft deleted users")
}
}
return true, nil
}

View File

@@ -2,6 +2,7 @@ package parser
import (
"errors"
"fmt"
occfg "github.com/opencloud-eu/opencloud/pkg/config"
"github.com/opencloud-eu/opencloud/pkg/shared"
@@ -38,6 +39,9 @@ func Validate(cfg *config.Config) error {
return shared.MissingJWTTokenError(cfg.Service.Name)
}
if cfg.Commons.MultiTenantEnabled && cfg.Driver != "null" {
return fmt.Errorf("Multi-tenant support is enabled. Only the 'null'-driver is supported by 'groups' service.")
}
if cfg.Drivers.LDAP.BindPassword == "" && cfg.Driver == "ldap" {
return shared.MissingLDAPBindPassword(cfg.Service.Name)
}

View File

@@ -19,6 +19,7 @@ func GroupsConfigFromStruct(cfg *config.Config) map[string]interface{} {
"gatewaysvc": cfg.Reva.Address,
"skip_user_groups_in_token": cfg.SkipUserGroupsInToken,
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"grpc": map[string]interface{}{
"network": cfg.GRPC.Protocol,

View File

@@ -147,7 +147,7 @@ function Login(props) {
spellCheck="false"
value={username}
onChange={handleChange("username")}
autoComplete="kopano-account username"
autoComplete="username"
placeholder={t("konnect.login.usernameField.label", "Username")}
label={t("konnect.login.usernameField.label", "Username")}
id="oc-login-username"
@@ -157,7 +157,7 @@ function Login(props) {
type="password"
margin="normal"
onChange={handleChange("password")}
autoComplete="kopano-account current-password"
autoComplete="current-password"
placeholder={t("konnect.login.passwordField.label", "Password")}
label={t("konnect.login.passwordField.label", "Password")}
id="oc-login-password"

View File

@@ -3,9 +3,12 @@ package channels
import (
"context"
"crypto/rand"
"crypto/tls"
"fmt"
stdmail "net/mail"
"strings"
"time"
"github.com/pkg/errors"
mail "github.com/xhit/go-simple-mail/v2"
@@ -118,6 +121,7 @@ func (m Mail) SendMessage(_ context.Context, message *Message) error {
email := mail.NewMSG()
email.SetFrom(appendSender(message.Sender, m.smtpAddress)).AddTo(message.Recipient...)
email.SetSubject(message.Subject)
email.AddHeader("Message-ID", generateMessageID(m.smtpAddress.Address))
email.SetBody(mail.TextPlain, message.TextBody)
if message.HTMLBody != "" {
email.AddAlternative(mail.TextHTML, message.HTMLBody)
@@ -135,3 +139,22 @@ func appendSender(sender string, a stdmail.Address) string {
}
return a.String()
}
// generateMessageID generates a unique Message-ID header value according to RFC 5322
func generateMessageID(domain string) string {
// Extract domain from email address if it contains @
if idx := strings.LastIndex(domain, "@"); idx != -1 {
domain = domain[idx+1:]
}
// Generate random bytes for uniqueness
b := make([]byte, 16)
if _, err := rand.Read(b); err != nil {
// Fallback to timestamp-based ID if random fails
return fmt.Sprintf("<%d@%s>", time.Now().UnixNano(), domain)
}
// Create Message-ID: <timestamp.random@domain>
timestamp := time.Now().Unix()
return fmt.Sprintf("<%d.%x@%s>", timestamp, b, domain)
}

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-22 00:01+0000\n"
"POT-Creation-Date: 2025-11-02 00:02+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: miguel tapias, 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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-15 00:01+0000\n"
"POT-Creation-Date: 2025-10-26 00:00+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Stephan Paternotte <stephan@paternottes.net>, 2025\n"
"Language-Team: Dutch (https://app.transifex.com/opencloud-eu/teams/204053/nl/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2025-09-16 00:01+0000\n"
"POT-Creation-Date: 2025-10-27 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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

@@ -25,9 +25,10 @@ func OCMConfigFromStruct(cfg *config.Config, logger log.Logger) map[string]inter
return map[string]interface{}{
"shared": map[string]interface{}{
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address, // Todo or address?
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"jwt_secret": cfg.TokenManager.JWTSecret,
"gatewaysvc": cfg.Reva.Address, // Todo or address?
"grpc_client_options": cfg.Reva.GetGRPCClientConfig(),
"multi_tenant_enabled": cfg.Commons.MultiTenantEnabled,
},
"http": map[string]interface{}{
"network": cfg.HTTP.Protocol,

View File

@@ -370,6 +370,7 @@ func loadMiddlewares(logger log.Logger, cfg *config.Config,
middleware.UserOIDCClaim(cfg.UserOIDCClaim),
middleware.UserCS3Claim(cfg.UserCS3Claim),
middleware.AutoprovisionAccounts(cfg.AutoprovisionAccounts),
middleware.MultiTenantEnabled(cfg.Commons.MultiTenantEnabled),
middleware.EventsPublisher(publisher),
),
middleware.SelectorCookie(

View File

@@ -274,7 +274,7 @@ func DefaultPolicies() []config.Policy {
},
{
Endpoint: "/wopi",
Service: "eu.opencloud.web.collaboration.Collabora",
Service: "eu.opencloud.web.collaboration",
Unprotected: true,
SkipXAccessToken: true,
},

View File

@@ -43,6 +43,7 @@ func AccountResolver(optionSetters ...Option) func(next http.Handler) http.Handl
userCS3Claim: options.UserCS3Claim,
userRoleAssigner: options.UserRoleAssigner,
autoProvisionAccounts: options.AutoprovisionAccounts,
multiTenantEnabled: options.MultiTenantEnabled,
lastGroupSyncCache: lastGroupSyncCache,
eventsPublisher: options.EventsPublisher,
}
@@ -56,6 +57,7 @@ type accountResolver struct {
userProvider backend.UserBackend
userRoleAssigner userroles.UserRoleAssigner
autoProvisionAccounts bool
multiTenantEnabled bool
userOIDCClaim string
userCS3Claim string
// lastGroupSyncCache is used to keep track of when the last sync of group
@@ -159,6 +161,14 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
return
}
// if this is a multi-tenant setup, make sure the resolved user has a tenant id set
if m.multiTenantEnabled && user.GetId().GetTenantId() == "" {
m.logger.Error().Str("userid", user.Id.OpaqueId).Msg("User does not have a tenantId assigned")
w.WriteHeader(http.StatusUnauthorized)
return
}
// update user if needed
if m.autoProvisionAccounts {
if err = m.userProvider.UpdateUserIfNeeded(req.Context(), user, claims); err != nil {
m.logger.Error().Err(err).Str("userid", user.GetId().GetOpaqueId()).Interface("claims", claims).Msg("Failed to update autoprovisioned user")
@@ -201,6 +211,13 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
m.logger.Debug().Interface("claims", claims).Interface("user", user).Msg("associated claims with user")
} else if user != nil && !hasToken {
// if this is a multi-tenant setup, make sure the resolved user has a tenant id set
if m.multiTenantEnabled && user.GetId().GetTenantId() == "" {
m.logger.Error().Str("userid", user.Id.OpaqueId).Msg("User does not have a tenantId assigned")
w.WriteHeader(http.StatusUnauthorized)
return
}
// If we already have a token (e.g. the app auth middleware adds the token to the context) there is no need
// to get yet another one here.
var err error

View File

@@ -24,7 +24,7 @@ func TestTokenIsAddedWithMailClaim(t *testing.T) {
sut := newMockAccountResolver(&userv1beta1.User{
Id: &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
Mail: "foo@example.com",
}, nil, oidc.Email, "mail")
}, nil, oidc.Email, "mail", false)
req, rw := mockRequest(map[string]interface{}{
oidc.Iss: "https://idx.example.com",
@@ -42,7 +42,7 @@ func TestTokenIsAddedWithUsernameClaim(t *testing.T) {
sut := newMockAccountResolver(&userv1beta1.User{
Id: &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
Mail: "foo@example.com",
}, nil, oidc.PreferredUsername, "username")
}, nil, oidc.PreferredUsername, "username", false)
req, rw := mockRequest(map[string]interface{}{
oidc.Iss: "https://idx.example.com",
@@ -61,7 +61,7 @@ func TestTokenIsAddedWithDotUsernamePathClaim(t *testing.T) {
sut := newMockAccountResolver(&userv1beta1.User{
Id: &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
Mail: "foo@example.com",
}, nil, "li.un", "username")
}, nil, "li.un", "username", false)
// This is how lico adds the username to the access token
req, rw := mockRequest(map[string]interface{}{
@@ -83,7 +83,7 @@ func TestTokenIsAddedWithDotEscapedUsernameClaim(t *testing.T) {
sut := newMockAccountResolver(&userv1beta1.User{
Id: &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
Mail: "foo@example.com",
}, nil, "li\\.un", "username")
}, nil, "li\\.un", "username", false)
// This tests the . escaping of the readUserIDClaim
req, rw := mockRequest(map[string]interface{}{
@@ -103,7 +103,7 @@ func TestTokenIsAddedWithDottedUsernameClaimFallback(t *testing.T) {
sut := newMockAccountResolver(&userv1beta1.User{
Id: &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
Mail: "foo@example.com",
}, nil, "li.un", "username")
}, nil, "li.un", "username", false)
// This tests the . escaping fallback of the readUserIDClaim
req, rw := mockRequest(map[string]interface{}{
@@ -120,7 +120,7 @@ func TestTokenIsAddedWithDottedUsernameClaimFallback(t *testing.T) {
}
func TestNSkipOnNoClaims(t *testing.T) {
sut := newMockAccountResolver(nil, backend.ErrAccountDisabled, oidc.Email, "mail")
sut := newMockAccountResolver(nil, backend.ErrAccountDisabled, oidc.Email, "mail", false)
req, rw := mockRequest(nil)
sut.ServeHTTP(rw, req)
@@ -131,7 +131,7 @@ func TestNSkipOnNoClaims(t *testing.T) {
}
func TestUnauthorizedOnUserNotFound(t *testing.T) {
sut := newMockAccountResolver(nil, backend.ErrAccountNotFound, oidc.PreferredUsername, "username")
sut := newMockAccountResolver(nil, backend.ErrAccountNotFound, oidc.PreferredUsername, "username", false)
req, rw := mockRequest(map[string]interface{}{
oidc.Iss: "https://idx.example.com",
oidc.PreferredUsername: "foo",
@@ -145,7 +145,7 @@ func TestUnauthorizedOnUserNotFound(t *testing.T) {
}
func TestUnauthorizedOnUserDisabled(t *testing.T) {
sut := newMockAccountResolver(nil, backend.ErrAccountDisabled, oidc.PreferredUsername, "username")
sut := newMockAccountResolver(nil, backend.ErrAccountDisabled, oidc.PreferredUsername, "username", false)
req, rw := mockRequest(map[string]interface{}{
oidc.Iss: "https://idx.example.com",
oidc.PreferredUsername: "foo",
@@ -159,7 +159,7 @@ func TestUnauthorizedOnUserDisabled(t *testing.T) {
}
func TestInternalServerErrorOnMissingMailAndUsername(t *testing.T) {
sut := newMockAccountResolver(nil, backend.ErrAccountNotFound, oidc.Email, "mail")
sut := newMockAccountResolver(nil, backend.ErrAccountNotFound, oidc.Email, "mail", false)
req, rw := mockRequest(map[string]interface{}{
oidc.Iss: "https://idx.example.com",
})
@@ -171,7 +171,49 @@ func TestInternalServerErrorOnMissingMailAndUsername(t *testing.T) {
assert.Equal(t, http.StatusInternalServerError, rw.Code)
}
func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr error, oidcclaim, cs3claim string) http.Handler {
func TestUnauthorizedOnMissingTenantId(t *testing.T) {
sut := newMockAccountResolver(
&userv1beta1.User{
Id: &userv1beta1.UserId{Idp: "https://idx.example.com", OpaqueId: "123"},
Username: "foo",
},
nil, oidc.PreferredUsername, "username", true)
req, rw := mockRequest(map[string]any{
oidc.Iss: "https://idx.example.com",
oidc.PreferredUsername: "foo",
})
sut.ServeHTTP(rw, req)
token := req.Header.Get(revactx.TokenHeader)
assert.Empty(t, token)
assert.Equal(t, http.StatusUnauthorized, rw.Code)
}
func TestTokenIsAddedWhenUserHasTenantId(t *testing.T) {
sut := newMockAccountResolver(
&userv1beta1.User{
Id: &userv1beta1.UserId{
Idp: "https://idx.example.com",
OpaqueId: "123",
TenantId: "tenant1",
},
Username: "foo",
},
nil, oidc.PreferredUsername, "username", true)
req, rw := mockRequest(map[string]any{
oidc.Iss: "https://idx.example.com",
oidc.PreferredUsername: "foo",
})
sut.ServeHTTP(rw, req)
token := req.Header.Get(revactx.TokenHeader)
assert.NotEmpty(t, token)
assert.Contains(t, token, "eyJ")
}
func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr error, oidcclaim, cs3claim string, multiTenant bool) http.Handler {
tokenManager, _ := jwt.New(map[string]interface{}{
"secret": "change-me",
"expires": int64(60),
@@ -198,6 +240,7 @@ func newMockAccountResolver(userBackendResult *userv1beta1.User, userBackendErr
UserOIDCClaim(oidcclaim),
UserCS3Claim(cs3claim),
AutoprovisionAccounts(false),
MultiTenantEnabled(multiTenant),
)(mockHandler{})
}

View File

@@ -70,8 +70,10 @@ type Options struct {
// TraceProvider sets the tracing provider.
TraceProvider trace.TracerProvider
// SkipUserInfo prevents the oidc middleware from querying the userinfo endpoint and read any claims directly from the access token instead
SkipUserInfo bool
EventsPublisher events.Publisher
SkipUserInfo bool
// MultiTenantEnabled causes the account resolve middleware to reject users that don't have a tenant id assigned
MultiTenantEnabled bool
EventsPublisher events.Publisher
}
// newOptions initializes the available default options.
@@ -239,6 +241,13 @@ func SkipUserInfo(val bool) Option {
}
}
// MultiTenantEnabled sets the MultiTenantEnabled flag.
func MultiTenantEnabled(val bool) Option {
return func(o *Options) {
o.MultiTenantEnabled = val
}
}
// EventsPublisher sets the events publisher.
func EventsPublisher(ep events.Publisher) Option {
return func(o *Options) {

View File

@@ -33,7 +33,7 @@ type Config struct {
TokenManager *TokenManager `yaml:"token_manager"`
SetupDefaultAssignments bool `yaml:"set_default_assignments" env:"SETTINGS_SETUP_DEFAULT_ASSIGNMENTS;IDM_CREATE_DEMO_USERS" desc:"The default role assignments the demo users should be setup." introductionVersion:"1.0.0"`
SetupDefaultAssignments bool `yaml:"set_default_assignments" env:"IDM_CREATE_DEMO_USERS;SETTINGS_SETUP_DEFAULT_ASSIGNMENTS" desc:"The default role assignments the demo users should be setup." introductionVersion:"1.0.0"`
ServiceAccountIDs []string `yaml:"service_account_ids" env:"SETTINGS_SERVICE_ACCOUNT_IDS;OC_SERVICE_ACCOUNT_ID" desc:"The list of all service account IDs. These will be assigned the hidden 'service-account' role. Note: When using 'OC_SERVICE_ACCOUNT_ID' this will contain only one value while 'SETTINGS_SERVICE_ACCOUNT_IDS' can have multiple. See the 'auth-service' service description for more details about service accounts." 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-09-09 00:02+0000\n"
"POT-Creation-Date: 2025-10-20 00:01+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"

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