Compare commits

...

31 Commits

Author SHA1 Message Date
OpenCloud Devops
edb917b74a 🎉 Release 5.1.0 (#2300) 2026-02-16 15:31:10 +01:00
Andre Duffeck
2fdb87291e Merge pull request #2348 from aduffeck/bump-reva-v2.42.4
[full-ci] Bump reva v2.42.4
2026-02-16 14:11:04 +01:00
Benedikt Kulmann
153fdeeac0 Merge pull request #2349 from opencloud-eu/bump-web-5.1.0
[full-ci] chore: bump web to v5.1.0
2026-02-16 12:51:34 +01:00
André Duffeck
2043dee745 Bump opencloud version 2026-02-16 11:02:50 +01:00
Benedikt Kulmann
5be98670f4 chore: bump web to v5.1.0 2026-02-16 11:01:47 +01:00
André Duffeck
97da8655b7 Bump reva 2026-02-16 10:53:20 +01:00
opencloudeu
e698a35aef [tx] updated from transifex 2026-02-16 00:16:53 +00:00
opencloudeu
d867665dc1 [tx] updated from transifex 2026-02-15 00:16:35 +00:00
opencloudeu
e0b465342f [tx] updated from transifex 2026-02-14 00:16:38 +00:00
Thomas Schweiger
8f3714f08f Merge pull request #2333 from opencloud-eu/fix/fix-typo-in-var-description
fix: fix typo in variable description
2026-02-12 18:13:02 +01:00
Michael Barz
1c493ec46b fix: include sessionID in sse logout event (#2327) 2026-02-12 17:21:09 +01:00
Thomas Schweiger
bac83c4729 fix: fix typo in variable description 2026-02-12 16:48:12 +01:00
Thomas Schweiger
b4af917ab3 Merge pull request #2332 from opencloud-eu/fix/fix-typo-in-gateway-service-docu
fix: fix typo in gateway service documentation
2026-02-12 16:24:48 +01:00
Thomas Schweiger
2f7422538b fix: fix typo in gateway service documentation 2026-02-12 15:43:00 +01:00
opencloudeu
d14ae65eba [tx] updated from transifex 2026-02-12 00:16:05 +00:00
André Duffeck
ae3582afa3 Bump reva 2026-02-11 10:05:53 +01:00
dependabot[bot]
99aba9cfa1 build(deps): bump github.com/gabriel-vasile/mimetype
Bumps [github.com/gabriel-vasile/mimetype](https://github.com/gabriel-vasile/mimetype) from 1.4.12 to 1.4.13.
- [Release notes](https://github.com/gabriel-vasile/mimetype/releases)
- [Commits](https://github.com/gabriel-vasile/mimetype/compare/v1.4.12...v1.4.13)

---
updated-dependencies:
- dependency-name: github.com/gabriel-vasile/mimetype
  dependency-version: 1.4.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-11 09:25:13 +01:00
dependabot[bot]
0cf2d8b785 build(deps): bump go.opentelemetry.io/otel/exporters/stdout/stdouttrace
Bumps [go.opentelemetry.io/otel/exporters/stdout/stdouttrace](https://github.com/open-telemetry/opentelemetry-go) from 1.39.0 to 1.40.0.
- [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases)
- [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.39.0...v1.40.0)

---
updated-dependencies:
- dependency-name: go.opentelemetry.io/otel/exporters/stdout/stdouttrace
  dependency-version: 1.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-11 09:22:59 +01:00
opencloudeu
1c80721aff [tx] updated from transifex 2026-02-11 00:15:55 +00:00
Christian Richter
63a0458307 vendor mod tidy
Signed-off-by: Christian Richter <c.richter@opencloud.eu>

 Conflicts:
	go.sum
	vendor/modules.txt
2026-02-10 10:45:09 +01:00
Christian Richter
6f7160556f fix tests
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2026-02-10 10:45:09 +01:00
Christian Richter
7d5d8f3484 adapt graph service
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
Co-authored-by: Ralf Haferkamp <r.haferkamp@opencloud.eu>
2026-02-10 10:45:09 +01:00
Christian Richter
f24041725b Bump traefik to 3.6.7 & adapt initilize_users.go & bump librgraph-api-go
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
Co-authored-by: Ralf Haferkamp <r.haferkamp@opencloud.eu>

# Conflicts:
#	go.mod
2026-02-10 10:45:09 +01:00
Christian Richter
5877bfa8a2 initial skel for external tenant id
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2026-02-10 10:45:09 +01:00
Artur Neumann
13ae67b02c Merge pull request #2257 from opencloud-eu/checkVersionPlaceholderReadyReleaseGo
ci: check version placeholder in release PR
2026-02-10 14:52:26 +05:45
Viktor Scharf
464c528634 update reva after merge #514 (#2309) 2026-02-10 09:12:41 +01:00
Viktor Scharf
564805bf94 fix: make file urls (#2304) 2026-02-09 14:31:58 +01:00
Ralf Haferkamp
c33850f213 Reapply "adapt test for #514 (#2255)" (#2305)
This reverts commit f21207ed96.
2026-02-09 14:23:24 +01:00
VicDeo
ab9c4d8f23 Sanitize web config only once 2026-02-09 14:09:33 +01:00
dependabot[bot]
8c725823f7 build(deps): bump github.com/go-chi/chi/v5 from 5.2.4 to 5.2.5
Bumps [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) from 5.2.4 to 5.2.5.
- [Release notes](https://github.com/go-chi/chi/releases)
- [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-chi/chi/compare/v5.2.4...v5.2.5)

---
updated-dependencies:
- dependency-name: github.com/go-chi/chi/v5
  dependency-version: 5.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-09 09:05:12 +01:00
Artur Neumann
be5d504b97 ci: check version placeholder in release PR 2026-02-03 15:42:34 +05:45
174 changed files with 5305 additions and 5125 deletions

View File

@@ -1,4 +1,4 @@
# The test runner source for UI tests
WEB_COMMITID=980964ccafe81cba6742cead151ac2d61408dae3
WEB_COMMITID=05cf6c25e32aeedf0901fcd5e6d43f7646310ef2
WEB_BRANCH=main

View File

@@ -497,7 +497,8 @@ def main(ctx):
is_release_pr = (ctx.build.event == "pull_request" and ctx.build.sender == "openclouders" and "🎉 release" in ctx.build.title.lower())
if is_release_pr:
return licenseCheck(ctx)
return checkVersionPlaceholder() + \
licenseCheck(ctx)
build_release_helpers = \
readyReleaseGo()
@@ -523,7 +524,6 @@ def main(ctx):
testPipelines(ctx)
build_release_pipelines = \
checkVersionPlaceholder() + \
dockerReleases(ctx) + \
binaryReleases(ctx)
@@ -1835,7 +1835,7 @@ def checkVersionPlaceholder():
},
],
"when": [
event["tag"],
event["pull_request"],
],
}]

View File

@@ -1,5 +1,34 @@
# Changelog
## [5.1.0](https://github.com/opencloud-eu/opencloud/releases/tag/v5.1.0) - 2026-02-16
### ❤️ Thanks to all contributors! ❤️
@ScharfViktor, @VicDeo, @aduffeck, @dragonchaser, @individual-it, @kulmann, @micbar, @rhafer, @schweigisito
### 🐛 Bug Fixes
- [full-ci] Bump reva v2.42.4 [[#2348](https://github.com/opencloud-eu/opencloud/pull/2348)]
- fix: fix typo in variable description [[#2333](https://github.com/opencloud-eu/opencloud/pull/2333)]
- fix: include sessionID in sse logout event [[#2327](https://github.com/opencloud-eu/opencloud/pull/2327)]
- fix: fix typo in gateway service documentation [[#2332](https://github.com/opencloud-eu/opencloud/pull/2332)]
- Sanitize web config only once [[#2286](https://github.com/opencloud-eu/opencloud/pull/2286)]
### 📈 Enhancement
- external tenant id [[#2258](https://github.com/opencloud-eu/opencloud/pull/2258)]
### 📚 Documentation
- fix: make file urls [[#2304](https://github.com/opencloud-eu/opencloud/pull/2304)]
### 📦️ Dependencies
- build(deps): bump github.com/gabriel-vasile/mimetype from 1.4.12 to 1.4.13 [[#2316](https://github.com/opencloud-eu/opencloud/pull/2316)]
- build(deps): bump go.opentelemetry.io/otel/exporters/stdout/stdouttrace from 1.39.0 to 1.40.0 [[#2279](https://github.com/opencloud-eu/opencloud/pull/2279)]
- update reva after merge #514 [[#2309](https://github.com/opencloud-eu/opencloud/pull/2309)]
- build(deps): bump github.com/go-chi/chi/v5 from 5.2.4 to 5.2.5 [[#2278](https://github.com/opencloud-eu/opencloud/pull/2278)]
## [5.0.2](https://github.com/opencloud-eu/opencloud/releases/tag/v5.0.2) - 2026-02-05
### ❤️ Thanks to all contributors! ❤️

View File

@@ -83,7 +83,7 @@ help:
@echo "Please use 'make <target>' where <target> is one of the following:"
@echo
@echo -e "${GREEN}Testing with test suite natively installed:${RESET}\n"
@echo -e "${PURPLE}\tdocs: https://opencloud.dev/opencloud/development/testing/#testing-with-test-suite-natively-installed${RESET}\n"
@echo -e "${PURPLE}\ttests: https://github.com/opencloud-eu/opencloud/blob/main/tests/README.md#running-test-suite-in-local-environment${RESET}\n"
@echo -e "\tmake test-acceptance-api\t\t${BLUE}run API acceptance tests${RESET}"
@echo -e "\tmake clean-tests\t\t\t${BLUE}delete API tests framework dependencies${RESET}"
@echo
@@ -92,17 +92,11 @@ help:
@echo -e "${RED}You also should have a look at other available Makefiles:${RESET}"
@echo
@echo -e "${GREEN}opencloud:${RESET}\n"
@echo -e "${PURPLE}\tdocs: https://opencloud.dev/opencloud/development/build/${RESET}\n"
@echo -e "${PURPLE}\tdocs: https://github.com/opencloud-eu/opencloud/blob/main/README.md#build-opencloud${RESET}\n"
@echo -e "\tsee ./opencloud/Makefile"
@echo -e "\tor run ${YELLOW}make -C opencloud help${RESET}"
@echo
@echo -e "${GREEN}Documentation:${RESET}\n"
@echo -e "${PURPLE}\tdocs: https://opencloud.dev/opencloud/development/build-docs/${RESET}\n"
@echo -e "\tsee ./docs/Makefile"
@echo -e "\tor run ${YELLOW}make -C docs help${RESET}"
@echo
@echo -e "${GREEN}Testing with test suite in docker:${RESET}\n"
@echo -e "${PURPLE}\tdocs: https://opencloud.dev/opencloud/development/testing/#testing-with-test-suite-in-docker${RESET}\n"
@echo -e "${PURPLE}\ttests: https://github.com/opencloud-eu/opencloud/blob/main/tests/README.md#running-test-suite-in-docker${RESET}\n"
@echo -e "\tsee ./tests/acceptance/docker/Makefile"
@echo -e "\tor run ${YELLOW}make -C tests/acceptance/docker help${RESET}"
@echo

View File

@@ -24,6 +24,7 @@ var demoTenants = []tenantWithUsers{
{
tenant: libregraph.EducationSchool{
DisplayName: libregraph.PtrString("Famous Coders"),
ExternalId: libregraph.PtrString("famouscodersExternalID"),
},
users: []libregraph.EducationUser{
{
@@ -41,6 +42,7 @@ var demoTenants = []tenantWithUsers{
{
tenant: libregraph.EducationSchool{
DisplayName: libregraph.PtrString("Scientists"),
ExternalId: libregraph.PtrString("scientistsExternalID"),
},
users: []libregraph.EducationUser{
{

View File

@@ -9,7 +9,7 @@ services:
- "traefik.http.services.opencloud.loadbalancer.server.port=9200"
- "traefik.http.routers.opencloud.${TRAEFIK_SERVICES_TLS_CONFIG}"
traefik:
image: traefik:v3.3.1
image: traefik:v3.6.7
# release notes: https://github.com/traefik/traefik/releases
networks:
opencloud-net:

View File

@@ -42,4 +42,4 @@ olcObjectClasses: ( openCloudOid:1.2.5 NAME 'openCloudEducationSchool'
DESC 'OpenCloud education school objectclass'
SUP openCloudObject
AUXILIARY
MAY ( openCloudEducationSchoolNumber $ openCloudEducationSchoolTerminationTimestamp ) )
MAY ( openCloudEducationSchoolNumber $ openCloudEducationSchoolTerminationTimestamp $ openCloudEducationExternalId) )

32
go.mod
View File

@@ -18,9 +18,9 @@ require (
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/gabriel-vasile/mimetype v1.4.12
github.com/gabriel-vasile/mimetype v1.4.13
github.com/ggwhite/go-masker v1.1.0
github.com/go-chi/chi/v5 v5.2.4
github.com/go-chi/chi/v5 v5.2.5
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.12
@@ -64,8 +64,8 @@ require (
github.com/onsi/gomega v1.39.1
github.com/open-policy-agent/opa v1.12.3
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.42.3
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260204102724-10bcda1b3068
github.com/opencloud-eu/reva/v2 v2.42.4
github.com/opensearch-project/opensearch-go/v4 v4.6.0
github.com/orcaman/concurrent-map v1.0.0
github.com/pkg/errors v0.9.1
@@ -95,12 +95,12 @@ require (
github.com/xhit/go-simple-mail/v2 v2.16.0
go-micro.dev/v4 v4.11.0
go.etcd.io/bbolt v1.4.3
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0
go.opentelemetry.io/contrib/zpages v0.64.0
go.opentelemetry.io/otel v1.40.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0
go.opentelemetry.io/otel/sdk v1.40.0
go.opentelemetry.io/otel/trace v1.40.0
golang.org/x/crypto v0.47.0
@@ -130,7 +130,7 @@ require (
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.5 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect
github.com/agnivade/levenshtein v1.2.1 // indirect
github.com/ajg/form v1.5.1 // indirect
@@ -181,7 +181,7 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/crewjam/httperr v0.2.0 // indirect
github.com/crewjam/saml v0.4.14 // indirect
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deckarep/golang-set v1.8.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
@@ -208,7 +208,7 @@ require (
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
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-git/go-git/v5 v5.16.5 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-kit/log v0.2.1 // indirect
@@ -287,7 +287,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.33 // indirect
github.com/maxymania/go-system v0.0.0-20170110133659-647cc364bf0b // indirect
github.com/mendsley/gojwk v0.0.0-20141217222730-4d5ec6e58103 // indirect
github.com/miekg/dns v1.1.57 // indirect
github.com/miekg/dns v1.1.68 // indirect
github.com/mileusna/useragent v1.3.5 // indirect
github.com/minio/crc64nvme v1.1.1 // indirect
github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect
@@ -328,9 +328,9 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/pquerna/cachecontrol v0.2.0 // indirect
github.com/prometheus/alertmanager v0.30.1 // indirect
github.com/prometheus/alertmanager v0.31.1 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.67.4 // indirect
github.com/prometheus/common v0.67.5 // 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-20250401214520-65e299d6c5c9 // indirect
@@ -339,9 +339,9 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/samber/lo v1.51.0 // indirect
github.com/samber/slog-common v0.19.0 // indirect
github.com/samber/slog-zerolog/v2 v2.9.0 // indirect
github.com/samber/lo v1.52.0 // indirect
github.com/samber/slog-common v0.20.0 // indirect
github.com/samber/slog-zerolog/v2 v2.9.1 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/segmentio/kafka-go v0.4.50 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
@@ -353,7 +353,7 @@ require (
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/skeema/knownhosts v1.3.1 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
github.com/spf13/cast v1.10.0 // indirect

72
go.sum
View File

@@ -91,8 +91,8 @@ github.com/Nerzal/gocloak/v13 v13.9.0 h1:YWsJsdM5b0yhM2Ba3MLydiOlujkBry4TtdzfIzS
github.com/Nerzal/gocloak/v13 v13.9.0/go.mod h1:YYuDcXZ7K2zKECyVP7pPqjKxx2AzYSpKDj8d6GuyM10=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@@ -272,8 +272,8 @@ github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1n
github.com/cs3org/go-cs3apis v0.0.0-20250908152307-4ca807afe54e h1:fC/BWMVWNFlSbzvSp2xTaH0qpJiq7ScRrOsCzpgi1xI=
github.com/cs3org/go-cs3apis v0.0.0-20250908152307-4ca807afe54e/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -327,8 +327,8 @@ github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0o
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc h1:6IxmRbXV8WXVkcYcTzkU219A3UZeNMX/e6X2sve1wXA=
github.com/egirna/icap v0.0.0-20181108071049-d5ee18bd70bc/go.mod h1:FdVN2WHg7zOHhJ7kZQdDorfFhIfqZaHttjAzDDvAXHE=
github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
github.com/elazarl/goproxy v1.4.0/go.mod h1:X/5W/t+gzDyLfHW4DrMdpjqYjpXsURlBt9lpBDxZZZQ=
github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o=
github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/emvi/iso-639-1 v1.1.1 h1:7jrl1Sqw9ZYWmCOaH+cpQotLbGr/khwlLPXlBvE8WXU=
@@ -358,8 +358,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
@@ -381,8 +381,8 @@ github.com/go-asn1-ber/asn1-ber v1.4.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4=
github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
@@ -393,8 +393,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw5s=
github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -849,8 +849,8 @@ github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3v
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=
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA=
github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
github.com/mileusna/useragent v1.3.5 h1:SJM5NzBmh/hO+4LGeATKpaEX9+b4vcGg2qXGLiNGDws=
github.com/mileusna/useragent v1.3.5/go.mod h1:3d8TOmwL/5I8pJjyVDteHtgDGcefrFUX4ccGOMKNYYc=
github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI=
@@ -967,10 +967,10 @@ github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+l
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI=
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9 h1:dIftlX03Bzfbujhp9B54FbgER0VBDWJi/w8RBxJlzxU=
github.com/opencloud-eu/inotifywaitgo v0.0.0-20251111171128-a390bae3c5e9/go.mod h1:JWyDC6H+5oZRdUJUgKuaye+8Ph5hEs6HVzVoPKzWSGI=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76 h1:vD/EdfDUrv4omSFjrinT8Mvf+8D7f9g4vgQ2oiDrVUI=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20250724122329-41ba6b191e76/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
github.com/opencloud-eu/reva/v2 v2.42.3 h1:A9v52jgIY6+UHnj5xuC4HVn/w8X4sVSibyvWsQ/50mk=
github.com/opencloud-eu/reva/v2 v2.42.3/go.mod h1:LrMYMcSrH9nvTywiE1ry0i2w38yGLFKUPYxWjvKulBo=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260204102724-10bcda1b3068 h1:i09YEVYbiUBMhxyak93REn/ZJOTRhAN4I3PXp2nCXgU=
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260204102724-10bcda1b3068/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
github.com/opencloud-eu/reva/v2 v2.42.4 h1:e1jNg5IGtRul7JUnrqMIa4lYFjAfbGzNZaSSJL/4h5U=
github.com/opencloud-eu/reva/v2 v2.42.4/go.mod h1:uYGfaWGUxQOKnLSbu8tFUHBz2AFib263VGfyapuxILA=
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=
@@ -1022,8 +1022,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om
github.com/pquerna/cachecontrol v0.2.0 h1:vBXSNuE5MYP9IJ5kjsdo8uq+w41jSPgvba2DEnkRx9k=
github.com/pquerna/cachecontrol v0.2.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI=
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/alertmanager v0.30.1 h1:427prmCHuy1rMmV7fl/TVQFh5A/78XQ/Mp+TsswZNGM=
github.com/prometheus/alertmanager v0.30.1/go.mod h1:93PBumcTLr/gNtNtM0m7BcCffbvYP5bKuLBWiOnISaA=
github.com/prometheus/alertmanager v0.31.1 h1:eAmIC42lzbWslHkMt693T36qdxfyZULswiHr681YS3Q=
github.com/prometheus/alertmanager v0.31.1/go.mod h1:zWPQwhbLt2ybee8rL921UONeQ59Oncash+m/hGP17tU=
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
@@ -1056,8 +1056,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc=
github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI=
github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4=
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
github.com/prometheus/procfs v0.0.0-20170703101242-e645f4e5aaa8/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -1103,12 +1103,12 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
github.com/sacloud/libsacloud v1.36.2/go.mod h1:P7YAOVmnIn3DKHqCZcUKYUXmSwGBm3yS7IBEjKVSrjg=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/samber/lo v1.51.0 h1:kysRYLbHy/MB7kQZf5DSN50JHmMsNEdeY24VzJFu7wI=
github.com/samber/lo v1.51.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/samber/slog-common v0.19.0 h1:fNcZb8B2uOLooeYwFpAlKjkQTUafdjfqKcwcC89G9YI=
github.com/samber/slog-common v0.19.0/go.mod h1:dTz+YOU76aH007YUU0DffsXNsGFQRQllPQh9XyNoA3M=
github.com/samber/slog-zerolog/v2 v2.9.0 h1:6LkOabJmZdNLaUWkTC3IVVA+dq7b/V0FM6lz6/7+THI=
github.com/samber/slog-zerolog/v2 v2.9.0/go.mod h1:gnQW9VnCfM34v2pRMUIGMsZOVbYLqY/v0Wxu6atSVGc=
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/samber/slog-common v0.20.0 h1:WaLnm/aCvBJSk5nR5aXZTFBaV0B47A+AEaEOiZDeUnc=
github.com/samber/slog-common v0.20.0/go.mod h1:+Ozat1jgnnE59UAlmNX1IF3IByHsODnnwf9jUcBZ+m8=
github.com/samber/slog-zerolog/v2 v2.9.1 h1:RMOq8XqzfuGx1X0TEIlS9OXbbFmqLY2/wJppghz66YY=
github.com/samber/slog-zerolog/v2 v2.9.1/go.mod h1:DQYYve14WgCRN/XnKeHl4266jXK0DgYkYXkfZ4Fp98k=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20210127161313-bd30bebeac4f/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
@@ -1142,8 +1142,8 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
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/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
@@ -1311,8 +1311,8 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ=
go.opentelemetry.io/contrib/zpages v0.64.0 h1:iMybqKVR8AHHxFX4DuEWJ9dY75+9E7+IPwUK3Ll7NxM=
@@ -1323,10 +1323,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQg
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs=
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/exporters/stdout/stdouttrace v1.39.0 h1:8UPA4IbVZxpsD76ihGOQiFml99GPAEZLohDXvqHdi6U=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0/go.mod h1:MZ1T/+51uIVKlRzGw1Fo46KEWThjlCBZKl2LzY5nv4g=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0 h1:MzfofMZN8ulNqobCmCAVbqVL5syHw+eB2qPRkCMA/fQ=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.40.0/go.mod h1:E73G9UFtKRXrxhBsHtG00TB5WxX57lpsQzogDkqBTz8=
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=

View File

@@ -34,7 +34,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 = "5.0.2+dev"
LatestTag = "5.1.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: 2026-01-25 00:11+0000\n"
"POT-Creation-Date: 2026-02-14 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"

View File

@@ -4,16 +4,16 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# ii kaka, 2025
# iikaka88, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-27 00:11+0000\n"
"POT-Creation-Date: 2026-02-16 00:16+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: ii kaka, 2025\n"
"Last-Translator: iikaka88, 2025\n"
"Language-Team: Japanese (https://app.transifex.com/opencloud-eu/teams/204053/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Mário Machado, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"

View File

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

View File

@@ -16,4 +16,5 @@ type FileEvent struct {
type BackchannelLogout struct {
UserID string `json:"userid"`
Timestamp string `json:"timestamp"`
SessionID string `json:"sessionid"`
}

View File

@@ -300,5 +300,6 @@ func backchannelLogoutEvent(e events.BackchannelLogout) (string, []string, Backc
return "backchannel-logout", []string{e.Executant.GetOpaqueId()}, BackchannelLogout{
UserID: e.Executant.GetOpaqueId(),
Timestamp: e.Timestamp.String(),
SessionID: e.SessionId,
}
}

View File

@@ -172,7 +172,7 @@ type OCDav struct {
type NameValidation struct {
InvalidChars []string `yaml:"invalid_chars" env:"OCDAV_NAME_VALIDATION_INVALID_CHARS;FRONTENT_OCDAV_NAME_VALIDATION_INVALID_CHARS" desc:"List of characters that are not allowed in file or folder names." introductionVersion:"%%NEXT%%"`
MaxLength int `yaml:"max_length" env:"OCDAV_NAME_VALIDATION_MAX_LENGTH;FRONTENT_OCDAV_NAME_VALIDATION_MAX_LENGTH" desc:"Max lenght og file or folder names." introductionVersion:"%%NEXT%%"`
MaxLength int `yaml:"max_length" env:"OCDAV_NAME_VALIDATION_MAX_LENGTH;FRONTENT_OCDAV_NAME_VALIDATION_MAX_LENGTH" desc:"Max length of file or folder names." introductionVersion:"%%NEXT%%"`
}
type CacheWarmupDrivers struct {

View File

@@ -104,7 +104,7 @@ SHARING_PUBLIC_JSONCS3_PROVIDER_ADDR="unix:/var/run/opencloud/storage-system.soc
## Storage Registry
In order to add another storage provider the CS3 storage registry that is running as part of the CS3 gateway hes to be made aware of it. The easiest cleanest way to do it is to set `GATEWAY_STORAGE_REGISTRY_CONFIG_JSON=/path/to/storages.json` and list all storage providers like this:
In order to add another storage provider the CS3 storage registry that is running as part of the CS3 gateway has to be made aware of it. The easiest and cleanest way to do it is to set `GATEWAY_STORAGE_REGISTRY_CONFIG_JSON=/path/to/storages.json` and list all storage providers like this:
```json
{
@@ -172,4 +172,4 @@ In order to add another storage provider the CS3 storage registry that is runnin
}
```
In the above replace `{storage-users-mount-uuid}` with the mount UUID that was generated for the storage-users service. You can find it in the `config.yaml` generated on by `opencloud init`. The last entry `eu.opencloud.api.storage-hello` and its `providerid` `"hello-storage-id"` are an example for in additional storage provider, in this case running `hellofs`, an example minimal storage driver.
In the above replace `{storage-users-mount-uuid}` with the mount UUID that was generated for the storage-users service. You can find it in the `config.yaml` generated on by `opencloud init`. The last entry `eu.opencloud.api.storage-hello` and its `providerid` `"hello-storage-id"` are an example for an additional storage provider, in this case running `hellofs`, an example minimal storage driver.

View File

@@ -7,8 +7,8 @@ import (
"github.com/go-ldap/ldap/v3"
"github.com/libregraph/idm/pkg/ldapdn"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
)
type educationClassAttributeMap struct {

View File

@@ -34,6 +34,7 @@ type educationConfig struct {
type schoolAttributeMap struct {
displayName string
schoolNumber string
externalId string
id string
terminationDate string
}
@@ -48,9 +49,10 @@ const (
)
var (
errNotSet = errors.New("attribute not set")
errSchoolNameExists = errorcode.New(errorcode.NameAlreadyExists, "A school with that name is already present")
errSchoolNumberExists = errorcode.New(errorcode.NameAlreadyExists, "A school with that number is already present")
errNotSet = errors.New("attribute not set")
errSchoolNameExists = errorcode.New(errorcode.NameAlreadyExists, "A school with that name is already present")
errSchoolNumberExists = errorcode.New(errorcode.NameAlreadyExists, "A school with that number is already present")
errSchoolExternalIdExists = errorcode.New(errorcode.NameAlreadyExists, "A school with that external id is already present")
)
func defaultEducationConfig() educationConfig {
@@ -105,6 +107,7 @@ func newSchoolAttributeMap() schoolAttributeMap {
return schoolAttributeMap{
displayName: "ou",
schoolNumber: "openCloudEducationSchoolNumber",
externalId: "openCloudEducationExternalId",
id: "openCloudUUID",
terminationDate: "openCloudEducationSchoolTerminationTimestamp",
}
@@ -121,11 +124,11 @@ func (i *LDAP) CreateEducationSchool(ctx context.Context, school libregraph.Educ
// Check that the school number is not already used
if school.HasSchoolNumber() {
_, err := i.getSchoolByNumber(school.GetSchoolNumber())
switch err {
case nil:
switch {
case err == nil:
logger.Debug().Err(errSchoolNumberExists).Str("schoolNumber", school.GetSchoolNumber()).Msg("duplicate school number")
return nil, errSchoolNumberExists
case ErrNotFound:
case errors.Is(err, ErrNotFound):
break
default:
logger.Error().Err(err).Str("schoolNumber", school.GetSchoolNumber()).Msg("error looking up school by number")
@@ -133,6 +136,21 @@ func (i *LDAP) CreateEducationSchool(ctx context.Context, school libregraph.Educ
}
}
// Check that the school external id is not already used
if school.HasExternalId() {
_, err := i.getSchoolByExternalId(school.GetExternalId())
switch {
case err == nil:
logger.Debug().Err(errSchoolExternalIdExists).Str("externalId", school.GetExternalId()).Msg("duplicate school external id")
return nil, errSchoolExternalIdExists
case errors.Is(err, ErrNotFound):
break
default:
logger.Error().Err(err).Str("externalId", school.GetExternalId()).Msg("error looking up school by external id")
return nil, errorcode.New(errorcode.GeneralException, "error looking up school by external id")
}
}
attributeTypeAndValue := ldap.AttributeTypeAndValue{
Type: i.educationConfig.schoolAttributeMap.displayName,
Value: school.GetDisplayName(),
@@ -147,6 +165,9 @@ func (i *LDAP) CreateEducationSchool(ctx context.Context, school libregraph.Educ
if school.HasSchoolNumber() {
ar.Attribute(i.educationConfig.schoolAttributeMap.schoolNumber, []string{school.GetSchoolNumber()})
}
if school.HasExternalId() {
ar.Attribute(i.educationConfig.schoolAttributeMap.externalId, []string{school.GetExternalId()})
}
if !i.useServerUUID {
ar.Attribute(i.educationConfig.schoolAttributeMap.id, []string{uuid.NewString()})
}
@@ -278,14 +299,14 @@ func (i *LDAP) updateSchoolProperties(ctx context.Context, dn string, currentSch
}
// UpdateEducationSchool updates the supplied school in the identity backend
func (i *LDAP) UpdateEducationSchool(ctx context.Context, numberOrID string, school libregraph.EducationSchool) (*libregraph.EducationSchool, error) {
func (i *LDAP) UpdateEducationSchool(ctx context.Context, numberOrIDOrExternalID string, school libregraph.EducationSchool) (*libregraph.EducationSchool, error) {
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("UpdateEducationSchool")
if !i.writeEnabled {
return nil, ErrReadOnly
}
e, err := i.getSchoolByNumberOrID(numberOrID)
e, err := i.getSchoolByNumberOrIDOrExternalID(numberOrIDOrExternalID)
if err != nil {
return nil, err
}
@@ -308,7 +329,7 @@ func (i *LDAP) UpdateEducationSchool(ctx context.Context, numberOrID string, sch
}
// Read back school from LDAP
e, err = i.getSchoolByNumberOrID(i.getID(e))
e, err = i.getSchoolByNumberOrIDOrExternalID(i.getID(e))
if err != nil {
return nil, err
}
@@ -322,7 +343,7 @@ func (i *LDAP) DeleteEducationSchool(ctx context.Context, id string) error {
if !i.writeEnabled {
return ErrReadOnly
}
e, err := i.getSchoolByNumberOrID(id)
e, err := i.getSchoolByNumberOrIDOrExternalID(id)
if err != nil {
return err
}
@@ -337,10 +358,10 @@ func (i *LDAP) DeleteEducationSchool(ctx context.Context, id string) error {
}
// GetEducationSchool implements the EducationBackend interface for the LDAP backend.
func (i *LDAP) GetEducationSchool(ctx context.Context, numberOrID string) (*libregraph.EducationSchool, error) {
func (i *LDAP) GetEducationSchool(ctx context.Context, numberOrIDOrExternalID string) (*libregraph.EducationSchool, error) {
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("GetEducationSchool")
e, err := i.getSchoolByNumberOrID(numberOrID)
e, err := i.getSchoolByNumberOrIDOrExternalID(numberOrIDOrExternalID)
if err != nil {
return nil, err
}
@@ -415,11 +436,11 @@ func (i *LDAP) GetEducationSchoolUsers(ctx context.Context, schoolNumberOrID str
}
// AddUsersToEducationSchool adds new members (reference by a slice of IDs) to supplied school in the identity backend.
func (i *LDAP) AddUsersToEducationSchool(ctx context.Context, schoolNumberOrID string, memberIDs []string) error {
func (i *LDAP) AddUsersToEducationSchool(ctx context.Context, schoolNumberOrIDOrExternalID string, memberIDs []string) error {
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("AddUsersToEducationSchool")
schoolEntry, err := i.getSchoolByNumberOrID(schoolNumberOrID)
schoolEntry, err := i.getSchoolByNumberOrIDOrExternalID(schoolNumberOrIDOrExternalID)
if err != nil {
return err
}
@@ -462,11 +483,11 @@ func (i *LDAP) AddUsersToEducationSchool(ctx context.Context, schoolNumberOrID s
}
// RemoveUserFromEducationSchool removes a single member (by ID) from a school
func (i *LDAP) RemoveUserFromEducationSchool(ctx context.Context, schoolNumberOrID string, memberID string) error {
func (i *LDAP) RemoveUserFromEducationSchool(ctx context.Context, schoolNumberOrIDOrExternalID string, memberID string) error {
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("RemoveUserFromEducationSchool")
schoolEntry, err := i.getSchoolByNumberOrID(schoolNumberOrID)
schoolEntry, err := i.getSchoolByNumberOrIDOrExternalID(schoolNumberOrIDOrExternalID)
if err != nil {
return err
}
@@ -521,12 +542,12 @@ func (i *LDAP) GetEducationSchoolClasses(ctx context.Context, schoolNumberOrID s
}
func (i *LDAP) getEducationSchoolEntries(
schoolNumberOrID, filter, objectClass, baseDN string,
schoolNumberOrIDOrExternalID, filter, objectClass, baseDN string,
scope int,
attributes []string,
logger log.Logger,
) ([]*ldap.Entry, error) {
schoolEntry, err := i.getSchoolByNumberOrID(schoolNumberOrID)
schoolEntry, err := i.getSchoolByNumberOrIDOrExternalID(schoolNumberOrIDOrExternalID)
if err != nil {
return nil, err
}
@@ -563,11 +584,11 @@ func (i *LDAP) getEducationSchoolEntries(
}
// AddClassesToEducationSchool adds new members (reference by a slice of IDs) to supplied school in the identity backend.
func (i *LDAP) AddClassesToEducationSchool(ctx context.Context, schoolNumberOrID string, memberIDs []string) error {
func (i *LDAP) AddClassesToEducationSchool(ctx context.Context, schoolNumberOrIDOrExternalID string, memberIDs []string) error {
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("AddClassesToEducationSchool")
schoolEntry, err := i.getSchoolByNumberOrID(schoolNumberOrID)
schoolEntry, err := i.getSchoolByNumberOrIDOrExternalID(schoolNumberOrIDOrExternalID)
if err != nil {
return err
}
@@ -610,11 +631,11 @@ func (i *LDAP) AddClassesToEducationSchool(ctx context.Context, schoolNumberOrID
}
// RemoveClassFromEducationSchool removes a single member (by ID) from a school
func (i *LDAP) RemoveClassFromEducationSchool(ctx context.Context, schoolNumberOrID string, memberID string) error {
func (i *LDAP) RemoveClassFromEducationSchool(ctx context.Context, schoolNumberOrIDOrExternalID string, memberID string) error {
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("RemoveClassFromEducationSchool")
schoolEntry, err := i.getSchoolByNumberOrID(schoolNumberOrID)
schoolEntry, err := i.getSchoolByNumberOrIDOrExternalID(schoolNumberOrIDOrExternalID)
if err != nil {
return err
}
@@ -652,14 +673,16 @@ func (i *LDAP) getSchoolByDN(dn string) (*ldap.Entry, error) {
return i.getEntryByDN(dn, i.getEducationSchoolAttrTypes(), filter)
}
func (i *LDAP) getSchoolByNumberOrID(numberOrID string) (*ldap.Entry, error) {
numberOrID = ldap.EscapeFilter(numberOrID)
func (i *LDAP) getSchoolByNumberOrIDOrExternalID(numberOrIDOrExternalID string) (*ldap.Entry, error) {
numberOrIDOrExternalID = ldap.EscapeFilter(numberOrIDOrExternalID)
filter := fmt.Sprintf(
"(|(%s=%s)(%s=%s))",
"(|(%s=%s)(%s=%s)(%s=%s))",
i.educationConfig.schoolAttributeMap.id,
numberOrID,
numberOrIDOrExternalID,
i.educationConfig.schoolAttributeMap.schoolNumber,
numberOrID,
numberOrIDOrExternalID,
i.educationConfig.schoolAttributeMap.externalId,
numberOrIDOrExternalID,
)
return i.getSchoolByFilter(filter)
}
@@ -674,6 +697,16 @@ func (i *LDAP) getSchoolByNumber(schoolNumber string) (*ldap.Entry, error) {
return i.getSchoolByFilter(filter)
}
func (i *LDAP) getSchoolByExternalId(schoolExternalId string) (*ldap.Entry, error) {
schoolExternalId = ldap.EscapeFilter(schoolExternalId)
filter := fmt.Sprintf(
"(%s=%s)",
i.educationConfig.schoolAttributeMap.externalId,
schoolExternalId,
)
return i.getSchoolByFilter(filter)
}
func (i *LDAP) getSchoolByFilter(filter string) (*ldap.Entry, error) {
filter = fmt.Sprintf("(&%s(objectClass=%s)%s)",
i.educationConfig.schoolFilter,
@@ -723,6 +756,8 @@ func (i *LDAP) createSchoolModelFromLDAP(e *ldap.Entry) *libregraph.EducationSch
id := i.getID(e)
schoolNumber := i.getSchoolNumber(e)
externalId := i.getExternalId(e)
t, err := i.getTerminationDate(e)
if err != nil && !errors.Is(err, errNotSet) {
i.logger.Error().Err(err).Str("dn", e.DN).Msg("Error reading termination date for LDAP entry")
@@ -739,6 +774,9 @@ func (i *LDAP) createSchoolModelFromLDAP(e *ldap.Entry) *libregraph.EducationSch
if schoolNumber != "" {
school.SetSchoolNumber(schoolNumber)
}
if externalId != "" {
school.SetExternalId(externalId)
}
if t != nil {
school.SetTerminationDate(*t)
}
@@ -750,6 +788,11 @@ func (i *LDAP) getSchoolNumber(e *ldap.Entry) string {
return schoolNumber
}
func (i *LDAP) getExternalId(e *ldap.Entry) string {
externalId := e.GetEqualFoldAttributeValue(i.educationConfig.schoolAttributeMap.externalId)
return externalId
}
func (i *LDAP) getID(e *ldap.Entry) string {
id := e.GetEqualFoldAttributeValue(i.educationConfig.schoolAttributeMap.id)
return id

View File

@@ -7,10 +7,10 @@ import (
"time"
"github.com/go-ldap/ldap/v3"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/opencloud-eu/opencloud/services/graph/pkg/config"
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity/mocks"
libregraph "github.com/opencloud-eu/libre-graph-api-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
@@ -45,6 +45,7 @@ var schoolEntry = ldap.NewEntry("ou=Test School",
"ou": {"Test School"},
"openCloudEducationSchoolNumber": {"0123"},
"openCloudUUID": {"abcd-defg"},
"openCloudEducationExternalId": {"abcd-defg"},
})
var schoolEntry1 = ldap.NewEntry("ou=Test School1",
@@ -52,20 +53,22 @@ var schoolEntry1 = ldap.NewEntry("ou=Test School1",
"ou": {"Test School1"},
"openCloudEducationSchoolNumber": {"0042"},
"openCloudUUID": {"hijk-defg"},
"openCloudEducationExternalId": {"hijk-defg"},
})
var schoolEntryWithTermination = ldap.NewEntry("ou=Test School",
map[string][]string{
"ou": {"Test School"},
"openCloudEducationSchoolNumber": {"0123"},
"openCloudUUID": {"abcd-defg"},
"openCloudEducationExternalId": {"abcd-defg"},
"openCloudEducationSchoolTerminationTimestamp": {"20420131120000Z"},
})
var (
filterSchoolSearchByIdExisting = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=abcd-defg)(openCloudEducationSchoolNumber=abcd-defg)))"
filterSchoolSearchByIdNonexistant = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=xxxx-xxxx)(openCloudEducationSchoolNumber=xxxx-xxxx)))"
filterSchoolSearchByNumberExisting = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=0123)(openCloudEducationSchoolNumber=0123)))"
filterSchoolSearchByNumberNonexistant = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=3210)(openCloudEducationSchoolNumber=3210)))"
filterSchoolSearchByIdExisting = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=abcd-defg)(openCloudEducationSchoolNumber=abcd-defg)(openCloudEducationExternalId=abcd-defg)))"
filterSchoolSearchByIdNonexistant = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=xxxx-xxxx)(openCloudEducationSchoolNumber=xxxx-xxxx)(openCloudEducationExternalId=xxxx-xxxx)))"
filterSchoolSearchByNumberExisting = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=0123)(openCloudEducationSchoolNumber=0123)(openCloudEducationExternalId=0123)))"
filterSchoolSearchByNumberNonexistant = "(&(objectClass=openCloudEducationSchool)(|(openCloudUUID=3210)(openCloudEducationSchoolNumber=3210)(openCloudEducationExternalId=3210)))"
)
func TestCreateEducationSchool(t *testing.T) {

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-25 00:11+0000\n"
"POT-Creation-Date: 2026-02-14 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"

View File

@@ -4,16 +4,16 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# ii kaka, 2025
# iikaka88, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-27 00:11+0000\n"
"POT-Creation-Date: 2026-02-16 00:16+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: ii kaka, 2025\n"
"Last-Translator: iikaka88, 2025\n"
"Language-Team: Japanese (https://app.transifex.com/opencloud-eu/teams/204053/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View File

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

@@ -14,7 +14,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Radoslaw Posim, 2025\n"
"Language-Team: Polish (https://app.transifex.com/opencloud-eu/teams/204053/pl/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Mário Machado, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+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: 2026-01-25 00:11+0000\n"
"POT-Creation-Date: 2026-02-14 00:15+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: 2026-01-26 00:11+0000\n"
"POT-Creation-Date: 2026-02-15 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Quan Tran, 2025\n"
"Language-Team: Vietnamese (https://app.transifex.com/opencloud-eu/teams/204053/vi/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+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: 2026-01-23 00:11+0000\n"
"POT-Creation-Date: 2026-02-12 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"

View File

@@ -4,16 +4,16 @@
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
# Translators:
# ii kaka, 2025
# iikaka88, 2025
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-27 00:11+0000\n"
"POT-Creation-Date: 2026-02-16 00:16+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: ii kaka, 2025\n"
"Last-Translator: iikaka88, 2025\n"
"Language-Team: Japanese (https://app.transifex.com/opencloud-eu/teams/204053/ja/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"

View File

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

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Mário Machado, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"

View File

@@ -12,7 +12,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+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: 2026-01-23 00:11+0000\n"
"POT-Creation-Date: 2026-02-12 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: idoet <idoet@protonmail.ch>, 2025\n"
"Language-Team: Indonesian (https://app.transifex.com/opencloud-eu/teams/204053/id/)\n"

View File

@@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Radoslaw Posim, 2025\n"
"Language-Team: Polish (https://app.transifex.com/opencloud-eu/teams/204053/pl/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Mário Machado, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-25 00:11+0000\n"
"POT-Creation-Date: 2026-02-14 00:15+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: 2026-01-25 00:11+0000\n"
"POT-Creation-Date: 2026-02-14 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Jiri Grönroos <jiri.gronroos@iki.fi>, 2025\n"
"Language-Team: Finnish (https://app.transifex.com/opencloud-eu/teams/204053/fi/)\n"

View File

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

@@ -13,7 +13,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Radoslaw Posim, 2025\n"
"Language-Team: Polish (https://app.transifex.com/opencloud-eu/teams/204053/pl/)\n"

View File

@@ -11,7 +11,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: EMAIL\n"
"POT-Creation-Date: 2026-01-22 00:11+0000\n"
"POT-Creation-Date: 2026-02-11 00:15+0000\n"
"PO-Revision-Date: 2025-01-27 10:17+0000\n"
"Last-Translator: Mário Machado, 2025\n"
"Language-Team: Portuguese (https://app.transifex.com/opencloud-eu/teams/204053/pt/)\n"

View File

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

View File

@@ -153,25 +153,30 @@ func Sanitize(cfg *config.Config) {
cfg.Web.Config.OpenIDConnect.MetadataURL = strings.TrimRight(cfg.Web.Config.OpenIDConnect.Authority, "/") + "/.well-known/openid-configuration"
}
// remove AccountEdit parent if no value is set
if cfg.Web.Config.Options.AccountEditLink.Href == "" {
if cfg.Web.Config.Options.AccountEditLink != nil &&
cfg.Web.Config.Options.AccountEditLink.Href == "" {
cfg.Web.Config.Options.AccountEditLink = nil
}
// remove Editor parent if no value is set
if !cfg.Web.Config.Options.Editor.AutosaveEnabled {
if cfg.Web.Config.Options.Editor != nil &&
!cfg.Web.Config.Options.Editor.AutosaveEnabled {
cfg.Web.Config.Options.Editor = nil
}
// remove FeedbackLink parent if no value is set
if cfg.Web.Config.Options.FeedbackLink.Href == "" &&
if cfg.Web.Config.Options.FeedbackLink != nil &&
cfg.Web.Config.Options.FeedbackLink.Href == "" &&
cfg.Web.Config.Options.FeedbackLink.AriaLabel == "" &&
cfg.Web.Config.Options.FeedbackLink.Description == "" {
cfg.Web.Config.Options.FeedbackLink = nil
}
// remove Upload parent if no value is set
if cfg.Web.Config.Options.Upload.CompanionURL == "" {
if cfg.Web.Config.Options.Upload != nil &&
cfg.Web.Config.Options.Upload.CompanionURL == "" {
cfg.Web.Config.Options.Upload = nil
}
// remove Embed parent if no value is set
if cfg.Web.Config.Options.Embed.Enabled == "" &&
if cfg.Web.Config.Options.Embed != nil &&
cfg.Web.Config.Options.Embed.Enabled == "" &&
cfg.Web.Config.Options.Embed.Target == "" &&
cfg.Web.Config.Options.Embed.MessagesOrigin == "" &&
cfg.Web.Config.Options.Embed.DelegateAuthentication &&

View File

@@ -324,13 +324,6 @@ _ocdav: api compatibility, return correct status code_
- [coreApiWebdavUploadTUS/uploadToShare.feature:376](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavUploadTUS/uploadToShare.feature#L376)
- [coreApiWebdavUploadTUS/uploadToShare.feature:377](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavUploadTUS/uploadToShare.feature#L377)
#### [Renaming resource to banned name is allowed in spaces webdav](https://github.com/owncloud/ocis/issues/3099)
- [coreApiWebdavMove/moveFile.feature:143](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L143)
- [coreApiWebdavMove/moveFolder.feature:36](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L36)
- [coreApiWebdavMove/moveFolder.feature:50](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L50)
- [coreApiWebdavMove/moveFolder.feature:64](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L64)
#### [Trying to delete other user's trashbin item returns 409 for spaces path instead of 404](https://github.com/owncloud/ocis/issues/9791)
- [coreApiTrashbin/trashbinDelete.feature:92](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiTrashbin/trashbinDelete.feature#L92)
@@ -340,9 +333,9 @@ _ocdav: api compatibility, return correct status code_
- [coreApiWebdavMove/moveFile.feature:100](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L100)
- [coreApiWebdavMove/moveFile.feature:101](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L101)
- [coreApiWebdavMove/moveFile.feature:102](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L102)
- [coreApiWebdavMove/moveFolder.feature:220](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L220)
- [coreApiWebdavMove/moveFolder.feature:221](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L221)
- [coreApiWebdavMove/moveFolder.feature:222](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L222)
- [coreApiWebdavMove/moveFolder.feature:217](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L217)
- [coreApiWebdavMove/moveFolder.feature:218](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L218)
- [coreApiWebdavMove/moveFolder.feature:219](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L219)
- [coreApiWebdavMove/moveShareOnOpencloud.feature:334](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveShareOnOpencloud.feature#L334)
- [coreApiWebdavMove/moveShareOnOpencloud.feature:337](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveShareOnOpencloud.feature#L337)
- [coreApiWebdavMove/moveShareOnOpencloud.feature:340](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveShareOnOpencloud.feature#L340)
@@ -370,24 +363,6 @@ _ocdav: api compatibility, return correct status code_
- [coreApiWebdavPreviews/previews.feature:264](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavPreviews/previews.feature#L264)
- [coreApiWebdavPreviews/previews.feature:265](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavPreviews/previews.feature#L265)
#### [Renaming a file with a slash in the filename makes the file inaccessible](https://github.com/opencloud-eu/web/issues/1893)
- [coreApiWebdavProperties/createFileFolder.feature:29](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L29)
- [coreApiWebdavProperties/createFileFolder.feature:42](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L42)
- [coreApiWebdavProperties/createFileFolder.feature:148](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L148)
- [coreApiWebdavProperties/createFileFolder.feature:160](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L160)
- [coreApiWebdavProperties/createFileFolder.feature:172](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L172)
- [coreApiWebdavMove/moveFile.feature:441](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L441)
- [coreApiWebdavMove/moveFile.feature:452](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L452)
- [coreApiWebdavMove/moveFolder.feature:164](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L164)
- [coreApiWebdavMove/moveFolder.feature:179](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L179)
- [coreApiWebdavOperations/downloadFile.feature:307](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavOperations/downloadFile.feature#L307)
- [coreApiWebdavOperations/downloadFile.feature:313](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavOperations/downloadFile.feature#L313)
- [coreApiWebdavOperations/downloadFile.feature:319](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavOperations/downloadFile.feature#L319)
### Won't fix
Not everything needs to be implemented for opencloud.

View File

@@ -324,12 +324,6 @@ _ocdav: api compatibility, return correct status code_
- [coreApiWebdavUploadTUS/uploadToShare.feature:376](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavUploadTUS/uploadToShare.feature#L376)
- [coreApiWebdavUploadTUS/uploadToShare.feature:377](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavUploadTUS/uploadToShare.feature#L377)
#### [Renaming resource to banned name is allowed in spaces webdav](https://github.com/owncloud/ocis/issues/3099)
- [coreApiWebdavMove/moveFile.feature:143](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L143)
- [coreApiWebdavMove/moveFolder.feature:36](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L36)
- [coreApiWebdavMove/moveFolder.feature:50](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L50)
- [coreApiWebdavMove/moveFolder.feature:64](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L64)
#### [Trying to delete other user's trashbin item returns 409 for spaces path instead of 404](https://github.com/owncloud/ocis/issues/9791)
@@ -340,9 +334,9 @@ _ocdav: api compatibility, return correct status code_
- [coreApiWebdavMove/moveFile.feature:100](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L100)
- [coreApiWebdavMove/moveFile.feature:101](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L101)
- [coreApiWebdavMove/moveFile.feature:102](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L102)
- [coreApiWebdavMove/moveFolder.feature:220](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L220)
- [coreApiWebdavMove/moveFolder.feature:221](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L221)
- [coreApiWebdavMove/moveFolder.feature:222](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L222)
- [coreApiWebdavMove/moveFolder.feature:217](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L217)
- [coreApiWebdavMove/moveFolder.feature:218](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L218)
- [coreApiWebdavMove/moveFolder.feature:219](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L219)
- [coreApiWebdavMove/moveShareOnOpencloud.feature:334](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveShareOnOpencloud.feature#L334)
- [coreApiWebdavMove/moveShareOnOpencloud.feature:337](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveShareOnOpencloud.feature#L337)
- [coreApiWebdavMove/moveShareOnOpencloud.feature:340](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveShareOnOpencloud.feature#L340)
@@ -371,24 +365,6 @@ _ocdav: api compatibility, return correct status code_
- [coreApiWebdavPreviews/previews.feature:265](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavPreviews/previews.feature#L265)
#### [Renaming a file with a slash in the filename makes the file inaccessible](https://github.com/opencloud-eu/web/issues/1893)
- [coreApiWebdavProperties/createFileFolder.feature:29](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L29)
- [coreApiWebdavProperties/createFileFolder.feature:42](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L42)
- [coreApiWebdavProperties/createFileFolder.feature:148](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L148)
- [coreApiWebdavProperties/createFileFolder.feature:160](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L160)
- [coreApiWebdavProperties/createFileFolder.feature:172](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavProperties/createFileFolder.feature#L172)
- [coreApiWebdavMove/moveFile.feature:441](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L441)
- [coreApiWebdavMove/moveFile.feature:452](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFile.feature#L452)
- [coreApiWebdavMove/moveFolder.feature:164](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L164)
- [coreApiWebdavMove/moveFolder.feature:179](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavMove/moveFolder.feature#L179)
- [coreApiWebdavOperations/downloadFile.feature:307](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavOperations/downloadFile.feature#L307)
- [coreApiWebdavOperations/downloadFile.feature:313](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavOperations/downloadFile.feature#L313)
- [coreApiWebdavOperations/downloadFile.feature:319](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/coreApiWebdavOperations/downloadFile.feature#L319)
### Won't fix
Not everything needs to be implemented for opencloud.

View File

@@ -134,7 +134,7 @@ Feature: move (rename) file
Scenario Outline: rename a file into an invalid filename
Given using <dav-path-version> DAV path
And user "Alice" has uploaded file "filesForUpload/textfile.txt" to "fileToRename.txt"
When user "Alice" moves file "/fileToRename.txt" to "/a\\a" using the WebDAV API
When user "Alice" moves file "/fileToRename.txt" to "/with\\backslash" using the WebDAV API
Then the HTTP status code should be "400"
Examples:
| dav-path-version |
@@ -438,7 +438,6 @@ Feature: move (rename) file
| old | "strängé .txt" | "testfile.txt" |
| old | "file,comma.txt" | "testfile.txt" |
| old | " start with space.txt" | "testfile.txt" |
| old | "testfile.txt" | "with\backslash" |
| new | "testfile.txt" | "'single'quotes.txt" |
| new | "testfile.txt" | '"double"quotes.txt' |
| new | "testfile.txt" | "strängé .txt" |
@@ -449,7 +448,6 @@ Feature: move (rename) file
| new | "strängé .txt" | "testfile.txt" |
| new | "file,comma.txt" | "testfile.txt" |
| new | " start with space.txt" | "testfile.txt" |
| new | "testfile.txt" | "with\backslash" |
| spaces | "testfile.txt" | "'single'quotes.txt" |
| spaces | "testfile.txt" | '"double"quotes.txt' |
| spaces | "testfile.txt" | "strängé .txt" |
@@ -460,7 +458,6 @@ Feature: move (rename) file
| spaces | "strängé .txt" | "testfile.txt" |
| spaces | "file,comma.txt" | "testfile.txt" |
| spaces | " start with space.txt" | "testfile.txt" |
| spaces | "testfile.txt" | "with\backslash" |
Scenario Outline: try to rename file to name having white space at the end

View File

@@ -161,7 +161,6 @@ Feature: move (rename) folder
| old | "Sample,Folder,With,Comma" | "testFolder" |
| old | " start with space" | "testFolder" |
| old | "renamed.part" | "testFolder" |
| old | "testFolder" | "with\backslash" |
| new | "testFolder" | "'single'quotes" |
| new | "testFolder" | '"double"quotes' |
| new | "testFolder" | "strängé folder" |
@@ -176,7 +175,6 @@ Feature: move (rename) folder
| new | "Sample,Folder,With,Comma" | "testFolder" |
| new | " start with space" | "testFolder" |
| new | "renamed.part" | "testFolder" |
| new | "testFolder" | "with\backslash" |
| spaces | "testFolder" | "'single'quotes" |
| spaces | "testFolder" | '"double"quotes' |
| spaces | "testFolder" | "strängé folder" |
@@ -191,7 +189,6 @@ Feature: move (rename) folder
| spaces | "Sample,Folder,With,Comma" | "testFolder" |
| spaces | " start with space" | "testFolder" |
| spaces | "renamed.part" | "testFolder" |
| spaces | "testFolder" | "with\backslash" |
Scenario Outline: try to rename folder to name having white space at the end

View File

@@ -304,18 +304,15 @@ Feature: download file
| old | "😀 🤖.txt" |
| old | "" |
| old | "C++ file.cpp" |
| old | "with\backslash" |
| old | "file #2.txt" |
| old | "file ?2.pdf" |
| new | "😀 🤖.txt" |
| new | "" |
| new | "C++ file.cpp" |
| new | "with\backslash" |
| new | "file #2.txt" |
| new | "file ?2.pdf" |
| spaces | "😀 🤖.txt" |
| spaces | "" |
| spaces | "C++ file.cpp" |
| spaces | "with\backslash" |
| spaces | "file #2.txt" |
| spaces | "file ?2.pdf" |

View File

@@ -26,7 +26,6 @@ Feature: create files and folder
| old | "Sample,comma" |
| old | "'single'" |
| old | '"double"' |
| old | "with\backslash" |
| new | "upload" |
| new | "strängé folder" |
| new | "C++ folder.cpp" |
@@ -39,7 +38,6 @@ Feature: create files and folder
| new | "'single'" |
| new | '"double"' |
| new | "" |
| new | "with\backslash" |
| spaces | "upload" |
| spaces | "strängé folder" |
| spaces | "C++ folder.cpp" |
@@ -51,7 +49,6 @@ Feature: create files and folder
| spaces | "Sample,comma" |
| spaces | "'single'" |
| spaces | '"double"' |
| spaces | "with\backslash" |
@smokeTest
Scenario Outline: get resourcetype property of a folder
@@ -145,7 +142,6 @@ Feature: create files and folder
| old | "Sample,comma.txt" |
| old | "'single'.txt" |
| old | '"double".txt' |
| old | "with\backslash" |
| new | "upload.txt" |
| new | "strängéfile.txt" |
| new | "C++ file.cpp" |
@@ -157,7 +153,6 @@ Feature: create files and folder
| new | "Sample,comma.txt" |
| new | "'single'.txt" |
| new | '"double".txt' |
| new | "with\backslash" |
| spaces | "upload.txt" |
| spaces | "strängéfile.txt" |
| spaces | "C++ file.cpp" |
@@ -169,7 +164,6 @@ Feature: create files and folder
| spaces | "Sample,comma.txt" |
| spaces | "'single'.txt" |
| spaces | '"double".txt' |
| spaces | "with\backslash" |
@issue-10339 @issue-9568
Scenario Outline: try to create file with '.', '..' and 'empty'
@@ -208,10 +202,32 @@ Feature: create files and folder
| new | | 400 |
| spaces | /. | 400 |
| spaces | /.. | 405 |
| spaces | /../lorem | 404 |
| spaces | /../lorem | 400 |
| spaces | | 400 |
Scenario Outline: try to create folder with backslash
Given using <dav-path-version> DAV path
When user "Alice" creates folder "<folder-name>" using the WebDAV API
Then the HTTP status code should be "400"
Examples:
| dav-path-version | folder-name |
| old | with\backslash |
| new | with\backslash |
| spaces | with\backslash |
Scenario Outline: try to create file with backslash
Given using <dav-path-version> DAV path
When user "Alice" uploads file with content "some text" to "<file-name>" using the WebDAV API
Then the HTTP status code should be "400"
Examples:
| dav-path-version | file-name |
| old | with\backslash |
| new | with\backslash |
| spaces | with\backslash |
Scenario Outline: create a file with dots in the name
Given using <dav-path-version> DAV path
And user "Alice" uploads file with content "some text" to "<file-name>" using the WebDAV API

View File

@@ -6,6 +6,7 @@
package errors // import "github.com/ProtonMail/go-crypto/openpgp/errors"
import (
"fmt"
"strconv"
)
@@ -178,3 +179,22 @@ type ErrMalformedMessage string
func (dke ErrMalformedMessage) Error() string {
return "openpgp: malformed message " + string(dke)
}
// ErrEncryptionKeySelection is returned if encryption key selection fails (v2 API).
type ErrEncryptionKeySelection struct {
PrimaryKeyId string
PrimaryKeyErr error
EncSelectionKeyId *string
EncSelectionErr error
}
func (eks ErrEncryptionKeySelection) Error() string {
prefix := fmt.Sprintf("openpgp: key selection for primary key %s:", eks.PrimaryKeyId)
if eks.PrimaryKeyErr != nil {
return fmt.Sprintf("%s invalid primary key: %s", prefix, eks.PrimaryKeyErr)
}
if eks.EncSelectionKeyId != nil {
return fmt.Sprintf("%s invalid encryption key %s: %s", prefix, *eks.EncSelectionKeyId, eks.EncSelectionErr)
}
return fmt.Sprintf("%s no encryption key: %s", prefix, eks.EncSelectionErr)
}

View File

@@ -173,6 +173,11 @@ type Config struct {
// weaknesses in the hash algo, potentially hindering e.g. some chosen-prefix attacks.
// The default behavior, when the config or flag is nil, is to enable the feature.
NonDeterministicSignaturesViaNotation *bool
// InsecureAllowAllKeyFlagsWhenMissing determines how a key without valid key flags is handled.
// When set to true, a key without flags is treated as if all flags are enabled.
// This behavior is consistent with GPG.
InsecureAllowAllKeyFlagsWhenMissing bool
}
func (c *Config) Random() io.Reader {
@@ -403,6 +408,13 @@ func (c *Config) RandomizeSignaturesViaNotation() bool {
return *c.NonDeterministicSignaturesViaNotation
}
func (c *Config) AllowAllKeyFlagsWhenMissing() bool {
if c == nil {
return false
}
return c.InsecureAllowAllKeyFlagsWhenMissing
}
// BoolPointer is a helper function to set a boolean pointer in the Config.
// e.g., config.CheckPacketSequence = BoolPointer(true)
func BoolPointer(value bool) *bool {

View File

@@ -1048,12 +1048,17 @@ func (pk *PublicKey) VerifyDirectKeySignature(sig *Signature) (err error) {
// KeyIdString returns the public key's fingerprint in capital hex
// (e.g. "6C7EE1B8621CC013").
func (pk *PublicKey) KeyIdString() string {
return fmt.Sprintf("%X", pk.Fingerprint[12:20])
return fmt.Sprintf("%016X", pk.KeyId)
}
// KeyIdShortString returns the short form of public key's fingerprint
// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
// This function will return the full key id for v5 and v6 keys
// since the short key id is undefined for them.
func (pk *PublicKey) KeyIdShortString() string {
if pk.Version >= 5 {
return pk.KeyIdString()
}
return fmt.Sprintf("%X", pk.Fingerprint[16:20])
}

View File

@@ -1288,7 +1288,9 @@ func (sig *Signature) buildSubpackets(issuer PublicKey) (subpackets []outputSubp
if sig.IssuerKeyId != nil && sig.Version == 4 {
keyId := make([]byte, 8)
binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, true, keyId})
// Note: making this critical breaks RPM <=4.16.
// See: https://github.com/ProtonMail/go-crypto/issues/263
subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
}
// Notation Data
for _, notation := range sig.Notations {

View File

@@ -6,6 +6,51 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ##
## [0.4.1] - 2025-01-28 ##
### Fixed ###
- The restrictions added for `root` paths passed to `SecureJoin` in 0.4.0 was
found to be too strict and caused some regressions when folks tried to
update, so this restriction has been relaxed to only return an error if the
path contains a `..` component. We still recommend users use `filepath.Clean`
(and even `filepath.EvalSymlinks`) on the `root` path they are using, but at
least you will no longer be punished for "trivial" unclean paths.
## [0.4.0] - 2025-01-13 ##
### Breaking ####
- `SecureJoin(VFS)` will now return an error if the provided `root` is not a
`filepath.Clean`'d path.
While it is ultimately the responsibility of the caller to ensure the root is
a safe path to use, passing a path like `/symlink/..` as a root would result
in the `SecureJoin`'d path being placed in `/` even though `/symlink/..`
might be a different directory, and so we should more strongly discourage
such usage.
All major users of `securejoin.SecureJoin` already ensure that the paths they
provide are safe (and this is ultimately a question of user error), but
removing this foot-gun is probably a good idea. Of course, this is
necessarily a breaking API change (though we expect no real users to be
affected by it).
Thanks to [Erik Sjölund](https://github.com/eriksjolund), who initially
reported this issue as a possible security issue.
- `MkdirAll` and `MkdirHandle` now take an `os.FileMode`-style mode argument
instead of a raw `unix.S_*`-style mode argument, which may cause compile-time
type errors depending on how you use `filepath-securejoin`. For most users,
there will be no change in behaviour aside from the type change (as the
bottom `0o777` bits are the same in both formats, and most users are probably
only using those bits).
However, if you were using `unix.S_ISVTX` to set the sticky bit with
`MkdirAll(Handle)` you will need to switch to `os.ModeSticky` otherwise you
will get a runtime error with this update. In addition, the error message you
will get from passing `unix.S_ISUID` and `unix.S_ISGID` will be different as
they are treated as invalid bits now (note that previously passing said bits
was also an error).
## [0.3.6] - 2024-12-17 ##
### Compatibility ###
@@ -193,7 +238,9 @@ This is our first release of `github.com/cyphar/filepath-securejoin`,
containing a full implementation with a coverage of 93.5% (the only missing
cases are the error cases, which are hard to mocktest at the moment).
[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.6...HEAD
[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.1...HEAD
[0.4.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.6...v0.4.0
[0.3.6]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.5...v0.3.6
[0.3.5]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.4...v0.3.5
[0.3.4]: https://github.com/cyphar/filepath-securejoin/compare/v0.3.3...v0.3.4

View File

@@ -1 +1 @@
0.3.6
0.4.1

View File

@@ -1,5 +1,5 @@
// Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved.
// Copyright (C) 2017-2024 SUSE LLC. All rights reserved.
// Copyright (C) 2017-2025 SUSE LLC. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -24,6 +24,31 @@ func IsNotExist(err error) bool {
return errors.Is(err, os.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) || errors.Is(err, syscall.ENOENT)
}
// errUnsafeRoot is returned if the user provides SecureJoinVFS with a path
// that contains ".." components.
var errUnsafeRoot = errors.New("root path provided to SecureJoin contains '..' components")
// stripVolume just gets rid of the Windows volume included in a path. Based on
// some godbolt tests, the Go compiler is smart enough to make this a no-op on
// Linux.
func stripVolume(path string) string {
return path[len(filepath.VolumeName(path)):]
}
// hasDotDot checks if the path contains ".." components in a platform-agnostic
// way.
func hasDotDot(path string) bool {
// If we are on Windows, strip any volume letters. It turns out that
// C:..\foo may (or may not) be a valid pathname and we need to handle that
// leading "..".
path = stripVolume(path)
// Look for "/../" in the path, but we need to handle leading and trailing
// ".."s by adding separators. Doing this with filepath.Separator is ugly
// so just convert to Unix-style "/" first.
path = filepath.ToSlash(path)
return strings.Contains("/"+path+"/", "/../")
}
// SecureJoinVFS joins the two given path components (similar to [filepath.Join]) except
// that the returned path is guaranteed to be scoped inside the provided root
// path (when evaluated). Any symbolic links in the path are evaluated with the
@@ -46,7 +71,22 @@ func IsNotExist(err error) bool {
// provided via direct input or when evaluating symlinks. Therefore:
//
// "C:\Temp" + "D:\path\to\file.txt" results in "C:\Temp\path\to\file.txt"
//
// If the provided root is not [filepath.Clean] then an error will be returned,
// as such root paths are bordering on somewhat unsafe and using such paths is
// not best practice. We also strongly suggest that any root path is first
// fully resolved using [filepath.EvalSymlinks] or otherwise constructed to
// avoid containing symlink components. Of course, the root also *must not* be
// attacker-controlled.
func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) {
// The root path must not contain ".." components, otherwise when we join
// the subpath we will end up with a weird path. We could work around this
// in other ways but users shouldn't be giving us non-lexical root paths in
// the first place.
if hasDotDot(root) {
return "", errUnsafeRoot
}
// Use the os.* VFS implementation if none was specified.
if vfs == nil {
vfs = osVFS{}
@@ -59,9 +99,10 @@ func SecureJoinVFS(root, unsafePath string, vfs VFS) (string, error) {
linksWalked int
)
for remainingPath != "" {
if v := filepath.VolumeName(remainingPath); v != "" {
remainingPath = remainingPath[len(v):]
}
// On Windows, if we managed to end up at a path referencing a volume,
// drop the volume to make sure we don't end up with broken paths or
// escaping the root volume.
remainingPath = stripVolume(remainingPath)
// Get the next path component.
var part string

View File

@@ -21,6 +21,33 @@ var (
errPossibleAttack = errors.New("possible attack detected")
)
// modePermExt is like os.ModePerm except that it also includes the set[ug]id
// and sticky bits.
const modePermExt = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky
//nolint:cyclop // this function needs to handle a lot of cases
func toUnixMode(mode os.FileMode) (uint32, error) {
sysMode := uint32(mode.Perm())
if mode&os.ModeSetuid != 0 {
sysMode |= unix.S_ISUID
}
if mode&os.ModeSetgid != 0 {
sysMode |= unix.S_ISGID
}
if mode&os.ModeSticky != 0 {
sysMode |= unix.S_ISVTX
}
// We don't allow file type bits.
if mode&os.ModeType != 0 {
return 0, fmt.Errorf("%w %+.3o (%s): type bits not permitted", errInvalidMode, mode, mode)
}
// We don't allow other unknown modes.
if mode&^modePermExt != 0 || sysMode&unix.S_IFMT != 0 {
return 0, fmt.Errorf("%w %+.3o (%s): unknown mode bits", errInvalidMode, mode, mode)
}
return sysMode, nil
}
// MkdirAllHandle is equivalent to [MkdirAll], except that it is safer to use
// in two respects:
//
@@ -39,17 +66,17 @@ var (
// a brand new lookup of unsafePath (such as with [SecureJoin] or openat2) after
// doing [MkdirAll]. If you intend to open the directory after creating it, you
// should use MkdirAllHandle.
func MkdirAllHandle(root *os.File, unsafePath string, mode int) (_ *os.File, Err error) {
// Make sure there are no os.FileMode bits set.
if mode&^0o7777 != 0 {
return nil, fmt.Errorf("%w for mkdir 0o%.3o", errInvalidMode, mode)
func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.File, Err error) {
unixMode, err := toUnixMode(mode)
if err != nil {
return nil, err
}
// On Linux, mkdirat(2) (and os.Mkdir) silently ignore the suid and sgid
// bits. We could also silently ignore them but since we have very few
// users it seems more prudent to return an error so users notice that
// these bits will not be set.
if mode&^0o1777 != 0 {
return nil, fmt.Errorf("%w for mkdir 0o%.3o: suid and sgid are ignored by mkdir", errInvalidMode, mode)
if unixMode&^0o1777 != 0 {
return nil, fmt.Errorf("%w for mkdir %+.3o: suid and sgid are ignored by mkdir", errInvalidMode, mode)
}
// Try to open as much of the path as possible.
@@ -104,9 +131,6 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode int) (_ *os.File, Err
return nil, fmt.Errorf("%w: yet-to-be-created path %q contains '..' components", unix.ENOENT, remainingPath)
}
// Make sure the mode doesn't have any type bits.
mode &^= unix.S_IFMT
// Create the remaining components.
for _, part := range remainingParts {
switch part {
@@ -123,7 +147,7 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode int) (_ *os.File, Err
// directory at the same time as us. In that case, just continue on as
// if we created it (if the created inode is not a directory, the
// following open call will fail).
if err := unix.Mkdirat(int(currentDir.Fd()), part, uint32(mode)); err != nil && !errors.Is(err, unix.EEXIST) {
if err := unix.Mkdirat(int(currentDir.Fd()), part, unixMode); err != nil && !errors.Is(err, unix.EEXIST) {
err = &os.PathError{Op: "mkdirat", Path: currentDir.Name() + "/" + part, Err: err}
// Make the error a bit nicer if the directory is dead.
if deadErr := isDeadInode(currentDir); deadErr != nil {
@@ -196,10 +220,7 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode int) (_ *os.File, Err
// If you plan to open the directory after you have created it or want to use
// an open directory handle as the root, you should use [MkdirAllHandle] instead.
// This function is a wrapper around [MkdirAllHandle].
//
// NOTE: The mode argument must be set the unix mode bits (unix.S_I...), not
// the Go generic mode bits ([os.FileMode]...).
func MkdirAll(root, unsafePath string, mode int) error {
func MkdirAll(root, unsafePath string, mode os.FileMode) error {
rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0)
if err != nil {
return err

View File

@@ -63,8 +63,6 @@ type parserState struct {
// mainly because the functionality is not needed.
currPath [][]byte
// firstToken stores the first JSON token encountered in input.
// TODO: performance would be better if we would stop parsing as soon
// as we see that first token is not what we are interested in.
firstToken int
// querySatisfied is true if both path and value of any queries passed to
// consumeAny are satisfied.

View File

@@ -40,9 +40,10 @@ func Voc(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("Creative Voice File"))
}
// M3u matches a Playlist file.
func M3u(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("#EXTM3U"))
// M3U matches a Playlist file.
func M3U(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("#EXTM3U\n")) ||
bytes.HasPrefix(raw, []byte("#EXTM3U\r\n"))
}
// AAC matches an Advanced Audio Coding file.

View File

@@ -3,6 +3,8 @@ package magic
import (
"bytes"
"encoding/binary"
"github.com/gabriel-vasile/mimetype/internal/scan"
)
// Pdf matches a Portable Document Format file.
@@ -98,3 +100,26 @@ func Lotus123(raw []byte, _ uint32) bool {
func CHM(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("ITSF\003\000\000\000\x60\000\000\000"))
}
// Inf matches an OS/2 .inf file.
func Inf(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("HSP\x01\x9b\x00"))
}
// Hlp matches an OS/2 .hlp file.
func Hlp(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte("HSP\x10\x9b\x00"))
}
// FrameMaker matches an Adobe FrameMaker file.
func FrameMaker(raw []byte, _ uint32) bool {
b := scan.Bytes(raw)
if !bytes.HasPrefix(b, []byte("<MakerFile")) &&
!bytes.HasPrefix(b, []byte("<MakerDictionary")) &&
b.Match([]byte("<BOOKFILE"), scan.IgnoreCase) == -1 {
return false
}
// To avoid plain text false positives.
return bytes.IndexByte(b[:min(len(b), 512)], 0x00) != -1
}

View File

@@ -2,6 +2,7 @@ package magic
import (
"bytes"
"encoding/binary"
)
// Woff matches a Web Open Font Format file.
@@ -16,7 +17,11 @@ func Woff2(raw []byte, _ uint32) bool {
// Otf matches an OpenType font file.
func Otf(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte{0x4F, 0x54, 0x54, 0x4F, 0x00})
// After OTTO an little endian int16 specifies the number of tables.
// Since the number of tables cannot exceed 256, the first byte of the
// int16 is always 0. PUID: fmt/520
return len(raw) > 48 && bytes.HasPrefix(raw, []byte("OTTO\x00")) &&
bytes.Contains(raw[12:48], []byte("CFF "))
}
// Ttf matches a TrueType font file.
@@ -24,7 +29,72 @@ func Ttf(raw []byte, limit uint32) bool {
if !bytes.HasPrefix(raw, []byte{0x00, 0x01, 0x00, 0x00}) {
return false
}
return !MsAccessAce(raw, limit) && !MsAccessMdb(raw, limit)
return hasSFNTTable(raw)
}
func hasSFNTTable(raw []byte) bool {
// 49 possible tables as explained below
if len(raw) < 16 || binary.BigEndian.Uint16(raw[4:]) >= 49 {
return false
}
// libmagic says there are 47 table names in specification, but it seems
// they reached 49 in the meantime.
// https://github.com/file/file/blob/5184ca2471c0e801c156ee120a90e669fe27b31d/magic/Magdir/fonts#L279
// At the same time, the TrueType docs seem misleading:
// 1. https://developer.apple.com/fonts/TrueType-Reference-Manual/index.html
// 2. https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html
// Page 1. has 48 tables. Page 2. has 49 tables. The diff is the gcid table.
// Take a permissive approach.
possibleTables := []uint32{
0x61636e74, // "acnt"
0x616e6b72, // "ankr"
0x61766172, // "avar"
0x62646174, // "bdat"
0x62686564, // "bhed"
0x626c6f63, // "bloc"
0x62736c6e, // "bsln"
0x636d6170, // "cmap"
0x63766172, // "cvar"
0x63767420, // "cvt "
0x45425343, // "EBSC"
0x66647363, // "fdsc"
0x66656174, // "feat"
0x666d7478, // "fmtx"
0x666f6e64, // "fond"
0x6670676d, // "fpgm"
0x66766172, // "fvar"
0x67617370, // "gasp"
0x67636964, // "gcid"
0x676c7966, // "glyf"
0x67766172, // "gvar"
0x68646d78, // "hdmx"
0x68656164, // "head"
0x68686561, // "hhea"
0x686d7478, // "hmtx"
0x6876676c, // "hvgl"
0x6876706d, // "hvpm"
0x6a757374, // "just"
0x6b65726e, // "kern"
0x6b657278, // "kerx"
0x6c636172, // "lcar"
0x6c6f6361, // "loca"
0x6c746167, // "ltag"
0x6d617870, // "maxp"
0x6d657461, // "meta"
0x6d6f7274, // "mort"
0x6d6f7278, // "morx"
0x6e616d65, // "name"
0x6f706264, // "opbd"
0x4f532f32, // "OS/2"
}
ourTable := binary.BigEndian.Uint32(raw[12:16])
for _, t := range possibleTables {
if ourTable == t {
return true
}
}
return false
}
// Eot matches an Embedded OpenType font file.

View File

@@ -1,6 +1,10 @@
package magic
import "bytes"
import (
"bytes"
"encoding/binary"
"slices"
)
// Png matches a Portable Network Graphics file.
// https://www.w3.org/TR/PNG/
@@ -42,7 +46,28 @@ func Gif(raw []byte, _ uint32) bool {
// Bmp matches a bitmap image file.
func Bmp(raw []byte, _ uint32) bool {
return bytes.HasPrefix(raw, []byte{0x42, 0x4D})
if len(raw) < 18 {
return false
}
if raw[0] != 'B' || raw[1] != 'M' {
return false
}
bmpFormat := binary.LittleEndian.Uint32(raw[14:])
// sourced from libmagic Magdir/images
possibleFormats := []uint32{
48, // PC bitmap, OS/2 2.x format (DIB header size=48)
24, // PC bitmap, OS/2 2.x format (DIB header size=24)
16, // PC bitmap, OS/2 2.x format (DIB header size=16)
64, // PC bitmap, OS/2 2.x format
52, // PC bitmap, Adobe Photoshop
56, // PC bitmap, Adobe Photoshop with alpha channel mask
40, // PC bitmap, Windows 3.x format
124, // PC bitmap, Windows 98/2000 and newer format
108, // PC bitmap, Windows 95/NT4 and newer format
}
return slices.Contains(possibleFormats, bmpFormat)
}
// Ps matches a PostScript file.

View File

@@ -10,3 +10,11 @@ func GRIB(raw []byte, _ uint32) bool {
bytes.HasPrefix(raw, []byte("GRIB")) &&
(raw[7] == 1 || raw[7] == 2)
}
// BUFR matches meteorological data format for storing point or time series data.
// https://confluence.ecmwf.int/download/attachments/31064617/ecCodes_BUFR_in_a_nutshell.pdf?version=1&modificationDate=1457000352419&api=v2
func BUFR(raw []byte, _ uint32) bool {
return len(raw) > 7 &&
bytes.HasPrefix(raw, []byte("BUFR")) &&
(raw[7] == 0x03 || raw[7] == 0x04)
}

View File

@@ -352,6 +352,9 @@ func GLTF(raw []byte, limit uint32) bool {
return jsonHelper(raw, limit, json.QueryGLTF, json.TokObject)
}
// jsonHelper parses raw and tries to match the q query against it. wantToks
// ensures we're not wasting time parsing an input that would not pass anyway,
// ex: the input is a valid JSON array, but we're looking for a JSON object.
func jsonHelper(raw scan.Bytes, limit uint32, q string, wantToks ...int) bool {
firstNonWS := raw.FirstNonWS()
@@ -376,7 +379,7 @@ func jsonHelper(raw scan.Bytes, limit uint32, q string, wantToks ...int) bool {
// If a section of the file was provided, check if all of it was inspected.
// In other words, check that if there was a problem parsing, that problem
// occurred at the last byte in the input.
// occurred after the last byte in the input.
return inspected == lraw && lraw > 0
}
@@ -387,7 +390,6 @@ func NdJSON(raw []byte, limit uint32) bool {
lCount, objOrArr := 0, 0
s := scan.Bytes(raw)
s.DropLastLine(limit)
var l scan.Bytes
for len(s) != 0 {
l = s.Line()

View File

@@ -1,7 +1,7 @@
package mimetype
import (
"mime"
stdmime "mime"
"slices"
"strings"
@@ -52,8 +52,8 @@ func (m *MIME) Parent() *MIME {
func (m *MIME) Is(expectedMIME string) bool {
// Parsing is needed because some detected MIME types contain parameters
// that need to be stripped for the comparison.
expectedMIME, _, _ = mime.ParseMediaType(expectedMIME)
found, _, _ := mime.ParseMediaType(m.mime)
expectedMIME, _, _ = stdmime.ParseMediaType(expectedMIME)
found, _, _ := stdmime.ParseMediaType(m.mime)
if expectedMIME == found {
return true
@@ -118,7 +118,7 @@ func (m *MIME) match(in []byte, readLimit uint32) *MIME {
// flatten transforms an hierarchy of MIMEs into a slice of MIMEs.
func (m *MIME) flatten() []*MIME {
out := []*MIME{m}
out := []*MIME{m} //nolint:prealloc
for _, c := range m.children {
out = append(out, c.flatten()...)
}
@@ -196,6 +196,7 @@ func (m *MIME) lookup(mime string) *MIME {
// The sub-format will be detected if all the detectors in the parent chain return true.
// The extension should include the leading dot, as in ".html".
func (m *MIME) Extend(detector func(raw []byte, limit uint32) bool, mime, extension string, aliases ...string) {
mime, _, _ = stdmime.ParseMediaType(mime)
c := &MIME{
mime: mime,
extension: extension,

View File

@@ -1,4 +1,4 @@
## 195 Supported MIME types
## 199 Supported MIME types
This file is automatically generated when running tests. Do not edit manually.
Extension | MIME type <br> Aliases | Hierarchy
@@ -99,7 +99,7 @@ Extension | MIME type <br> Aliases | Hierarchy
**.asf** | **video/x-ms-asf** <br> video/asf, video/x-ms-wmv | asf>root
**.aac** | **audio/aac** | aac>root
**.voc** | **audio/x-unknown** | voc>root
**.m3u** | **application/vnd.apple.mpegurl** <br> audio/mpegurl | m3u>root
**.m3u** | **application/vnd.apple.mpegurl** <br> audio/mpegurl, application/x-mpegurl | m3u>root
**.rmvb** | **application/vnd.rn-realmedia-vbr** | rmvb>root
**.gz** | **application/gzip** <br> application/x-gzip, application/x-gunzip, application/gzipped, application/gzip-compressed, application/x-gzip-compressed, gzip/document | gz>root
**.class** | **application/x-java-applet** | class>root
@@ -154,6 +154,10 @@ Extension | MIME type <br> Aliases | Hierarchy
**.dxf** | **image/vnd.dxf** | dxf>root
**.grb** | **application/grib** | grb>root
**n/a** | **application/zlib** | zlib>root
**.inf** | **application/x-os2-inf** | inf>root
**.hlp** | **application/x-os2-hlp** | hlp>root
**.fm** | **application/vnd.framemaker** | fm>root
**.bufr** | **application/bufr** | bufr>root
**.txt** | **text/plain** | txt>root
**.svg** | **image/svg+xml** | svg>txt>root
**.html** | **text/html** | html>txt>root

View File

@@ -24,7 +24,7 @@ var root = newMIME("application/octet-stream", "",
woff2, otf, ttc, eot, wasm, shx, dbf, dcm, rar, djvu, mobi, lit, bpg, cbor,
sqlite3, dwg, nes, lnk, macho, qcp, icns, hdr, mrc, mdb, accdb, zstd, cab,
rpm, xz, lzip, torrent, cpio, tzif, xcf, pat, gbr, glb, cabIS, jxr, parquet,
oneNote, chm, wpd, dxf, grib, zlib,
oneNote, chm, wpd, dxf, grib, zlib, inf, hlp, fm, bufr,
// Keep text last because it is the slowest check.
text,
)
@@ -174,8 +174,8 @@ var (
aMp4 = newMIME("audio/mp4", ".mp4", magic.AMp4).
alias("audio/x-mp4a")
m4a = newMIME("audio/x-m4a", ".m4a", magic.M4a)
m3u = newMIME("application/vnd.apple.mpegurl", ".m3u", magic.M3u).
alias("audio/mpegurl")
m3u = newMIME("application/vnd.apple.mpegurl", ".m3u", magic.M3U).
alias("audio/mpegurl", "application/x-mpegurl")
m4v = newMIME("video/x-m4v", ".m4v", magic.M4v)
mj2 = newMIME("video/mj2", ".mj2", magic.Mj2)
dvb = newMIME("video/vnd.dvb.file", ".dvb", magic.Dvb)
@@ -290,4 +290,8 @@ var (
rfc822 = newMIME("message/rfc822", ".eml", magic.RFC822)
grib = newMIME("application/grib", ".grb", magic.GRIB)
zlib = newMIME("application/zlib", "", magic.Zlib)
inf = newMIME("application/x-os2-inf", ".inf", magic.Inf)
hlp = newMIME("application/x-os2-hlp", ".hlp", magic.Hlp)
fm = newMIME("application/vnd.framemaker", ".fm", magic.FrameMaker)
bufr = newMIME("application/bufr", ".bufr", magic.BUFR)
)

View File

@@ -79,6 +79,7 @@ func (hr HeaderRouter) Handler(next http.Handler) http.Handler {
if len(hr) == 0 {
// skip if no routes set
next.ServeHTTP(w, r)
return
}
// find first matching header route, and continue

View File

@@ -8,6 +8,7 @@ import (
"time"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
formatcfg "github.com/go-git/go-git/v5/plumbing/format/config"
@@ -72,9 +73,16 @@ type CloneOptions struct {
// Tags describe how the tags will be fetched from the remote repository,
// by default is AllTags.
Tags TagMode
// InsecureSkipTLS skips ssl verify if protocol is https
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
InsecureSkipTLS bool
// CABundle specify additional ca bundle with system cert pool
// ClientCert is the client certificate to use for mutual TLS authentication
// over the HTTPS protocol.
ClientCert []byte
// ClientKey is the client key to use for mutual TLS authentication over
// the HTTPS protocol.
ClientKey []byte
// CABundle specifies an additional CA bundle to use together with the
// system cert pool.
CABundle []byte
// ProxyOptions provides info required for connecting to a proxy.
ProxyOptions transport.ProxyOptions
@@ -153,9 +161,16 @@ type PullOptions struct {
// Force allows the pull to update a local branch even when the remote
// branch does not descend from it.
Force bool
// InsecureSkipTLS skips ssl verify if protocol is https
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
InsecureSkipTLS bool
// CABundle specify additional ca bundle with system cert pool
// ClientCert is the client certificate to use for mutual TLS authentication
// over the HTTPS protocol.
ClientCert []byte
// ClientKey is the client key to use for mutual TLS authentication over
// the HTTPS protocol.
ClientKey []byte
// CABundle specifies an additional CA bundle to use together with the
// system cert pool.
CABundle []byte
// ProxyOptions provides info required for connecting to a proxy.
ProxyOptions transport.ProxyOptions
@@ -211,9 +226,16 @@ type FetchOptions struct {
// Force allows the fetch to update a local branch even when the remote
// branch does not descend from it.
Force bool
// InsecureSkipTLS skips ssl verify if protocol is https
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
InsecureSkipTLS bool
// CABundle specify additional ca bundle with system cert pool
// ClientCert is the client certificate to use for mutual TLS authentication
// over the HTTPS protocol.
ClientCert []byte
// ClientKey is the client key to use for mutual TLS authentication over
// the HTTPS protocol.
ClientKey []byte
// CABundle specifies an additional CA bundle to use together with the
// system cert pool.
CABundle []byte
// ProxyOptions provides info required for connecting to a proxy.
ProxyOptions transport.ProxyOptions
@@ -267,9 +289,16 @@ type PushOptions struct {
// Force allows the push to update a remote branch even when the local
// branch does not descend from it.
Force bool
// InsecureSkipTLS skips ssl verify if protocol is https
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
InsecureSkipTLS bool
// CABundle specify additional ca bundle with system cert pool
// ClientCert is the client certificate to use for mutual TLS authentication
// over the HTTPS protocol.
ClientCert []byte
// ClientKey is the client key to use for mutual TLS authentication over
// the HTTPS protocol.
ClientKey []byte
// CABundle specifies an additional CA bundle to use together with the
// system cert pool.
CABundle []byte
// RequireRemoteRefs only allows a remote ref to be updated if its current
// value is the one specified here.
@@ -693,9 +722,16 @@ func (o *CreateTagOptions) loadConfigTagger(r *Repository) error {
type ListOptions struct {
// Auth credentials, if required, to use with the remote repository.
Auth transport.AuthMethod
// InsecureSkipTLS skips ssl verify if protocol is https
// InsecureSkipTLS skips SSL verification if protocol is HTTPS.
InsecureSkipTLS bool
// CABundle specify additional ca bundle with system cert pool
// ClientCert is the client certificate to use for mutual TLS authentication
// over the HTTPS protocol.
ClientCert []byte
// ClientKey is the client key to use for mutual TLS authentication over
// the HTTPS protocol.
ClientKey []byte
// CABundle specifies an additional CA bundle to use together with the
// system cert pool.
CABundle []byte
// PeelingOption defines how peeled objects are handled during a
// remote list.

View File

@@ -1,9 +1,11 @@
package idxfile
import (
"bufio"
"bytes"
"crypto"
"encoding/hex"
"errors"
"fmt"
"io"
"github.com/go-git/go-git/v5/plumbing/hash"
@@ -25,12 +27,15 @@ const (
// Decoder reads and decodes idx files from an input stream.
type Decoder struct {
*bufio.Reader
io.Reader
h hash.Hash
}
// NewDecoder builds a new idx stream decoder, that reads from r.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{bufio.NewReader(r)}
h := hash.New(crypto.SHA1)
tr := io.TeeReader(r, h)
return &Decoder{tr, h}
}
// Decode reads from the stream and decode the content into the MemoryIndex struct.
@@ -45,7 +50,7 @@ func (d *Decoder) Decode(idx *MemoryIndex) error {
readObjectNames,
readCRC32,
readOffsets,
readChecksums,
readPackChecksum,
}
for _, f := range flow {
@@ -54,11 +59,21 @@ func (d *Decoder) Decode(idx *MemoryIndex) error {
}
}
actual := d.h.Sum(nil)
if err := readIdxChecksum(idx, d); err != nil {
return err
}
if !bytes.Equal(actual, idx.IdxChecksum[:]) {
return fmt.Errorf("%w: checksum mismatch: %q instead of %q",
ErrMalformedIdxFile, hex.EncodeToString(idx.IdxChecksum[:]), hex.EncodeToString(actual))
}
return nil
}
func validateHeader(r io.Reader) error {
var h = make([]byte, 4)
h := make([]byte, 4)
if _, err := io.ReadFull(r, h); err != nil {
return err
}
@@ -165,11 +180,15 @@ func readOffsets(idx *MemoryIndex, r io.Reader) error {
return nil
}
func readChecksums(idx *MemoryIndex, r io.Reader) error {
func readPackChecksum(idx *MemoryIndex, r io.Reader) error {
if _, err := io.ReadFull(r, idx.PackfileChecksum[:]); err != nil {
return err
}
return nil
}
func readIdxChecksum(idx *MemoryIndex, r io.Reader) error {
if _, err := io.ReadFull(r, idx.IdxChecksum[:]); err != nil {
return err
}

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"io"
"sort"
"sync"
encbin "encoding/binary"
@@ -57,8 +58,9 @@ type MemoryIndex struct {
PackfileChecksum [hash.Size]byte
IdxChecksum [hash.Size]byte
offsetHash map[int64]plumbing.Hash
offsetHashIsFull bool
offsetHash map[int64]plumbing.Hash
offsetBuildOnce sync.Once
mu sync.RWMutex
}
var _ Index = (*MemoryIndex)(nil)
@@ -126,13 +128,13 @@ func (idx *MemoryIndex) FindOffset(h plumbing.Hash) (int64, error) {
offset := idx.getOffset(k, i)
if !idx.offsetHashIsFull {
// Save the offset for reverse lookup
if idx.offsetHash == nil {
idx.offsetHash = make(map[int64]plumbing.Hash)
}
idx.offsetHash[int64(offset)] = h
// Save the offset for reverse lookup
idx.mu.Lock()
if idx.offsetHash == nil {
idx.offsetHash = make(map[int64]plumbing.Hash)
}
idx.offsetHash[int64(offset)] = h
idx.mu.Unlock()
return int64(offset), nil
}
@@ -173,20 +175,17 @@ func (idx *MemoryIndex) FindHash(o int64) (plumbing.Hash, error) {
var hash plumbing.Hash
var ok bool
if idx.offsetHash != nil {
if hash, ok = idx.offsetHash[o]; ok {
return hash, nil
}
var genErr error
idx.offsetBuildOnce.Do(func() {
genErr = idx.genOffsetHash()
})
if genErr != nil {
return plumbing.ZeroHash, genErr
}
// Lazily generate the reverse offset/hash map if required.
if !idx.offsetHashIsFull || idx.offsetHash == nil {
if err := idx.genOffsetHash(); err != nil {
return plumbing.ZeroHash, err
}
hash, ok = idx.offsetHash[o]
}
idx.mu.RLock()
hash, ok = idx.offsetHash[o]
idx.mu.RUnlock()
if !ok {
return plumbing.ZeroHash, plumbing.ErrObjectNotFound
@@ -202,8 +201,7 @@ func (idx *MemoryIndex) genOffsetHash() error {
return err
}
idx.offsetHash = make(map[int64]plumbing.Hash, count)
idx.offsetHashIsFull = true
offsetHash := make(map[int64]plumbing.Hash, count)
var hash plumbing.Hash
i := uint32(0)
@@ -212,11 +210,15 @@ func (idx *MemoryIndex) genOffsetHash() error {
for secondLevel := uint32(0); i < fanoutValue; i++ {
copy(hash[:], idx.Names[mappedFirstLevel][secondLevel*objectIDLength:])
offset := int64(idx.getOffset(mappedFirstLevel, int(secondLevel)))
idx.offsetHash[offset] = hash
offsetHash[offset] = hash
secondLevel++
}
}
idx.mu.Lock()
idx.offsetHash = offsetHash
idx.mu.Unlock()
return nil
}

View File

@@ -30,7 +30,7 @@ type Reader struct {
func NewReader(r io.Reader) (*Reader, error) {
zlib, err := sync.GetZlibReader(r)
if err != nil {
return nil, packfile.ErrZLib.AddDetails(err.Error())
return nil, packfile.ErrZLib.AddDetails("%s", err.Error())
}
return &Reader{

View File

@@ -47,7 +47,6 @@ type Parser struct {
oi []*objectInfo
oiByHash map[plumbing.Hash]*objectInfo
oiByOffset map[int64]*objectInfo
checksum plumbing.Hash
cache *cache.BufferLRU
// delta content by offset, only used if source is not seekable
@@ -133,28 +132,27 @@ func (p *Parser) onFooter(h plumbing.Hash) error {
// Parse start decoding phase of the packfile.
func (p *Parser) Parse() (plumbing.Hash, error) {
if err := p.init(); err != nil {
return plumbing.ZeroHash, err
return plumbing.ZeroHash, wrapEOF(err)
}
if err := p.indexObjects(); err != nil {
return plumbing.ZeroHash, err
return plumbing.ZeroHash, wrapEOF(err)
}
var err error
p.checksum, err = p.scanner.Checksum()
checksum, err := p.scanner.Checksum()
if err != nil && err != io.EOF {
return plumbing.ZeroHash, err
return plumbing.ZeroHash, wrapEOF(err)
}
if err := p.resolveDeltas(); err != nil {
return plumbing.ZeroHash, err
return plumbing.ZeroHash, wrapEOF(err)
}
if err := p.onFooter(p.checksum); err != nil {
return plumbing.ZeroHash, err
if err := p.onFooter(checksum); err != nil {
return plumbing.ZeroHash, wrapEOF(err)
}
return p.checksum, nil
return checksum, nil
}
func (p *Parser) init() error {
@@ -218,7 +216,7 @@ func (p *Parser) indexObjects() error {
if !ok {
// can't find referenced object in this pack file
// this must be a "thin" pack.
parent = &objectInfo{ //Placeholder parent
parent = &objectInfo{ // Placeholder parent
SHA1: oh.Reference,
ExternalRef: true, // mark as an external reference that must be resolved
Type: plumbing.AnyObject,
@@ -531,6 +529,13 @@ func (p *Parser) readData(w io.Writer, o *objectInfo) error {
return nil
}
func wrapEOF(err error) error {
if err == io.ErrUnexpectedEOF || err == io.EOF {
return fmt.Errorf("%w: %w", ErrMalformedPackFile, err)
}
return err
}
// applyPatchBase applies the patch to target.
//
// Note that ota will be updated based on the description in resolveObject.
@@ -558,15 +563,6 @@ func applyPatchBase(ota *objectInfo, base io.ReaderAt, delta io.Reader, target i
return nil
}
func getSHA1(t plumbing.ObjectType, data []byte) (plumbing.Hash, error) {
hasher := plumbing.NewHasher(t, int64(len(data)))
if _, err := hasher.Write(data); err != nil {
return plumbing.ZeroHash, err
}
return hasher.Sum(), nil
}
type objectInfo struct {
Offset int64
Length int64

View File

@@ -3,12 +3,15 @@ package packfile
import (
"bufio"
"bytes"
"crypto"
"errors"
"fmt"
"hash"
gohash "hash"
"hash/crc32"
"io"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/hash"
"github.com/go-git/go-git/v5/utils/binary"
"github.com/go-git/go-git/v5/utils/ioutil"
"github.com/go-git/go-git/v5/utils/sync"
@@ -24,6 +27,8 @@ var (
ErrUnsupportedVersion = NewError("unsupported packfile version")
// ErrSeekNotSupported returned if seek is not support
ErrSeekNotSupported = NewError("not seek support")
// ErrMalformedPackFile is returned by the parser when the pack file is corrupted.
ErrMalformedPackFile = errors.New("malformed PACK file")
)
// ObjectHeader contains the information related to the object, this information
@@ -37,8 +42,9 @@ type ObjectHeader struct {
}
type Scanner struct {
r *scannerReader
crc hash.Hash32
r *scannerReader
crc gohash.Hash32
packHasher hash.Hash
// pendingObject is used to detect if an object has been read, or still
// is waiting to be read
@@ -56,10 +62,12 @@ func NewScanner(r io.Reader) *Scanner {
_, ok := r.(io.ReadSeeker)
crc := crc32.NewIEEE()
hasher := hash.New(crypto.SHA1)
return &Scanner{
r: newScannerReader(r, crc),
r: newScannerReader(r, io.MultiWriter(crc, hasher)),
crc: crc,
IsSeekable: ok,
packHasher: hasher,
}
}
@@ -68,6 +76,7 @@ func (s *Scanner) Reset(r io.Reader) {
s.r.Reset(r)
s.crc.Reset()
s.packHasher.Reset()
s.IsSeekable = ok
s.pendingObject = nil
s.version = 0
@@ -114,7 +123,7 @@ func (s *Scanner) Header() (version, objects uint32, err error) {
// readSignature reads a returns the signature field in the packfile.
func (s *Scanner) readSignature() ([]byte, error) {
var sig = make([]byte, 4)
sig := make([]byte, 4)
if _, err := io.ReadFull(s.r, sig); err != nil {
return []byte{}, err
}
@@ -322,7 +331,6 @@ func (s *Scanner) NextObject(w io.Writer) (written int64, crc32 uint32, err erro
func (s *Scanner) ReadObject() (io.ReadCloser, error) {
s.pendingObject = nil
zr, err := sync.GetZlibReader(s.r)
if err != nil {
return nil, fmt.Errorf("zlib reset error: %s", err)
}
@@ -374,7 +382,18 @@ func (s *Scanner) Checksum() (plumbing.Hash, error) {
return plumbing.ZeroHash, err
}
return binary.ReadHash(s.r)
s.r.Flush()
actual := plumbing.Hash(s.packHasher.Sum(nil))
packChecksum, err := binary.ReadHash(s.r)
if err != nil {
return plumbing.ZeroHash, err
}
if actual != packChecksum {
return plumbing.ZeroHash, fmt.Errorf("%w: checksum mismatch: %q instead of %q", ErrMalformedPackFile, packChecksum, actual)
}
return packChecksum, nil
}
// Close reads the reader until io.EOF
@@ -401,17 +420,17 @@ func (s *Scanner) Flush() error {
// to the crc32 hash writer.
type scannerReader struct {
reader io.Reader
crc io.Writer
writer io.Writer
rbuf *bufio.Reader
wbuf *bufio.Writer
offset int64
}
func newScannerReader(r io.Reader, h io.Writer) *scannerReader {
func newScannerReader(r io.Reader, w io.Writer) *scannerReader {
sr := &scannerReader{
rbuf: bufio.NewReader(nil),
wbuf: bufio.NewWriterSize(nil, 64),
crc: h,
rbuf: bufio.NewReader(nil),
wbuf: bufio.NewWriterSize(nil, 64),
writer: w,
}
sr.Reset(r)
@@ -421,7 +440,7 @@ func newScannerReader(r io.Reader, h io.Writer) *scannerReader {
func (r *scannerReader) Reset(reader io.Reader) {
r.reader = reader
r.rbuf.Reset(r.reader)
r.wbuf.Reset(r.crc)
r.wbuf.Reset(r.writer)
r.offset = 0
if seeker, ok := r.reader.(io.ReadSeeker); ok {

View File

@@ -62,10 +62,55 @@ type Commit struct {
ParentHashes []plumbing.Hash
// Encoding is the encoding of the commit.
Encoding MessageEncoding
// List of extra headers of the commit
ExtraHeaders []ExtraHeader
s storer.EncodedObjectStorer
}
// ExtraHeader holds any non-standard header
type ExtraHeader struct {
// Header name
Key string
// Value of the header
Value string
}
// Implement fmt.Formatter for ExtraHeader
func (h ExtraHeader) Format(f fmt.State, verb rune) {
switch verb {
case 'v':
fmt.Fprintf(f, "ExtraHeader{Key: %v, Value: %v}", h.Key, h.Value)
default:
fmt.Fprintf(f, "%s", h.Key)
if len(h.Value) > 0 {
fmt.Fprint(f, " ")
// Content may be spread on multiple lines, if so we need to
// prepend each of them with a space for "continuation".
value := strings.TrimSuffix(h.Value, "\n")
lines := strings.Split(value, "\n")
fmt.Fprint(f, strings.Join(lines, "\n "))
}
}
}
// Parse an extra header and indicate whether it may be continue on the next line
func parseExtraHeader(line []byte) (ExtraHeader, bool) {
split := bytes.SplitN(line, []byte{' '}, 2)
out := ExtraHeader {
Key: string(bytes.TrimRight(split[0], "\n")),
Value: "",
}
if len(split) == 2 {
out.Value += string(split[1])
return out, true
} else {
return out, false
}
}
// GetCommit gets a commit from an object storer and decodes it.
func GetCommit(s storer.EncodedObjectStorer, h plumbing.Hash) (*Commit, error) {
o, err := s.EncodedObject(plumbing.CommitObject, h)
@@ -204,6 +249,7 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
var mergetag bool
var pgpsig bool
var msgbuf bytes.Buffer
var extraheader *ExtraHeader = nil
for {
line, err := r.ReadBytes('\n')
if err != nil && err != io.EOF {
@@ -230,7 +276,19 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
}
}
if extraheader != nil {
if len(line) > 0 && line[0] == ' ' {
extraheader.Value += string(line[1:])
continue
} else {
extraheader.Value = strings.TrimRight(extraheader.Value, "\n")
c.ExtraHeaders = append(c.ExtraHeaders, *extraheader)
extraheader = nil
}
}
if !message {
original_line := line
line = bytes.TrimSpace(line)
if len(line) == 0 {
message = true
@@ -261,6 +319,13 @@ func (c *Commit) Decode(o plumbing.EncodedObject) (err error) {
case headerpgp:
c.PGPSignature += string(data) + "\n"
pgpsig = true
default:
h, maybecontinued := parseExtraHeader(original_line)
if maybecontinued {
extraheader = &h
} else {
c.ExtraHeaders = append(c.ExtraHeaders, h)
}
}
} else {
msgbuf.Write(line)
@@ -341,6 +406,13 @@ func (c *Commit) encode(o plumbing.EncodedObject, includeSig bool) (err error) {
}
}
for _, header := range c.ExtraHeaders {
if _, err = fmt.Fprintf(w, "\n%s", header); err != nil {
return err
}
}
if c.PGPSignature != "" && includeSig {
if _, err = fmt.Fprint(w, "\n"+headerpgp+" "); err != nil {
return err

View File

@@ -262,9 +262,8 @@ func decodeShallow(p *advRefsDecoder) decoderStateFn {
p.line = bytes.TrimPrefix(p.line, shallow)
if len(p.line) != hashSize {
p.error(fmt.Sprintf(
"malformed shallow hash: wrong length, expected 40 bytes, read %d bytes",
len(p.line)))
p.error("malformed shallow hash: wrong length, expected 40 bytes, read %d bytes",
len(p.line))
return nil
}

View File

@@ -62,7 +62,7 @@ func (req *ReferenceUpdateRequest) encodeCommands(e *pktline.Encoder,
}
for _, cmd := range cmds[1:] {
if err := e.Encodef(formatCommand(cmd)); err != nil {
if err := e.Encodef("%s", formatCommand(cmd)); err != nil {
return err
}
}

View File

@@ -113,9 +113,17 @@ type Endpoint struct {
Port int
// Path is the repository path.
Path string
// InsecureSkipTLS skips ssl verify if protocol is https
// InsecureSkipTLS skips SSL verification if Protocol is HTTPS.
InsecureSkipTLS bool
// CaBundle specify additional ca bundle with system cert pool
// ClientCert specifies an optional client certificate to use for mutual
// TLS authentication if Protocol is HTTPS.
ClientCert []byte
// ClientKey specifies an optional client key to use for mutual TLS
// authentication if Protocol is HTTPS.
ClientKey []byte
// CaBundle specifies an optional CA bundle to use for SSL verification
// if Protocol is HTTPS. The bundle is added in addition to the system
// CA bundle.
CaBundle []byte
// Proxy provides info required for connecting to a proxy.
Proxy ProxyOptions

View File

@@ -15,12 +15,13 @@ import (
"strings"
"sync"
"github.com/golang/groupcache/lru"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/protocol/packp"
"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/utils/ioutil"
"github.com/golang/groupcache/lru"
)
// it requires a bytes.Buffer, because we need to know the length
@@ -185,6 +186,18 @@ func transportWithInsecureTLS(transport *http.Transport) {
transport.TLSClientConfig.InsecureSkipVerify = true
}
func transportWithClientCert(transport *http.Transport, cert, key []byte) error {
keyPair, err := tls.X509KeyPair(cert, key)
if err != nil {
return err
}
if transport.TLSClientConfig == nil {
transport.TLSClientConfig = &tls.Config{}
}
transport.TLSClientConfig.Certificates = []tls.Certificate{keyPair}
return nil
}
func transportWithCABundle(transport *http.Transport, caBundle []byte) error {
rootCAs, err := x509.SystemCertPool()
if err != nil {
@@ -206,6 +219,11 @@ func transportWithProxy(transport *http.Transport, proxyURL *url.URL) {
}
func configureTransport(transport *http.Transport, ep *transport.Endpoint) error {
if len(ep.ClientCert) > 0 && len(ep.ClientKey) > 0 {
if err := transportWithClientCert(transport, ep.ClientCert, ep.ClientKey); err != nil {
return err
}
}
if len(ep.CaBundle) > 0 {
if err := transportWithCABundle(transport, ep.CaBundle); err != nil {
return err
@@ -230,7 +248,7 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
// We need to configure the http transport if there are transport specific
// options present in the endpoint.
if len(ep.CaBundle) > 0 || ep.InsecureSkipTLS || ep.Proxy.URL != "" {
if len(ep.ClientKey) > 0 || len(ep.ClientCert) > 0 || len(ep.CaBundle) > 0 || ep.InsecureSkipTLS || ep.Proxy.URL != "" {
var transport *http.Transport
// if the client wasn't configured to have a cache for transports then just configure
// the transport and use it directly, otherwise try to use the cache.
@@ -242,9 +260,13 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
}
transport = tr.Clone()
configureTransport(transport, ep)
if err := configureTransport(transport, ep); err != nil {
return nil, err
}
} else {
transportOpts := transportOptions{
clientCert: string(ep.ClientCert),
clientKey: string(ep.ClientKey),
caBundle: string(ep.CaBundle),
insecureSkipTLS: ep.InsecureSkipTLS,
}
@@ -260,7 +282,9 @@ func newSession(c *client, ep *transport.Endpoint, auth transport.AuthMethod) (*
if !found {
transport = c.client.Transport.(*http.Transport).Clone()
configureTransport(transport, ep)
if err := configureTransport(transport, ep); err != nil {
return nil, err
}
c.addTransport(transportOpts, transport)
}
}

View File

@@ -9,8 +9,10 @@ import (
type transportOptions struct {
insecureSkipTLS bool
// []byte is not comparable.
caBundle string
proxyURL url.URL
clientCert string
clientKey string
caBundle string
proxyURL url.URL
}
func (c *client) addTransport(opts transportOptions, transport *http.Transport) {

View File

@@ -54,7 +54,7 @@ func (a *KeyboardInteractive) String() string {
}
func (a *KeyboardInteractive) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
return a.SetHostKeyCallbackAndAlgorithms(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{
a.Challenge,
@@ -78,7 +78,7 @@ func (a *Password) String() string {
}
func (a *Password) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
return a.SetHostKeyCallbackAndAlgorithms(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.Password(a.Password)},
})
@@ -101,7 +101,7 @@ func (a *PasswordCallback) String() string {
}
func (a *PasswordCallback) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
return a.SetHostKeyCallbackAndAlgorithms(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)},
})
@@ -150,7 +150,7 @@ func (a *PublicKeys) String() string {
}
func (a *PublicKeys) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
return a.SetHostKeyCallbackAndAlgorithms(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PublicKeys(a.Signer)},
})
@@ -211,7 +211,7 @@ func (a *PublicKeysCallback) String() string {
}
func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
return a.SetHostKeyCallbackAndAlgorithms(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)},
})
@@ -230,11 +230,26 @@ func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) {
// ~/.ssh/known_hosts
// /etc/ssh/ssh_known_hosts
func NewKnownHostsCallback(files ...string) (ssh.HostKeyCallback, error) {
kh, err := newKnownHosts(files...)
return ssh.HostKeyCallback(kh), err
kh, err := NewKnownHostsDb(files...)
if err != nil {
return nil, err
}
return kh.HostKeyCallback(), nil
}
func newKnownHosts(files ...string) (knownhosts.HostKeyCallback, error) {
// NewKnownHostsDb returns knownhosts.HostKeyDB based on a file based on a
// known_hosts file. http://man.openbsd.org/sshd#SSH_KNOWN_HOSTS_FILE_FORMAT
//
// If list of files is empty, then it will be read from the SSH_KNOWN_HOSTS
// environment variable, example:
//
// /home/foo/custom_known_hosts_file:/etc/custom_known/hosts_file
//
// If SSH_KNOWN_HOSTS is not set the following file locations will be used:
//
// ~/.ssh/known_hosts
// /etc/ssh/ssh_known_hosts
func NewKnownHostsDb(files ...string) (*knownhosts.HostKeyDB, error) {
var err error
if len(files) == 0 {
@@ -247,7 +262,7 @@ func newKnownHosts(files ...string) (knownhosts.HostKeyCallback, error) {
return nil, err
}
return knownhosts.New(files...)
return knownhosts.NewDB(files...)
}
func getDefaultKnownHostsFiles() ([]string, error) {
@@ -289,25 +304,50 @@ func filterKnownHostsFiles(files ...string) ([]string, error) {
}
// HostKeyCallbackHelper is a helper that provides common functionality to
// configure HostKeyCallback into a ssh.ClientConfig.
// configure HostKeyCallback and HostKeyAlgorithms into a ssh.ClientConfig.
type HostKeyCallbackHelper struct {
// HostKeyCallback is the function type used for verifying server keys.
// If nil default callback will be create using NewKnownHostsCallback
// If nil, a default callback will be created using NewKnownHostsDb
// without argument.
HostKeyCallback ssh.HostKeyCallback
// HostKeyAlgorithms is a list of supported host key algorithms that will
// be used for host key verification.
HostKeyAlgorithms []string
// fallback allows for injecting the fallback call, which is called
// when a HostKeyCallback is not set.
fallback func(files ...string) (ssh.HostKeyCallback, error)
}
// SetHostKeyCallback sets the field HostKeyCallback in the given cfg. If
// HostKeyCallback is empty a default callback is created using
// NewKnownHostsCallback.
func (m *HostKeyCallbackHelper) SetHostKeyCallback(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) {
var err error
// SetHostKeyCallbackAndAlgorithms sets the field HostKeyCallback and HostKeyAlgorithms in the given cfg.
// If the host key callback or algorithms is empty it is left empty. It will be handled by the dial method,
// falling back to knownhosts.
func (m *HostKeyCallbackHelper) SetHostKeyCallbackAndAlgorithms(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) {
if cfg == nil {
cfg = &ssh.ClientConfig{}
}
if m.HostKeyCallback == nil {
if m.HostKeyCallback, err = NewKnownHostsCallback(); err != nil {
return cfg, err
if m.fallback == nil {
m.fallback = NewKnownHostsCallback
}
hkcb, err := m.fallback()
if err != nil {
return nil, fmt.Errorf("cannot create known hosts callback: %w", err)
}
cfg.HostKeyCallback = hkcb
cfg.HostKeyAlgorithms = m.HostKeyAlgorithms
return cfg, err
}
cfg.HostKeyCallback = m.HostKeyCallback
cfg.HostKeyAlgorithms = m.HostKeyAlgorithms
return cfg, nil
}
func (m *HostKeyCallbackHelper) SetHostKeyCallback(cfg *ssh.ClientConfig) (*ssh.ClientConfig, error) {
return m.SetHostKeyCallbackAndAlgorithms(cfg)
}

View File

@@ -11,7 +11,6 @@ import (
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/internal/common"
"github.com/skeema/knownhosts"
"github.com/kevinburke/ssh_config"
"golang.org/x/crypto/ssh"
@@ -127,17 +126,17 @@ func (c *command) connect() error {
}
hostWithPort := c.getHostWithPort()
if config.HostKeyCallback == nil {
kh, err := newKnownHosts()
db, err := NewKnownHostsDb()
if err != nil {
return err
}
config.HostKeyCallback = kh.HostKeyCallback()
config.HostKeyAlgorithms = kh.HostKeyAlgorithms(hostWithPort)
} else if len(config.HostKeyAlgorithms) == 0 {
// Set the HostKeyAlgorithms based on HostKeyCallback.
// For background see https://github.com/go-git/go-git/issues/411 as well as
// https://github.com/golang/go/issues/29286 for root cause.
config.HostKeyAlgorithms = knownhosts.HostKeyAlgorithms(config.HostKeyCallback, hostWithPort)
config.HostKeyCallback = db.HostKeyCallback()
config.HostKeyAlgorithms = db.HostKeyAlgorithms(hostWithPort)
} else {
// If the user gave a custom HostKeyCallback, we do not try to detect host key algorithms
// based on knownhosts functionality, as the user may be requesting a FixedKey or using a
// different key approval strategy. In that case, the user is responsible for populating
// HostKeyAlgorithms appropriately
}
overrideConfig(c.config, config)

View File

@@ -114,7 +114,7 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
o.RemoteURL = r.c.URLs[len(r.c.URLs)-1]
}
s, err := newSendPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.CABundle, o.ProxyOptions)
s, err := newSendPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.ClientCert, o.ClientKey, o.CABundle, o.ProxyOptions)
if err != nil {
return err
}
@@ -416,7 +416,7 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
o.RemoteURL = r.c.URLs[0]
}
s, err := newUploadPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.CABundle, o.ProxyOptions)
s, err := newUploadPackSession(o.RemoteURL, o.Auth, o.InsecureSkipTLS, o.ClientCert, o.ClientKey, o.CABundle, o.ProxyOptions)
if err != nil {
return nil, err
}
@@ -532,8 +532,8 @@ func depthChanged(before []plumbing.Hash, s storage.Storer) (bool, error) {
return false, nil
}
func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool, cabundle []byte, proxyOpts transport.ProxyOptions) (transport.UploadPackSession, error) {
c, ep, err := newClient(url, insecure, cabundle, proxyOpts)
func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool, clientCert, clientKey, caBundle []byte, proxyOpts transport.ProxyOptions) (transport.UploadPackSession, error) {
c, ep, err := newClient(url, insecure, clientCert, clientKey, caBundle, proxyOpts)
if err != nil {
return nil, err
}
@@ -541,8 +541,8 @@ func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool,
return c.NewUploadPackSession(ep, auth)
}
func newSendPackSession(url string, auth transport.AuthMethod, insecure bool, cabundle []byte, proxyOpts transport.ProxyOptions) (transport.ReceivePackSession, error) {
c, ep, err := newClient(url, insecure, cabundle, proxyOpts)
func newSendPackSession(url string, auth transport.AuthMethod, insecure bool, clientCert, clientKey, caBundle []byte, proxyOpts transport.ProxyOptions) (transport.ReceivePackSession, error) {
c, ep, err := newClient(url, insecure, clientCert, clientKey, caBundle, proxyOpts)
if err != nil {
return nil, err
}
@@ -550,13 +550,15 @@ func newSendPackSession(url string, auth transport.AuthMethod, insecure bool, ca
return c.NewReceivePackSession(ep, auth)
}
func newClient(url string, insecure bool, cabundle []byte, proxyOpts transport.ProxyOptions) (transport.Transport, *transport.Endpoint, error) {
func newClient(url string, insecure bool, clientCert, clientKey, caBundle []byte, proxyOpts transport.ProxyOptions) (transport.Transport, *transport.Endpoint, error) {
ep, err := transport.NewEndpoint(url)
if err != nil {
return nil, nil, err
}
ep.InsecureSkipTLS = insecure
ep.CaBundle = cabundle
ep.ClientCert = clientCert
ep.ClientKey = clientKey
ep.CaBundle = caBundle
ep.Proxy = proxyOpts
c, err := client.NewClient(ep)
@@ -1356,7 +1358,7 @@ func (r *Remote) list(ctx context.Context, o *ListOptions) (rfs []*plumbing.Refe
return nil, ErrEmptyUrls
}
s, err := newUploadPackSession(r.c.URLs[0], o.Auth, o.InsecureSkipTLS, o.CABundle, o.ProxyOptions)
s, err := newUploadPackSession(r.c.URLs[0], o.Auth, o.InsecureSkipTLS, o.ClientCert, o.ClientKey, o.CABundle, o.ProxyOptions)
if err != nil {
return nil, err
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-billy/v5/util"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/internal/path_util"
"github.com/go-git/go-git/v5/internal/revision"
@@ -930,6 +931,8 @@ func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
Tags: o.Tags,
RemoteName: o.RemoteName,
InsecureSkipTLS: o.InsecureSkipTLS,
ClientCert: o.ClientCert,
ClientKey: o.ClientKey,
CABundle: o.CABundle,
ProxyOptions: o.ProxyOptions,
}, o.ReferenceName)

View File

@@ -2,6 +2,8 @@ package filesystem
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"os"
"sync"
@@ -87,6 +89,11 @@ func (s *ObjectStorage) loadIdxFile(h plumbing.Hash) (err error) {
return err
}
if !bytes.Equal(idxf.PackfileChecksum[:], h[:]) {
return fmt.Errorf("%w: packfile mismatch: target is %q not %q",
idxfile.ErrMalformedIdxFile, hex.EncodeToString(idxf.PackfileChecksum[:]), h.String())
}
s.index[h] = idxf
return err
}
@@ -186,7 +193,8 @@ func (s *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) {
}
func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) (
size int64, err error) {
size int64, err error,
) {
f, err := s.dir.Object(h)
if err != nil {
if os.IsNotExist(err) {
@@ -274,7 +282,8 @@ func (s *ObjectStorage) storePackfileInCache(hash plumbing.Hash, p *packfile.Pac
}
func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
size int64, err error) {
size int64, err error,
) {
if err := s.requireIndex(); err != nil {
return 0, err
}
@@ -310,7 +319,8 @@ func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
// EncodedObjectSize returns the plaintext size of the given object,
// without actually reading the full object data from storage.
func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (
size int64, err error) {
size int64, err error,
) {
size, err = s.encodedObjectSizeFromUnpacked(h)
if err != nil && err != plumbing.ErrObjectNotFound {
return 0, err
@@ -371,7 +381,8 @@ func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (p
// DeltaObject returns the object with the given hash, by searching for
// it in the packfile and the git object directories.
func (s *ObjectStorage) DeltaObject(t plumbing.ObjectType,
h plumbing.Hash) (plumbing.EncodedObject, error) {
h plumbing.Hash,
) (plumbing.EncodedObject, error) {
obj, err := s.getFromUnpacked(h)
if err == plumbing.ErrObjectNotFound {
obj, err = s.getFromPackfile(h, true)
@@ -451,8 +462,8 @@ var copyBufferPool = sync.Pool{
// Get returns the object with the given hash, by searching for it in
// the packfile.
func (s *ObjectStorage) getFromPackfile(h plumbing.Hash, canBeDelta bool) (
plumbing.EncodedObject, error) {
plumbing.EncodedObject, error,
) {
if err := s.requireIndex(); err != nil {
return nil, err
}
@@ -509,9 +520,7 @@ func (s *ObjectStorage) decodeDeltaObjectAt(
return nil, err
}
var (
base plumbing.Hash
)
var base plumbing.Hash
switch header.Type {
case plumbing.REFDeltaObject:

View File

@@ -131,7 +131,9 @@ func (l *Changes) addRecursive(root noder.Path, ctor noderToChangeFn) error {
}
if !root.IsDir() {
l.Add(ctor(root))
if !root.Skip() {
l.Add(ctor(root))
}
return nil
}
@@ -148,7 +150,7 @@ func (l *Changes) addRecursive(root noder.Path, ctor noderToChangeFn) error {
}
return err
}
if current.IsDir() {
if current.IsDir() || current.Skip() {
continue
}
l.Add(ctor(current))

View File

@@ -297,18 +297,16 @@ func DiffTreeContext(ctx context.Context, fromTree, toTree noder.Noder,
case noMoreNoders:
return ret, nil
case onlyFromRemains:
if err = ret.AddRecursiveDelete(from); err != nil {
return nil, err
if !from.Skip() {
if err = ret.AddRecursiveDelete(from); err != nil {
return nil, err
}
}
if err = ii.nextFrom(); err != nil {
return nil, err
}
case onlyToRemains:
if to.Skip() {
if err = ret.AddRecursiveDelete(to); err != nil {
return nil, err
}
} else {
if !to.Skip() {
if err = ret.AddRecursiveInsert(to); err != nil {
return nil, err
}
@@ -317,26 +315,25 @@ func DiffTreeContext(ctx context.Context, fromTree, toTree noder.Noder,
return nil, err
}
case bothHaveNodes:
if from.Skip() {
if err = ret.AddRecursiveDelete(from); err != nil {
return nil, err
var err error
switch {
case from.Skip():
if from.Name() == to.Name() {
err = ii.nextBoth()
} else {
err = ii.nextFrom()
}
if err := ii.nextBoth(); err != nil {
return nil, err
case to.Skip():
if from.Name() == to.Name() {
err = ii.nextBoth()
} else {
err = ii.nextTo()
}
break
}
if to.Skip() {
if err = ret.AddRecursiveDelete(to); err != nil {
return nil, err
}
if err := ii.nextBoth(); err != nil {
return nil, err
}
break
default:
err = diffNodes(&ret, ii)
}
if err = diffNodes(&ret, ii); err != nil {
if err != nil {
return nil, err
}
default:

View File

@@ -36,7 +36,15 @@ func NewRootNode(idx *index.Index) noder.Noder {
parent := fullpath
fullpath = path.Join(fullpath, part)
if _, ok := m[fullpath]; ok {
// It's possible that the first occurrence of subdirectory is skipped.
// The parent node can be created with SkipWorktree set to true, but
// if any future children do not skip their subtree, the entire lineage
// of the tree needs to have this value set to false so that subdirectories
// are not ignored.
if parentNode, ok := m[fullpath]; ok {
if e.SkipWorktree == false {
parentNode.skip = false
}
continue
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/util"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/filemode"
@@ -79,6 +80,8 @@ func (w *Worktree) PullContext(ctx context.Context, o *PullOptions) error {
Progress: o.Progress,
Force: o.Force,
InsecureSkipTLS: o.InsecureSkipTLS,
ClientCert: o.ClientCert,
ClientKey: o.ClientKey,
CABundle: o.CABundle,
ProxyOptions: o.ProxyOptions,
})
@@ -307,13 +310,20 @@ func (w *Worktree) ResetSparsely(opts *ResetOptions, dirs []string) error {
return err
}
var removedFiles []string
if opts.Mode == MixedReset || opts.Mode == MergeReset || opts.Mode == HardReset {
if err := w.resetIndex(t, dirs, opts.Files); err != nil {
if removedFiles, err = w.resetIndex(t, dirs, opts.Files); err != nil {
return err
}
}
if opts.Mode == MergeReset || opts.Mode == HardReset {
if opts.Mode == MergeReset && len(removedFiles) > 0 {
if err := w.resetWorktree(t, removedFiles); err != nil {
return err
}
}
if opts.Mode == HardReset {
if err := w.resetWorktree(t, opts.Files); err != nil {
return err
}
@@ -362,23 +372,24 @@ func (w *Worktree) Reset(opts *ResetOptions) error {
return w.ResetSparsely(opts, nil)
}
func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) error {
func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) ([]string, error) {
idx, err := w.r.Storer.Index()
if err != nil {
return err
return nil, err
}
b := newIndexBuilder(idx)
changes, err := w.diffTreeWithStaging(t, true)
if err != nil {
return err
return nil, err
}
var removedFiles []string
for _, ch := range changes {
a, err := ch.Action()
if err != nil {
return err
return nil, err
}
var name string
@@ -389,7 +400,7 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) err
name = ch.To.String()
e, err = t.FindEntry(name)
if err != nil {
return err
return nil, err
}
case merkletrie.Delete:
name = ch.From.String()
@@ -403,6 +414,7 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) err
}
b.Remove(name)
removedFiles = append(removedFiles, name)
if e == nil {
continue
}
@@ -421,7 +433,7 @@ func (w *Worktree) resetIndex(t *object.Tree, dirs []string, files []string) err
idx.SkipUnless(dirs)
}
return w.r.Storer.SetIndex(idx)
return removedFiles, w.r.Storer.SetIndex(idx)
}
func inFiles(files []string, v string) bool {

View File

@@ -82,7 +82,11 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://dnscheck.tools/
* https://github.com/egbakou/domainverifier
* https://github.com/semihalev/sdns
* https://github.com/wintbiit/NineDNS
* https://linuxcontainers.org/incus/
* https://ifconfig.es
* https://github.com/zmap/zdns
* https://framagit.org/bortzmeyer/check-soa
Send pull request if you want to be listed here.
@@ -125,6 +129,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
*all of them*
* 103{4,5} - DNS standard
* 1183 - ISDN, X25 and other deprecated records
* 1348 - NSAP record (removed the record)
* 1982 - Serial Arithmetic
* 1876 - LOC record
@@ -144,6 +149,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
* 3225 - DO bit (DNSSEC OK)
* 340{1,2,3} - NAPTR record
* 3445 - Limiting the scope of (DNS)KEY
* 3596 - AAAA record
* 3597 - Unknown RRs
* 4025 - A Method for Storing IPsec Keying Material in DNS
* 403{3,4,5} - DNSSEC + validation functions
@@ -179,11 +185,18 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
* 7871 - EDNS0 Client Subnet
* 7873 - Domain Name System (DNS) Cookies
* 8080 - EdDSA for DNSSEC
* 8490 - DNS Stateful Operations
* 8499 - DNS Terminology
* 8659 - DNS Certification Authority Authorization (CAA) Resource Record
* 8777 - DNS Reverse IP Automatic Multicast Tunneling (AMT) Discovery
* 8914 - Extended DNS Errors
* 8976 - Message Digest for DNS Zones (ZONEMD RR)
* 9460 - Service Binding and Parameter Specification via the DNS
* 9461 - Service Binding Mapping for DNS Servers
* 9462 - Discovery of Designated Resolvers
* 9460 - SVCB and HTTPS Records
* 9606 - DNS Resolver Information
* Draft - Compact Denial of Existence in DNSSEC
## Loosely Based Upon

View File

@@ -198,10 +198,12 @@ func IsDomainName(s string) (labels int, ok bool) {
off int
begin int
wasDot bool
escape bool
)
for i := 0; i < len(s); i++ {
switch s[i] {
case '\\':
escape = !escape
if off+1 > lenmsg {
return labels, false
}
@@ -217,6 +219,7 @@ func IsDomainName(s string) (labels int, ok bool) {
wasDot = false
case '.':
escape = false
if i == 0 && len(s) > 1 {
// leading dots are not legal except for the root zone
return labels, false
@@ -243,10 +246,13 @@ func IsDomainName(s string) (labels int, ok bool) {
labels++
begin = i + 1
default:
escape = false
wasDot = false
}
}
if escape {
return labels, false
}
return labels, true
}

View File

@@ -250,14 +250,6 @@ func (d *DS) ToCDS() *CDS {
// zero, it is used as-is, otherwise the TTL of the RRset is used as the
// OrigTTL.
func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
if k == nil {
return ErrPrivKey
}
// s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
return ErrKey
}
h0 := rrset[0].Header()
rr.Hdr.Rrtype = TypeRRSIG
rr.Hdr.Name = h0.Name
@@ -272,6 +264,18 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
rr.Labels-- // wildcard, remove from label count
}
return rr.signAsIs(k, rrset)
}
func (rr *RRSIG) signAsIs(k crypto.Signer, rrset []RR) error {
if k == nil {
return ErrPrivKey
}
// s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
return ErrKey
}
sigwire := new(rrsigWireFmt)
sigwire.TypeCovered = rr.TypeCovered
sigwire.Algorithm = rr.Algorithm
@@ -370,9 +374,12 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
if rr.Algorithm != k.Algorithm {
return ErrKey
}
if !strings.EqualFold(rr.SignerName, k.Hdr.Name) {
signerName := CanonicalName(rr.SignerName)
if !equal(signerName, k.Hdr.Name) {
return ErrKey
}
if k.Protocol != 3 {
return ErrKey
}
@@ -384,9 +391,18 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
}
// IsRRset checked that we have at least one RR and that the RRs in
// the set have consistent type, class, and name. Also check that type and
// class matches the RRSIG record.
if h0 := rrset[0].Header(); h0.Class != rr.Hdr.Class || h0.Rrtype != rr.TypeCovered {
// the set have consistent type, class, and name. Also check that type,
// class and name matches the RRSIG record.
// Also checks RFC 4035 5.3.1 the number of labels in the RRset owner
// name MUST be greater than or equal to the value in the RRSIG RR's Labels field.
// RFC 4035 5.3.1 Signer's Name MUST be the name of the zone that [contains the RRset].
// Since we don't have SOA info, checking suffix may be the best we can do...?
if h0 := rrset[0].Header(); h0.Class != rr.Hdr.Class ||
h0.Rrtype != rr.TypeCovered ||
uint8(CountLabel(h0.Name)) < rr.Labels ||
!equal(h0.Name, rr.Hdr.Name) ||
!strings.HasSuffix(CanonicalName(h0.Name), signerName) {
return ErrRRset
}
@@ -400,7 +416,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
sigwire.Expiration = rr.Expiration
sigwire.Inception = rr.Inception
sigwire.KeyTag = rr.KeyTag
sigwire.SignerName = CanonicalName(rr.SignerName)
sigwire.SignerName = signerName
// Create the desired binary blob
signeddata := make([]byte, DefaultMsgSize)
n, err := packSigWire(sigwire, signeddata)

View File

@@ -160,7 +160,7 @@ func parseKey(r io.Reader, file string) (map[string]string, error) {
k = l.token
case zValue:
if k == "" {
return nil, &ParseError{file, "no private key seen", l}
return nil, &ParseError{file: file, err: "no private key seen", lex: l}
}
m[strings.ToLower(k)] = l.token

157
vendor/github.com/miekg/dns/edns.go generated vendored
View File

@@ -27,6 +27,7 @@ const (
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (See RFC 6891)
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (See RFC 6891)
_DO = 1 << 15 // DNSSEC OK
_CO = 1 << 14 // Compact Answers OK
)
// makeDataOpt is used to unpack the EDNS0 option(s) from a message.
@@ -58,7 +59,7 @@ func makeDataOpt(code uint16) EDNS0 {
case EDNS0EDE:
return new(EDNS0_EDE)
case EDNS0ESU:
return &EDNS0_ESU{Code: EDNS0ESU}
return new(EDNS0_ESU)
default:
e := new(EDNS0_LOCAL)
e.Code = code
@@ -66,8 +67,7 @@ func makeDataOpt(code uint16) EDNS0 {
}
}
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
// See RFC 6891.
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information. See RFC 6891.
type OPT struct {
Hdr RR_Header
Option []EDNS0 `dns:"opt"`
@@ -76,7 +76,11 @@ type OPT struct {
func (rr *OPT) String() string {
s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
if rr.Do() {
s += "flags: do; "
if rr.Co() {
s += "flags: do, co; "
} else {
s += "flags: do; "
}
} else {
s += "flags:; "
}
@@ -144,8 +148,6 @@ func (*OPT) parse(c *zlexer, origin string) *ParseError {
func (rr *OPT) isDuplicate(r2 RR) bool { return false }
// return the old value -> delete SetVersion?
// Version returns the EDNS version used. Only zero is defined.
func (rr *OPT) Version() uint8 {
return uint8(rr.Hdr.Ttl & 0x00FF0000 >> 16)
@@ -198,14 +200,34 @@ func (rr *OPT) SetDo(do ...bool) {
}
}
// Z returns the Z part of the OPT RR as a uint16 with only the 15 least significant bits used.
func (rr *OPT) Z() uint16 {
return uint16(rr.Hdr.Ttl & 0x7FFF)
// Co returns the value of the CO (Compact Answers OK) bit.
func (rr *OPT) Co() bool {
return rr.Hdr.Ttl&_CO == _CO
}
// SetZ sets the Z part of the OPT RR, note only the 15 least significant bits of z are used.
// SetCo sets the CO (Compact Answers OK) bit.
// If we pass an argument, set the CO bit to that value.
// It is possible to pass 2 or more arguments, but they will be ignored.
func (rr *OPT) SetCo(co ...bool) {
if len(co) == 1 {
if co[0] {
rr.Hdr.Ttl |= _CO
} else {
rr.Hdr.Ttl &^= _CO
}
} else {
rr.Hdr.Ttl |= _CO
}
}
// Z returns the Z part of the OPT RR as a uint16 with only the 14 least significant bits used.
func (rr *OPT) Z() uint16 {
return uint16(rr.Hdr.Ttl & 0x3FFF)
}
// SetZ sets the Z part of the OPT RR, note only the 14 least significant bits of z are used.
func (rr *OPT) SetZ(z uint16) {
rr.Hdr.Ttl = rr.Hdr.Ttl&^0x7FFF | uint32(z&0x7FFF)
rr.Hdr.Ttl = rr.Hdr.Ttl&^0x3FFF | uint32(z&0x3FFF)
}
// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to it.
@@ -236,8 +258,8 @@ type EDNS0 interface {
// e.Nsid = "AA"
// o.Option = append(o.Option, e)
type EDNS0_NSID struct {
Code uint16 // Always EDNS0NSID
Nsid string // This string needs to be hex encoded
Code uint16 // always EDNS0NSID
Nsid string // string needs to be hex encoded
}
func (e *EDNS0_NSID) pack() ([]byte, error) {
@@ -275,7 +297,7 @@ func (e *EDNS0_NSID) copy() EDNS0 { return &EDNS0_NSID{e.Code, e.Nsid}
// When packing it will apply SourceNetmask. If you need more advanced logic,
// patches welcome and good luck.
type EDNS0_SUBNET struct {
Code uint16 // Always EDNS0SUBNET
Code uint16 // always EDNS0SUBNET
Family uint16 // 1 for IP, 2 for IP6
SourceNetmask uint8
SourceScope uint8
@@ -295,30 +317,30 @@ func (e *EDNS0_SUBNET) pack() ([]byte, error) {
// "dig" sets AddressFamily to 0 if SourceNetmask is also 0
// We might don't need to complain either
if e.SourceNetmask != 0 {
return nil, errors.New("dns: bad address family")
return nil, errors.New("bad address family")
}
case 1:
if e.SourceNetmask > net.IPv4len*8 {
return nil, errors.New("dns: bad netmask")
return nil, errors.New("bad netmask")
}
if len(e.Address.To4()) != net.IPv4len {
return nil, errors.New("dns: bad address")
return nil, errors.New("bad address")
}
ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
case 2:
if e.SourceNetmask > net.IPv6len*8 {
return nil, errors.New("dns: bad netmask")
return nil, errors.New("bad netmask")
}
if len(e.Address) != net.IPv6len {
return nil, errors.New("dns: bad address")
return nil, errors.New("bad address")
}
ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
b = append(b, ip[:needLength]...)
default:
return nil, errors.New("dns: bad address family")
return nil, errors.New("bad address family")
}
return b, nil
}
@@ -335,25 +357,25 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error {
// "dig" sets AddressFamily to 0 if SourceNetmask is also 0
// It's okay to accept such a packet
if e.SourceNetmask != 0 {
return errors.New("dns: bad address family")
return errors.New("bad address family")
}
e.Address = net.IPv4(0, 0, 0, 0)
case 1:
if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
return errors.New("dns: bad netmask")
return errors.New("bad netmask")
}
addr := make(net.IP, net.IPv4len)
copy(addr, b[4:])
e.Address = addr.To16()
case 2:
if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
return errors.New("dns: bad netmask")
return errors.New("bad netmask")
}
addr := make(net.IP, net.IPv6len)
copy(addr, b[4:])
e.Address = addr
default:
return errors.New("dns: bad address family")
return errors.New("bad address family")
}
return nil
}
@@ -399,8 +421,8 @@ func (e *EDNS0_SUBNET) copy() EDNS0 {
//
// There is no guarantee that the Cookie string has a specific length.
type EDNS0_COOKIE struct {
Code uint16 // Always EDNS0COOKIE
Cookie string // Hex-encoded cookie data
Code uint16 // always EDNS0COOKIE
Cookie string // hex encoded cookie data
}
func (e *EDNS0_COOKIE) pack() ([]byte, error) {
@@ -430,7 +452,7 @@ func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.C
// e.Lease = 120 // in seconds
// o.Option = append(o.Option, e)
type EDNS0_UL struct {
Code uint16 // Always EDNS0UL
Code uint16 // always EDNS0UL
Lease uint32
KeyLease uint32
}
@@ -469,7 +491,7 @@ func (e *EDNS0_UL) unpack(b []byte) error {
// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
// Implemented for completeness, as the EDNS0 type code is assigned.
type EDNS0_LLQ struct {
Code uint16 // Always EDNS0LLQ
Code uint16 // always EDNS0LLQ
Version uint16
Opcode uint16
Error uint16
@@ -515,7 +537,7 @@ func (e *EDNS0_LLQ) copy() EDNS0 {
// EDNS0_DAU implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
type EDNS0_DAU struct {
Code uint16 // Always EDNS0DAU
Code uint16 // always EDNS0DAU
AlgCode []uint8
}
@@ -539,7 +561,7 @@ func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} }
// EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
type EDNS0_DHU struct {
Code uint16 // Always EDNS0DHU
Code uint16 // always EDNS0DHU
AlgCode []uint8
}
@@ -563,7 +585,7 @@ func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} }
// EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
type EDNS0_N3U struct {
Code uint16 // Always EDNS0N3U
Code uint16 // always EDNS0N3U
AlgCode []uint8
}
@@ -588,7 +610,7 @@ func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
// EDNS0_EXPIRE implements the EDNS0 option as described in RFC 7314.
type EDNS0_EXPIRE struct {
Code uint16 // Always EDNS0EXPIRE
Code uint16 // always EDNS0EXPIRE
Expire uint32
Empty bool // Empty is used to signal an empty Expire option in a backwards compatible way, it's not used on the wire.
}
@@ -668,7 +690,7 @@ func (e *EDNS0_LOCAL) unpack(b []byte) error {
// EDNS0_TCP_KEEPALIVE is an EDNS0 option that instructs the server to keep
// the TCP connection alive. See RFC 7828.
type EDNS0_TCP_KEEPALIVE struct {
Code uint16 // Always EDNSTCPKEEPALIVE
Code uint16 // always EDNSTCPKEEPALIVE
// Timeout is an idle timeout value for the TCP connection, specified in
// units of 100 milliseconds, encoded in network byte order. If set to 0,
@@ -698,7 +720,7 @@ func (e *EDNS0_TCP_KEEPALIVE) unpack(b []byte) error {
case 2:
e.Timeout = binary.BigEndian.Uint16(b)
default:
return fmt.Errorf("dns: length mismatch, want 0/2 but got %d", len(b))
return fmt.Errorf("length mismatch, want 0/2 but got %d", len(b))
}
return nil
}
@@ -756,36 +778,48 @@ const (
ExtendedErrorCodeNoReachableAuthority
ExtendedErrorCodeNetworkError
ExtendedErrorCodeInvalidData
ExtendedErrorCodeSignatureExpiredBeforeValid
ExtendedErrorCodeTooEarly
ExtendedErrorCodeUnsupportedNSEC3IterValue
ExtendedErrorCodeUnableToConformToPolicy
ExtendedErrorCodeSynthesized
ExtendedErrorCodeInvalidQueryType
)
// ExtendedErrorCodeToString maps extended error info codes to a human readable
// description.
var ExtendedErrorCodeToString = map[uint16]string{
ExtendedErrorCodeOther: "Other",
ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "Unsupported DNSKEY Algorithm",
ExtendedErrorCodeUnsupportedDSDigestType: "Unsupported DS Digest Type",
ExtendedErrorCodeStaleAnswer: "Stale Answer",
ExtendedErrorCodeForgedAnswer: "Forged Answer",
ExtendedErrorCodeDNSSECIndeterminate: "DNSSEC Indeterminate",
ExtendedErrorCodeDNSBogus: "DNSSEC Bogus",
ExtendedErrorCodeSignatureExpired: "Signature Expired",
ExtendedErrorCodeSignatureNotYetValid: "Signature Not Yet Valid",
ExtendedErrorCodeDNSKEYMissing: "DNSKEY Missing",
ExtendedErrorCodeRRSIGsMissing: "RRSIGs Missing",
ExtendedErrorCodeNoZoneKeyBitSet: "No Zone Key Bit Set",
ExtendedErrorCodeNSECMissing: "NSEC Missing",
ExtendedErrorCodeCachedError: "Cached Error",
ExtendedErrorCodeNotReady: "Not Ready",
ExtendedErrorCodeBlocked: "Blocked",
ExtendedErrorCodeCensored: "Censored",
ExtendedErrorCodeFiltered: "Filtered",
ExtendedErrorCodeProhibited: "Prohibited",
ExtendedErrorCodeStaleNXDOMAINAnswer: "Stale NXDOMAIN Answer",
ExtendedErrorCodeNotAuthoritative: "Not Authoritative",
ExtendedErrorCodeNotSupported: "Not Supported",
ExtendedErrorCodeNoReachableAuthority: "No Reachable Authority",
ExtendedErrorCodeNetworkError: "Network Error",
ExtendedErrorCodeInvalidData: "Invalid Data",
ExtendedErrorCodeOther: "Other",
ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "Unsupported DNSKEY Algorithm",
ExtendedErrorCodeUnsupportedDSDigestType: "Unsupported DS Digest Type",
ExtendedErrorCodeStaleAnswer: "Stale Answer",
ExtendedErrorCodeForgedAnswer: "Forged Answer",
ExtendedErrorCodeDNSSECIndeterminate: "DNSSEC Indeterminate",
ExtendedErrorCodeDNSBogus: "DNSSEC Bogus",
ExtendedErrorCodeSignatureExpired: "Signature Expired",
ExtendedErrorCodeSignatureNotYetValid: "Signature Not Yet Valid",
ExtendedErrorCodeDNSKEYMissing: "DNSKEY Missing",
ExtendedErrorCodeRRSIGsMissing: "RRSIGs Missing",
ExtendedErrorCodeNoZoneKeyBitSet: "No Zone Key Bit Set",
ExtendedErrorCodeNSECMissing: "NSEC Missing",
ExtendedErrorCodeCachedError: "Cached Error",
ExtendedErrorCodeNotReady: "Not Ready",
ExtendedErrorCodeBlocked: "Blocked",
ExtendedErrorCodeCensored: "Censored",
ExtendedErrorCodeFiltered: "Filtered",
ExtendedErrorCodeProhibited: "Prohibited",
ExtendedErrorCodeStaleNXDOMAINAnswer: "Stale NXDOMAIN Answer",
ExtendedErrorCodeNotAuthoritative: "Not Authoritative",
ExtendedErrorCodeNotSupported: "Not Supported",
ExtendedErrorCodeNoReachableAuthority: "No Reachable Authority",
ExtendedErrorCodeNetworkError: "Network Error",
ExtendedErrorCodeInvalidData: "Invalid Data",
ExtendedErrorCodeSignatureExpiredBeforeValid: "Signature Expired Before Valid",
ExtendedErrorCodeTooEarly: "Too Early",
ExtendedErrorCodeUnsupportedNSEC3IterValue: "Unsupported NSEC3 Iterations Value",
ExtendedErrorCodeUnableToConformToPolicy: "Unable To Conform To Policy",
ExtendedErrorCodeSynthesized: "Synthesized",
ExtendedErrorCodeInvalidQueryType: "Invalid Query Type",
}
// StringToExtendedErrorCode is a map from human readable descriptions to
@@ -827,13 +861,12 @@ func (e *EDNS0_EDE) unpack(b []byte) error {
return nil
}
// The EDNS0_ESU option for ENUM Source-URI Extension
// The EDNS0_ESU option for ENUM Source-URI Extension.
type EDNS0_ESU struct {
Code uint16
Code uint16 // always EDNS0ESU
Uri string
}
// Option implements the EDNS0 interface.
func (e *EDNS0_ESU) Option() uint16 { return EDNS0ESU }
func (e *EDNS0_ESU) String() string { return e.Uri }
func (e *EDNS0_ESU) copy() EDNS0 { return &EDNS0_ESU{e.Code, e.Uri} }

View File

@@ -116,7 +116,7 @@ func (r *generateReader) parseError(msg string, end int) *ParseError {
l.token = r.s[r.si-1 : end]
l.column += r.si // l.column starts one zBLANK before r.s
return &ParseError{r.file, msg, l}
return &ParseError{file: r.file, err: msg, lex: l}
}
func (r *generateReader) Read(p []byte) (int, error) {

View File

@@ -3,9 +3,15 @@
package dns
import "net"
import (
"fmt"
"net"
)
const supportsReusePort = false
const (
supportsReusePort = false
supportsReuseAddr = false
)
func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) {
if reuseport || reuseaddr {
@@ -15,8 +21,6 @@ func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, e
return net.Listen(network, addr)
}
const supportsReuseAddr = false
func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, error) {
if reuseport || reuseaddr {
// TODO(tmthrgd): return an error?
@@ -24,3 +28,13 @@ func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn,
return net.ListenPacket(network, addr)
}
// this is just for test compatibility
func checkReuseport(fd uintptr) (bool, error) {
return false, fmt.Errorf("not supported")
}
// this is just for test compatibility
func checkReuseaddr(fd uintptr) (bool, error) {
return false, fmt.Errorf("not supported")
}

View File

@@ -39,10 +39,40 @@ func reuseaddrControl(network, address string, c syscall.RawConn) error {
return opErr
}
func reuseaddrandportControl(network, address string, c syscall.RawConn) error {
err := reuseaddrControl(network, address, c)
if err != nil {
return err
}
return reuseportControl(network, address, c)
}
// this is just for test compatibility
func checkReuseport(fd uintptr) (bool, error) {
v, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT)
if err != nil {
return false, err
}
return v == 1, nil
}
// this is just for test compatibility
func checkReuseaddr(fd uintptr) (bool, error) {
v, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR)
if err != nil {
return false, err
}
return v == 1, nil
}
func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) {
var lc net.ListenConfig
switch {
case reuseaddr && reuseport:
lc.Control = reuseaddrandportControl
case reuseport:
lc.Control = reuseportControl
case reuseaddr:
@@ -56,6 +86,7 @@ func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn,
var lc net.ListenConfig
switch {
case reuseaddr && reuseport:
lc.Control = reuseaddrandportControl
case reuseport:
lc.Control = reuseportControl
case reuseaddr:

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