mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-25 06:29:15 -05:00
Merge remote-tracking branch 'origin/main' into feature/guest-links
This commit is contained in:
@@ -3,5 +3,3 @@ module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
|
||||
go 1.23.4
|
||||
|
||||
require github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a // go-xgettext
|
||||
|
||||
require github.com/jessevdk/go-flags v1.6.1 // indirect
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# The test runner source for UI tests
|
||||
WEB_COMMITID=6818f0d09b145720ef31737b84284239545d1eb8
|
||||
WEB_COMMITID=909f9915b39cb736467d02a9afdc7e9bfa99de53
|
||||
WEB_BRANCH=main
|
||||
|
||||
|
||||
+1
-1
@@ -371,7 +371,7 @@ config = {
|
||||
"skip": False,
|
||||
"suites": [
|
||||
"user-settings",
|
||||
"file-action",
|
||||
#"fileaction",
|
||||
"embed",
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,5 +1,44 @@
|
||||
# Changelog
|
||||
|
||||
## [6.2.0](https://github.com/opencloud-eu/opencloud/releases/tag/v6.2.0) - 2026-05-11
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
@JammingBen, @ScharfViktor, @Sweeistaken, @aduffeck, @dragonchaser, @dschmidt, @fschade, @pedropintosilva, @rhafer, @schweigisito
|
||||
|
||||
### 📈 Enhancement
|
||||
|
||||
- feat: enable EnableRemoteLinkPicker WOPI flag for Collabora Online [[#2663](https://github.com/opencloud-eu/opencloud/pull/2663)]
|
||||
- feat(kql): support dotted keys in property restrictions [[#2632](https://github.com/opencloud-eu/opencloud/pull/2632)]
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Set new defaults for caches and stores [[#2702](https://github.com/opencloud-eu/opencloud/pull/2702)]
|
||||
- fix: remove typo in error message [[#2701](https://github.com/opencloud-eu/opencloud/pull/2701)]
|
||||
- fix(search): preserve value case for non-lowercased bleve fields [[#2633](https://github.com/opencloud-eu/opencloud/pull/2633)]
|
||||
- More graceful shutdown fixes [[#2690](https://github.com/opencloud-eu/opencloud/pull/2690)]
|
||||
- Hotfix for https://github.com/opencloud-eu/opencloud/issues/2282 [[#2631](https://github.com/opencloud-eu/opencloud/pull/2631)]
|
||||
- fix(search): read --force-rescan flag with its registered name [[#2639](https://github.com/opencloud-eu/opencloud/pull/2639)]
|
||||
- fix(search): parse tika xmpDM:duration as a float [[#2638](https://github.com/opencloud-eu/opencloud/pull/2638)]
|
||||
|
||||
### ✅ Tests
|
||||
|
||||
- [api-tests] delete PROPATCH favorite tests [[#2689](https://github.com/opencloud-eu/opencloud/pull/2689)]
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- enhancement: increase display size of graph flow diagram [[#2620](https://github.com/opencloud-eu/opencloud/pull/2620)]
|
||||
|
||||
### 📦️ Dependencies
|
||||
|
||||
- build(deps): bump go.opentelemetry.io/contrib/zpages from 0.67.0 to 0.68.0 [[#2666](https://github.com/opencloud-eu/opencloud/pull/2666)]
|
||||
- build(deps): bump @types/node from 22.19.17 to 25.6.0 in /services/idp [[#2687](https://github.com/opencloud-eu/opencloud/pull/2687)]
|
||||
- build(deps): bump go.opentelemetry.io/otel/exporters/stdout/stdouttrace from 1.42.0 to 1.43.0 [[#2601](https://github.com/opencloud-eu/opencloud/pull/2601)]
|
||||
- build(deps): bump github.com/davidbyttow/govips/v2 from 2.17.0 to 2.18.0 [[#2656](https://github.com/opencloud-eu/opencloud/pull/2656)]
|
||||
- build(deps): bump i18next from 25.10.10 to 26.0.4 in /services/idp [[#2609](https://github.com/opencloud-eu/opencloud/pull/2609)]
|
||||
- build(deps): bump github.com/testcontainers/testcontainers-go/modules/opensearch from 0.41.0 to 0.42.0 [[#2645](https://github.com/opencloud-eu/opencloud/pull/2645)]
|
||||
- build(deps): bump github.com/open-policy-agent/opa from 1.15.1 to 1.15.2 [[#2602](https://github.com/opencloud-eu/opencloud/pull/2602)]
|
||||
|
||||
## [6.1.0](https://github.com/opencloud-eu/opencloud/releases/tag/v6.1.0) - 2026-04-20
|
||||
|
||||
### ❤️ Thanks to all contributors! ❤️
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ COPY --from=generate /opencloud /opencloud
|
||||
WORKDIR /opencloud/opencloud
|
||||
RUN make go-generate build ENABLE_VIPS=true
|
||||
|
||||
FROM alpine:3.20
|
||||
FROM alpine:3.23
|
||||
|
||||
RUN apk add --no-cache attr ca-certificates curl mailcap tree vips && \
|
||||
echo 'hosts: files dns' >| /etc/nsswitch.conf
|
||||
|
||||
@@ -57,10 +57,9 @@ require (
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/nats-io/nats-server/v2 v2.14.0
|
||||
github.com/nats-io/nats.go v1.51.0
|
||||
github.com/oklog/run v1.2.0
|
||||
github.com/olekukonko/tablewriter v1.1.4
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/ginkgo/v2 v2.28.1
|
||||
github.com/onsi/ginkgo/v2 v2.28.3
|
||||
github.com/onsi/gomega v1.40.0
|
||||
github.com/open-policy-agent/opa v1.15.2
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
||||
@@ -106,7 +105,7 @@ require (
|
||||
golang.org/x/crypto v0.50.0
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/image v0.38.0
|
||||
golang.org/x/net v0.52.0
|
||||
golang.org/x/net v0.53.0
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/sync v0.20.0
|
||||
golang.org/x/term v0.42.0
|
||||
@@ -239,14 +238,14 @@ require (
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-tpm v0.9.8 // indirect
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
|
||||
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect
|
||||
github.com/google/renameio/v2 v2.0.2 // indirect
|
||||
github.com/gookit/goutil v0.7.4 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/schema v1.4.1 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
|
||||
github.com/hashicorp/go-hclog v1.6.3 // indirect
|
||||
github.com/hashicorp/go-plugin v1.7.0 // indirect
|
||||
github.com/hashicorp/go-plugin v1.8.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
@@ -288,7 +287,7 @@ require (
|
||||
github.com/minio/crc64nvme v1.1.1 // indirect
|
||||
github.com/minio/highwayhash v1.0.4 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.99 // indirect
|
||||
github.com/minio/minio-go/v7 v7.1.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
@@ -308,6 +307,7 @@ require (
|
||||
github.com/nats-io/nkeys v0.4.15 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/oklog/run v1.2.0 // indirect
|
||||
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||
github.com/olekukonko/errors v1.2.0 // indirect
|
||||
github.com/olekukonko/ll v0.1.6 // indirect
|
||||
@@ -376,6 +376,7 @@ require (
|
||||
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||
github.com/yashtewari/glob-intersection v0.2.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
github.com/zeebo/xxh3 v1.1.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.6.10 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.10 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.6.10 // indirect
|
||||
@@ -388,10 +389,10 @@ require (
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/mod v0.34.0 // indirect
|
||||
golang.org/x/mod v0.35.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
golang.org/x/tools v0.43.0 // indirect
|
||||
golang.org/x/tools v0.44.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d // indirect
|
||||
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
|
||||
|
||||
@@ -576,8 +576,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
|
||||
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg=
|
||||
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/renameio/v2 v2.0.2 h1:qKZs+tfn+arruZZhQ7TKC/ergJunuJicWS6gLDt/dGw=
|
||||
github.com/google/renameio/v2 v2.0.2/go.mod h1:OX+G6WHHpHq3NVj7cAOleLOwJfcQ1s3uUJQCrr78SWo=
|
||||
@@ -626,8 +626,8 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
|
||||
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
|
||||
github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs=
|
||||
github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
@@ -843,8 +843,8 @@ github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clg
|
||||
github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.99 h1:2vH/byrwUkIpFQFOilvTfaUpvAX3fEFhEzO+DR3DlCE=
|
||||
github.com/minio/minio-go/v7 v7.0.99/go.mod h1:EtGNKtlX20iL2yaYnxEigaIvj0G0GwSDnifnG8ClIdw=
|
||||
github.com/minio/minio-go/v7 v7.1.0 h1:QEt5IStDpxgGjEdtOgpiZ5QhmSl3ax7qy61vi2SwHO8=
|
||||
github.com/minio/minio-go/v7 v7.1.0/go.mod h1:Dm7WS1AgLmBa0NcQD6SeJnJf+K/EUW3GR7Ks6olB3OA=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
@@ -935,8 +935,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
|
||||
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
|
||||
github.com/onsi/ginkgo/v2 v2.28.3 h1:4JvMdwtFU0imd8fHx25OJXoDMRexnf8v5NHKYSTTji4=
|
||||
github.com/onsi/ginkgo/v2 v2.28.3/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
@@ -1275,6 +1275,10 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
||||
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
|
||||
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
|
||||
@@ -1397,8 +1401,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1449,8 +1453,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1642,8 +1646,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
||||
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
|
||||
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
|
||||
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:alpine3.22 AS build
|
||||
FROM golang:alpine3.23 AS build
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG VERSION
|
||||
@@ -14,7 +14,7 @@ RUN --mount=type=bind,target=/build,rw \
|
||||
GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH:-amd64}" ; \
|
||||
make -C opencloud/opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
|
||||
|
||||
FROM alpine:3.22
|
||||
FROM alpine:3.23
|
||||
ARG VERSION
|
||||
ARG REVISION
|
||||
ARG TARGETOS
|
||||
|
||||
@@ -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 = "6.1.0+dev"
|
||||
LatestTag = "6.2.0+dev"
|
||||
|
||||
// Date indicates the build date.
|
||||
// This has been removed, it looks like you can only replace static strings with recent go versions
|
||||
|
||||
@@ -627,13 +627,13 @@ type Bundle struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
|
||||
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty" yaml:"type"` // @gotags: yaml:"type"
|
||||
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty" yaml:"extension"` // @gotags: yaml:"extension"
|
||||
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
|
||||
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty" yaml:"settings"` // @gotags: yaml:"settings"
|
||||
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
|
||||
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty"` // @gotags: yaml:"type"
|
||||
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty"` // @gotags: yaml:"extension"
|
||||
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
|
||||
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty"` // @gotags: yaml:"settings"
|
||||
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
|
||||
}
|
||||
|
||||
func (x *Bundle) Reset() {
|
||||
@@ -722,10 +722,10 @@ type Setting struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
|
||||
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
|
||||
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` // @gotags: yaml:"description"
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
|
||||
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
|
||||
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` // @gotags: yaml:"description"
|
||||
// Types that are assignable to Value:
|
||||
//
|
||||
// *Setting_IntValue
|
||||
@@ -736,7 +736,7 @@ type Setting struct {
|
||||
// *Setting_PermissionValue
|
||||
// *Setting_MultiChoiceCollectionValue
|
||||
Value isSetting_Value `protobuf_oneof:"value"`
|
||||
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
|
||||
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
|
||||
}
|
||||
|
||||
func (x *Setting) Reset() {
|
||||
@@ -867,31 +867,31 @@ type isSetting_Value interface {
|
||||
}
|
||||
|
||||
type Setting_IntValue struct {
|
||||
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type Setting_StringValue struct {
|
||||
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type Setting_BoolValue struct {
|
||||
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
type Setting_SingleChoiceValue struct {
|
||||
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof" yaml:"single_choice_value"` // @gotags: yaml:"single_choice_value"
|
||||
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof"` // @gotags: yaml:"single_choice_value"
|
||||
}
|
||||
|
||||
type Setting_MultiChoiceValue struct {
|
||||
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof" yaml:"multi_choice_value"` // @gotags: yaml:"multi_choice_value"
|
||||
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof"` // @gotags: yaml:"multi_choice_value"
|
||||
}
|
||||
|
||||
type Setting_PermissionValue struct {
|
||||
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof" yaml:"permission_value"` // @gotags: yaml:"permission_value"
|
||||
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof"` // @gotags: yaml:"permission_value"
|
||||
}
|
||||
|
||||
type Setting_MultiChoiceCollectionValue struct {
|
||||
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof" yaml:"multi_choice_collection_value"` // @gotags: yaml:"multi_choice_collection_value"
|
||||
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof"` // @gotags: yaml:"multi_choice_collection_value"
|
||||
}
|
||||
|
||||
func (*Setting_IntValue) isSetting_Value() {}
|
||||
@@ -913,11 +913,11 @@ type Int struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty" yaml:"min"` // @gotags: yaml:"min"
|
||||
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty" yaml:"max"` // @gotags: yaml:"max"
|
||||
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty" yaml:"step"` // @gotags: yaml:"step"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
|
||||
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty"` // @gotags: yaml:"min"
|
||||
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` // @gotags: yaml:"max"
|
||||
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty"` // @gotags: yaml:"step"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
|
||||
}
|
||||
|
||||
func (x *Int) Reset() {
|
||||
@@ -992,11 +992,11 @@ type String struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty" yaml:"required"` // @gotags: yaml:"required"
|
||||
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty" yaml:"min_length"` // @gotags: yaml:"min_length"
|
||||
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty" yaml:"max_length"` // @gotags: yaml:"max_length"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
|
||||
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty"` // @gotags: yaml:"required"
|
||||
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` // @gotags: yaml:"min_length"
|
||||
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` // @gotags: yaml:"max_length"
|
||||
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
|
||||
}
|
||||
|
||||
func (x *String) Reset() {
|
||||
@@ -1071,8 +1071,8 @@ type Bool struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty" yaml:"label"` // @gotags: yaml:"label"
|
||||
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` // @gotags: yaml:"label"
|
||||
}
|
||||
|
||||
func (x *Bool) Reset() {
|
||||
@@ -1126,7 +1126,7 @@ type SingleChoiceList struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
|
||||
}
|
||||
|
||||
func (x *SingleChoiceList) Reset() {
|
||||
@@ -1173,7 +1173,7 @@ type MultiChoiceList struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
|
||||
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
|
||||
}
|
||||
|
||||
func (x *MultiChoiceList) Reset() {
|
||||
@@ -1220,9 +1220,9 @@ type ListOption struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
|
||||
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
|
||||
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
|
||||
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
|
||||
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
|
||||
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
|
||||
}
|
||||
|
||||
func (x *ListOption) Reset() {
|
||||
@@ -1283,7 +1283,7 @@ type MultiChoiceCollection struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
|
||||
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
|
||||
}
|
||||
|
||||
func (x *MultiChoiceCollection) Reset() {
|
||||
@@ -1330,10 +1330,10 @@ type MultiChoiceCollectionOption struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
|
||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
|
||||
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty" yaml:"attribute"` // @gotags: yaml:"attribute"
|
||||
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
|
||||
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
|
||||
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
|
||||
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty"` // @gotags: yaml:"attribute"
|
||||
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
|
||||
}
|
||||
|
||||
func (x *MultiChoiceCollectionOption) Reset() {
|
||||
@@ -1474,15 +1474,15 @@ type isMultiChoiceCollectionOptionValue_Option interface {
|
||||
}
|
||||
|
||||
type MultiChoiceCollectionOptionValue_IntValue struct {
|
||||
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type MultiChoiceCollectionOptionValue_StringValue struct {
|
||||
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type MultiChoiceCollectionOptionValue_BoolValue struct {
|
||||
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
func (*MultiChoiceCollectionOptionValue_IntValue) isMultiChoiceCollectionOptionValue_Option() {}
|
||||
@@ -1496,8 +1496,8 @@ type Permission struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty" yaml:"operation"` // @gotags: yaml:"operation"
|
||||
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty" yaml:"constraint"` // @gotags: yaml:"constraint"
|
||||
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty"` // @gotags: yaml:"operation"
|
||||
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty"` // @gotags: yaml:"constraint"
|
||||
}
|
||||
|
||||
func (x *Permission) Reset() {
|
||||
@@ -1552,12 +1552,12 @@ type Value struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// id is the id of the Value. It is generated on saving it.
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
|
||||
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty" yaml:"bundle_id"` // @gotags: yaml:"bundle_id"
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
|
||||
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty"` // @gotags: yaml:"bundle_id"
|
||||
// setting_id is the id of the setting from within its bundle.
|
||||
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty" yaml:"setting_id"` // @gotags: yaml:"setting_id"
|
||||
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty" yaml:"account_uuid"` // @gotags: yaml:"account_uuid"
|
||||
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
|
||||
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty"` // @gotags: yaml:"setting_id"
|
||||
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty"` // @gotags: yaml:"account_uuid"
|
||||
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
|
||||
// Types that are assignable to Value:
|
||||
//
|
||||
// *Value_BoolValue
|
||||
@@ -1682,23 +1682,23 @@ type isValue_Value interface {
|
||||
}
|
||||
|
||||
type Value_BoolValue struct {
|
||||
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
type Value_IntValue struct {
|
||||
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type Value_StringValue struct {
|
||||
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type Value_ListValue struct {
|
||||
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof" yaml:"list_value"` // @gotags: yaml:"list_value"
|
||||
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof"` // @gotags: yaml:"list_value"
|
||||
}
|
||||
|
||||
type Value_CollectionValue struct {
|
||||
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof" yaml:"collection_value"` // @gotags: yaml:"collection_value"
|
||||
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof"` // @gotags: yaml:"collection_value"
|
||||
}
|
||||
|
||||
func (*Value_BoolValue) isValue_Value() {}
|
||||
@@ -1716,7 +1716,7 @@ type ListValue struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
|
||||
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
|
||||
}
|
||||
|
||||
func (x *ListValue) Reset() {
|
||||
@@ -1836,15 +1836,15 @@ type isListOptionValue_Option interface {
|
||||
}
|
||||
|
||||
type ListOptionValue_StringValue struct {
|
||||
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type ListOptionValue_IntValue struct {
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type ListOptionValue_BoolValue struct {
|
||||
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
func (*ListOptionValue_StringValue) isListOptionValue_Option() {}
|
||||
@@ -1858,7 +1858,7 @@ type CollectionValue struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
|
||||
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
|
||||
}
|
||||
|
||||
func (x *CollectionValue) Reset() {
|
||||
@@ -1906,7 +1906,7 @@ type CollectionOption struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// required
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
|
||||
// Types that are assignable to Option:
|
||||
//
|
||||
// *CollectionOption_IntValue
|
||||
@@ -1987,15 +1987,15 @@ type isCollectionOption_Option interface {
|
||||
}
|
||||
|
||||
type CollectionOption_IntValue struct {
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
|
||||
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
|
||||
}
|
||||
|
||||
type CollectionOption_StringValue struct {
|
||||
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
|
||||
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
|
||||
}
|
||||
|
||||
type CollectionOption_BoolValue struct {
|
||||
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
|
||||
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
|
||||
}
|
||||
|
||||
func (*CollectionOption_IntValue) isCollectionOption_Option() {}
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/oklog/run"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/runner"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
@@ -62,7 +62,7 @@ func Server(cfg *config.Config) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
gr := run.Group{}
|
||||
gr := runner.NewGroup()
|
||||
ctx, cancel := context.WithCancel(cmd.Context())
|
||||
|
||||
mtrcs := metrics.New()
|
||||
@@ -132,23 +132,7 @@ func Server(cfg *config.Config) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
gr.Add(func() error {
|
||||
return svc.Run()
|
||||
}, func(err error) {
|
||||
if err == nil {
|
||||
logger.Info().
|
||||
Str("transport", "http").
|
||||
Str("server", cfg.Service.Name).
|
||||
Msg("Shutting down server")
|
||||
} else {
|
||||
logger.Error().Err(err).
|
||||
Str("transport", "http").
|
||||
Str("server", cfg.Service.Name).
|
||||
Msg("Shutting down server")
|
||||
}
|
||||
|
||||
cancel()
|
||||
})
|
||||
gr.Add(runner.NewGoMicroHttpServerRunner(cfg.Service.Name+".http", svc))
|
||||
}
|
||||
|
||||
{
|
||||
@@ -162,13 +146,18 @@ func Server(cfg *config.Config) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
gr.Add(debugServer.ListenAndServe, func(_ error) {
|
||||
_ = debugServer.Shutdown(ctx)
|
||||
cancel()
|
||||
})
|
||||
gr.Add(runner.NewGolangHttpServerRunner(cfg.Service.Name+".debug", debugServer))
|
||||
}
|
||||
|
||||
return gr.Run()
|
||||
grResults := gr.Run(ctx)
|
||||
|
||||
// return the first non-nil error found in the results
|
||||
for _, grResult := range grResults {
|
||||
if grResult.RunnerError != nil {
|
||||
return grResult.RunnerError
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1278,6 +1278,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
|
||||
fileinfo.KeyEnableOwnerTermination: true, // only for collabora
|
||||
fileinfo.KeyEnableInsertRemoteImage: true,
|
||||
fileinfo.KeyEnableInsertRemoteFile: true,
|
||||
fileinfo.KeyEnableRemoteLinkPicker: true,
|
||||
fileinfo.KeySupportsExtendedLockLength: true,
|
||||
fileinfo.KeySupportsGetLock: true,
|
||||
fileinfo.KeySupportsLocks: true,
|
||||
|
||||
@@ -1802,6 +1802,7 @@ var _ = Describe("FileConnector", func() {
|
||||
PostMessageOrigin: "https://cloud.opencloud.test",
|
||||
EnableInsertRemoteImage: true,
|
||||
EnableInsertRemoteFile: true,
|
||||
EnableRemoteLinkPicker: true,
|
||||
IsAnonymousUser: true,
|
||||
}
|
||||
|
||||
@@ -1995,6 +1996,7 @@ var _ = Describe("FileConnector", func() {
|
||||
PostMessageOrigin: "https://cloud.opencloud.test",
|
||||
EnableInsertRemoteImage: true,
|
||||
EnableInsertRemoteFile: true,
|
||||
EnableRemoteLinkPicker: true,
|
||||
IsAdminUser: true,
|
||||
UserExtraInfo: &fileinfo.UserExtraInfo{
|
||||
Mail: "shaft@example.com",
|
||||
|
||||
@@ -46,6 +46,8 @@ type Collabora struct {
|
||||
EnableInsertRemoteImage bool `json:"EnableInsertRemoteImage,omitempty"`
|
||||
// If set to true, this will enable the insertion of remote files chosen from the WOPI storage. A UI_InsertFile postMessage will be sent to the WOPI host to request the UI to select the file. This enables multimedia insertion and document comparison features.
|
||||
EnableInsertRemoteFile bool `json:"EnableInsertRemoteFile,omitempty"`
|
||||
// If set to true, this will enable picking a link to a remote file from the WOPI storage. A UI_PickLink postMessage will be sent to the WOPI host to request the UI to select the file. The host is expected to reply with an Action_InsertLink message carrying the file URL.
|
||||
EnableRemoteLinkPicker bool `json:"EnableRemoteLinkPicker,omitempty"`
|
||||
// If set to true, this will disable the insertion of image chosen from the local device. If EnableInsertRemoteImage is not set to true, then inserting images files is not possible.
|
||||
DisableInsertLocalImage bool `json:"DisableInsertLocalImage,omitempty"`
|
||||
// If set to true, hides the print option from the file menu bar in the UI.
|
||||
@@ -124,6 +126,8 @@ func (cinfo *Collabora) SetProperties(props map[string]any) {
|
||||
cinfo.EnableInsertRemoteImage = value.(bool)
|
||||
case KeyEnableInsertRemoteFile:
|
||||
cinfo.EnableInsertRemoteFile = value.(bool)
|
||||
case KeyEnableRemoteLinkPicker:
|
||||
cinfo.EnableRemoteLinkPicker = value.(bool)
|
||||
case KeyDisableInsertLocalImage:
|
||||
cinfo.DisableInsertLocalImage = value.(bool)
|
||||
case KeyHidePrintOption:
|
||||
|
||||
@@ -104,6 +104,7 @@ const (
|
||||
|
||||
KeyEnableInsertRemoteImage = "EnableInsertRemoteImage"
|
||||
KeyEnableInsertRemoteFile = "EnableInsertRemoteFile"
|
||||
KeyEnableRemoteLinkPicker = "EnableRemoteLinkPicker"
|
||||
KeyDisableInsertLocalImage = "DisableInsertLocalImage"
|
||||
KeyHidePrintOption = "HidePrintOption"
|
||||
KeyHideSaveOption = "HideSaveOption"
|
||||
|
||||
@@ -63,7 +63,7 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string
|
||||
"tags": true,
|
||||
"archivers": archivers,
|
||||
"app_providers": appProviders,
|
||||
"favorites": true,
|
||||
"favorites": false,
|
||||
"full_text_search": cfg.FullTextSearch,
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package svc
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"slices"
|
||||
@@ -91,6 +92,10 @@ type ListPermissionsQueryOptions struct {
|
||||
|
||||
// NewDriveItemPermissionsService creates a new DriveItemPermissionsService
|
||||
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache cache.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) {
|
||||
publicBaseURL, err := url.Parse(config.Spaces.WebDavBase)
|
||||
if err != nil {
|
||||
return DriveItemPermissionsService{}, fmt.Errorf("could not parse graph.spaces.webdav_base: %w", err)
|
||||
}
|
||||
return DriveItemPermissionsService{
|
||||
BaseGraphService: BaseGraphService{
|
||||
logger: &log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemService").Logger()},
|
||||
@@ -98,6 +103,7 @@ func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Sele
|
||||
identityCache: identityCache,
|
||||
config: config,
|
||||
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(config.UnifiedRoles.AvailableRoles...)),
|
||||
publicBaseURL: publicBaseURL,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -401,7 +407,7 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
|
||||
|
||||
driveItems := make(driveItemsByResourceID, 1)
|
||||
// we can use the statResponse to build the drive item before fetching the shares
|
||||
item, err := cs3ResourceToDriveItem(s.logger, statResponse.GetInfo())
|
||||
item, err := cs3ResourceToDriveItem(s.logger, s.publicBaseURL, statResponse.GetInfo())
|
||||
if err != nil {
|
||||
return collectionOfPermissions, err
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ type BaseGraphService struct {
|
||||
identityCache cache.IdentityCache
|
||||
config *config.Config
|
||||
availableRoles []*libregraph.UnifiedRoleDefinition
|
||||
publicBaseURL *url.URL
|
||||
}
|
||||
|
||||
func (g BaseGraphService) getDriveItem(ctx context.Context, ref *storageprovider.Reference) (*libregraph.DriveItem, error) {
|
||||
@@ -65,7 +66,7 @@ func (g BaseGraphService) getDriveItem(ctx context.Context, ref *storageprovider
|
||||
refStr, _ := storagespace.FormatReference(ref)
|
||||
return nil, fmt.Errorf("could not stat %s: %s", refStr, res.GetStatus().GetMessage())
|
||||
}
|
||||
return cs3ResourceToDriveItem(g.logger, res.GetInfo())
|
||||
return cs3ResourceToDriveItem(g.logger, g.publicBaseURL, res.GetInfo())
|
||||
}
|
||||
|
||||
func (g BaseGraphService) CS3ReceivedSharesToDriveItems(ctx context.Context, receivedShares []*collaboration.ReceivedShare) ([]libregraph.DriveItem, error) {
|
||||
|
||||
@@ -204,7 +204,7 @@ func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
files, err := formatDriveItems(g.logger, lRes.GetInfos())
|
||||
files, err := formatDriveItems(g.logger, g.publicBaseURL, lRes.GetInfos())
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("error encoding response as json")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
@@ -269,7 +269,7 @@ func (g Graph) GetDriveItem(w http.ResponseWriter, r *http.Request) {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.GetStatus().GetMessage())
|
||||
return
|
||||
}
|
||||
driveItem, err := cs3ResourceToDriveItem(g.logger, res.GetInfo())
|
||||
driveItem, err := cs3ResourceToDriveItem(g.logger, g.publicBaseURL, res.GetInfo())
|
||||
if err != nil {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
@@ -337,7 +337,7 @@ func (g Graph) GetDriveItemChildren(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
files, err := formatDriveItems(g.logger, res.GetInfos())
|
||||
files, err := formatDriveItems(g.logger, g.publicBaseURL, res.GetInfos())
|
||||
if err != nil {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
@@ -385,10 +385,10 @@ func (g Graph) getRemoteItem(ctx context.Context, root *storageprovider.Resource
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func formatDriveItems(logger *log.Logger, mds []*storageprovider.ResourceInfo) ([]*libregraph.DriveItem, error) {
|
||||
func formatDriveItems(logger *log.Logger, publicBaseURL *url.URL, mds []*storageprovider.ResourceInfo) ([]*libregraph.DriveItem, error) {
|
||||
responses := make([]*libregraph.DriveItem, 0, len(mds))
|
||||
for i := range mds {
|
||||
res, err := cs3ResourceToDriveItem(logger, mds[i])
|
||||
res, err := cs3ResourceToDriveItem(logger, publicBaseURL, mds[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -402,7 +402,7 @@ func cs3TimestampToTime(t *types.Timestamp) time.Time {
|
||||
return time.Unix(int64(t.GetSeconds()), int64(t.GetNanos()))
|
||||
}
|
||||
|
||||
func cs3ResourceToDriveItem(logger *log.Logger, res *storageprovider.ResourceInfo) (*libregraph.DriveItem, error) {
|
||||
func cs3ResourceToDriveItem(logger *log.Logger, publicBaseURL *url.URL, res *storageprovider.ResourceInfo) (*libregraph.DriveItem, error) {
|
||||
size := new(int64)
|
||||
*size = int64(res.GetSize()) // TODO lurking overflow: make size of libregraph drive item use uint64
|
||||
|
||||
@@ -411,6 +411,10 @@ func cs3ResourceToDriveItem(logger *log.Logger, res *storageprovider.ResourceInf
|
||||
Size: size,
|
||||
}
|
||||
|
||||
webURL := *publicBaseURL
|
||||
webURL.Path = path.Join(webURL.Path, "f", storagespace.FormatResourceID(res.GetId()))
|
||||
driveItem.WebUrl = libregraph.PtrString(webURL.String())
|
||||
|
||||
if name := path.Base(res.GetPath()); name != "" {
|
||||
driveItem.Name = &name
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
)
|
||||
|
||||
func TestCS3ResourceToDriveItemPopulatesWebUrl(t *testing.T) {
|
||||
logger := log.NewLogger()
|
||||
res := &provider.ResourceInfo{
|
||||
Id: &provider.ResourceId{
|
||||
StorageId: "storage-1",
|
||||
SpaceId: "space-1",
|
||||
OpaqueId: "item-1",
|
||||
},
|
||||
Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER,
|
||||
}
|
||||
|
||||
t.Run("public base URL without path", func(t *testing.T) {
|
||||
base, err := url.Parse("https://example.com")
|
||||
require.NoError(t, err)
|
||||
|
||||
item, err := cs3ResourceToDriveItem(&logger, base, res)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, item.WebUrl)
|
||||
assert.Equal(t, "https://example.com/f/storage-1$space-1%21item-1", *item.WebUrl)
|
||||
})
|
||||
|
||||
t.Run("public base URL with path prefix", func(t *testing.T) {
|
||||
base, err := url.Parse("https://example.com/cloud")
|
||||
require.NoError(t, err)
|
||||
|
||||
item, err := cs3ResourceToDriveItem(&logger, base, res)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, item.WebUrl)
|
||||
assert.Equal(t, "https://example.com/cloud/f/storage-1$space-1%21item-1", *item.WebUrl)
|
||||
})
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func (g Graph) FollowDriveItem(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
driveItem, err := cs3ResourceToDriveItem(g.logger, statRes.GetInfo())
|
||||
driveItem, err := cs3ResourceToDriveItem(g.logger, g.publicBaseURL, statRes.GetInfo())
|
||||
if err != nil {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -154,12 +155,18 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
cache.IdentityCacheWithGroupsTTL(time.Duration(options.Config.Spaces.GroupsCacheTTL)),
|
||||
)
|
||||
|
||||
publicBaseURL, err := url.Parse(options.Config.Spaces.WebDavBase)
|
||||
if err != nil {
|
||||
return Graph{}, fmt.Errorf("could not parse graph.spaces.webdav_base: %w", err)
|
||||
}
|
||||
|
||||
baseGraphService := BaseGraphService{
|
||||
logger: &options.Logger,
|
||||
identityCache: identityCache,
|
||||
gatewaySelector: options.GatewaySelector,
|
||||
config: options.Config,
|
||||
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(options.Config.UnifiedRoles.AvailableRoles...)),
|
||||
publicBaseURL: publicBaseURL,
|
||||
}
|
||||
|
||||
drivesDriveItemService, err := NewDrivesDriveItemService(options.Logger, options.GatewaySelector)
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/userstate"
|
||||
ocsettingssvc "github.com/opencloud-eu/opencloud/services/settings/pkg/service/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
)
|
||||
|
||||
@@ -421,10 +420,10 @@ func (g Graph) PostUser(w http.ResponseWriter, r *http.Request) {
|
||||
// to all new users for now, as create Account request does not have any role field
|
||||
if _, err = g.roleService.AssignRoleToUser(r.Context(), &settingssvc.AssignRoleToUserRequest{
|
||||
AccountUuid: *u.Id,
|
||||
RoleId: ocsettingssvc.BundleUUIDRoleUser,
|
||||
RoleId: defaults.BundleUUIDRoleUser,
|
||||
}); err != nil {
|
||||
// log as error, admin eventually needs to do something
|
||||
logger.Error().Err(err).Str("id", *u.Id).Str("role", ocsettingssvc.BundleUUIDRoleUser).Msg("could not create user: role assignment failed")
|
||||
logger.Error().Err(err).Str("id", *u.Id).Str("role", defaults.BundleUUIDRoleUser).Msg("could not create user: role assignment failed")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "role assignment failed")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ func (_c *UserBackend_Authenticate_Call) RunAndReturn(run func(ctx context.Conte
|
||||
}
|
||||
|
||||
// CreateUserFromClaims provides a mock function for the type UserBackend
|
||||
func (_mock *UserBackend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error) {
|
||||
func (_mock *UserBackend) CreateUserFromClaims(ctx context.Context, claims map[string]any) (*userv1beta1.User, error) {
|
||||
ret := _mock.Called(ctx, claims)
|
||||
|
||||
if len(ret) == 0 {
|
||||
@@ -128,17 +128,17 @@ func (_mock *UserBackend) CreateUserFromClaims(ctx context.Context, claims map[s
|
||||
|
||||
var r0 *userv1beta1.User
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]interface{}) (*userv1beta1.User, error)); ok {
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]any) (*userv1beta1.User, error)); ok {
|
||||
return returnFunc(ctx, claims)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]interface{}) *userv1beta1.User); ok {
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]any) *userv1beta1.User); ok {
|
||||
r0 = returnFunc(ctx, claims)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*userv1beta1.User)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context, map[string]interface{}) error); ok {
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context, map[string]any) error); ok {
|
||||
r1 = returnFunc(ctx, claims)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -153,20 +153,20 @@ type UserBackend_CreateUserFromClaims_Call struct {
|
||||
|
||||
// CreateUserFromClaims is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - claims map[string]interface{}
|
||||
// - claims map[string]any
|
||||
func (_e *UserBackend_Expecter) CreateUserFromClaims(ctx interface{}, claims interface{}) *UserBackend_CreateUserFromClaims_Call {
|
||||
return &UserBackend_CreateUserFromClaims_Call{Call: _e.mock.On("CreateUserFromClaims", ctx, claims)}
|
||||
}
|
||||
|
||||
func (_c *UserBackend_CreateUserFromClaims_Call) Run(run func(ctx context.Context, claims map[string]interface{})) *UserBackend_CreateUserFromClaims_Call {
|
||||
func (_c *UserBackend_CreateUserFromClaims_Call) Run(run func(ctx context.Context, claims map[string]any)) *UserBackend_CreateUserFromClaims_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
arg0 = args[0].(context.Context)
|
||||
}
|
||||
var arg1 map[string]interface{}
|
||||
var arg1 map[string]any
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(map[string]interface{})
|
||||
arg1 = args[1].(map[string]any)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
@@ -181,7 +181,7 @@ func (_c *UserBackend_CreateUserFromClaims_Call) Return(user *userv1beta1.User,
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UserBackend_CreateUserFromClaims_Call) RunAndReturn(run func(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error)) *UserBackend_CreateUserFromClaims_Call {
|
||||
func (_c *UserBackend_CreateUserFromClaims_Call) RunAndReturn(run func(ctx context.Context, claims map[string]any) (*userv1beta1.User, error)) *UserBackend_CreateUserFromClaims_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
@@ -267,7 +267,7 @@ func (_c *UserBackend_GetUserByClaims_Call) RunAndReturn(run func(ctx context.Co
|
||||
}
|
||||
|
||||
// SyncGroupMemberships provides a mock function for the type UserBackend
|
||||
func (_mock *UserBackend) SyncGroupMemberships(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error {
|
||||
func (_mock *UserBackend) SyncGroupMemberships(ctx context.Context, user *userv1beta1.User, claims map[string]any) error {
|
||||
ret := _mock.Called(ctx, user, claims)
|
||||
|
||||
if len(ret) == 0 {
|
||||
@@ -275,7 +275,7 @@ func (_mock *UserBackend) SyncGroupMemberships(ctx context.Context, user *userv1
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) error); ok {
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) error); ok {
|
||||
r0 = returnFunc(ctx, user, claims)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
@@ -291,12 +291,12 @@ type UserBackend_SyncGroupMemberships_Call struct {
|
||||
// SyncGroupMemberships is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - user *userv1beta1.User
|
||||
// - claims map[string]interface{}
|
||||
// - claims map[string]any
|
||||
func (_e *UserBackend_Expecter) SyncGroupMemberships(ctx interface{}, user interface{}, claims interface{}) *UserBackend_SyncGroupMemberships_Call {
|
||||
return &UserBackend_SyncGroupMemberships_Call{Call: _e.mock.On("SyncGroupMemberships", ctx, user, claims)}
|
||||
}
|
||||
|
||||
func (_c *UserBackend_SyncGroupMemberships_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{})) *UserBackend_SyncGroupMemberships_Call {
|
||||
func (_c *UserBackend_SyncGroupMemberships_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any)) *UserBackend_SyncGroupMemberships_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
@@ -306,9 +306,9 @@ func (_c *UserBackend_SyncGroupMemberships_Call) Run(run func(ctx context.Contex
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(*userv1beta1.User)
|
||||
}
|
||||
var arg2 map[string]interface{}
|
||||
var arg2 map[string]any
|
||||
if args[2] != nil {
|
||||
arg2 = args[2].(map[string]interface{})
|
||||
arg2 = args[2].(map[string]any)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
@@ -324,13 +324,13 @@ func (_c *UserBackend_SyncGroupMemberships_Call) Return(err error) *UserBackend_
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UserBackend_SyncGroupMemberships_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error) *UserBackend_SyncGroupMemberships_Call {
|
||||
func (_c *UserBackend_SyncGroupMemberships_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any) error) *UserBackend_SyncGroupMemberships_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// UpdateUserIfNeeded provides a mock function for the type UserBackend
|
||||
func (_mock *UserBackend) UpdateUserIfNeeded(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error {
|
||||
func (_mock *UserBackend) UpdateUserIfNeeded(ctx context.Context, user *userv1beta1.User, claims map[string]any) error {
|
||||
ret := _mock.Called(ctx, user, claims)
|
||||
|
||||
if len(ret) == 0 {
|
||||
@@ -338,7 +338,7 @@ func (_mock *UserBackend) UpdateUserIfNeeded(ctx context.Context, user *userv1be
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) error); ok {
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) error); ok {
|
||||
r0 = returnFunc(ctx, user, claims)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
@@ -354,12 +354,12 @@ type UserBackend_UpdateUserIfNeeded_Call struct {
|
||||
// UpdateUserIfNeeded is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - user *userv1beta1.User
|
||||
// - claims map[string]interface{}
|
||||
// - claims map[string]any
|
||||
func (_e *UserBackend_Expecter) UpdateUserIfNeeded(ctx interface{}, user interface{}, claims interface{}) *UserBackend_UpdateUserIfNeeded_Call {
|
||||
return &UserBackend_UpdateUserIfNeeded_Call{Call: _e.mock.On("UpdateUserIfNeeded", ctx, user, claims)}
|
||||
}
|
||||
|
||||
func (_c *UserBackend_UpdateUserIfNeeded_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{})) *UserBackend_UpdateUserIfNeeded_Call {
|
||||
func (_c *UserBackend_UpdateUserIfNeeded_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any)) *UserBackend_UpdateUserIfNeeded_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
@@ -369,9 +369,9 @@ func (_c *UserBackend_UpdateUserIfNeeded_Call) Run(run func(ctx context.Context,
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(*userv1beta1.User)
|
||||
}
|
||||
var arg2 map[string]interface{}
|
||||
var arg2 map[string]any
|
||||
if args[2] != nil {
|
||||
arg2 = args[2].(map[string]interface{})
|
||||
arg2 = args[2].(map[string]any)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
@@ -387,7 +387,7 @@ func (_c *UserBackend_UpdateUserIfNeeded_Call) Return(err error) *UserBackend_Up
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UserBackend_UpdateUserIfNeeded_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error) *UserBackend_UpdateUserIfNeeded_Call {
|
||||
func (_c *UserBackend_UpdateUserIfNeeded_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any) error) *UserBackend_UpdateUserIfNeeded_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
"github.com/opencloud-eu/opencloud/pkg/middleware"
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
settingsService "github.com/opencloud-eu/opencloud/services/settings/pkg/service/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
"go-micro.dev/v4/metadata"
|
||||
)
|
||||
@@ -44,9 +44,9 @@ func (d defaultRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user
|
||||
// default user role. At least until proper roles are provided. See
|
||||
// https://github.com/owncloud/ocis/issues/1825 for more context.
|
||||
if user.Id.Type == cs3.UserType_USER_TYPE_PRIMARY || user.Id.Type == cs3.UserType_USER_TYPE_GUEST {
|
||||
roleId := settingsService.BundleUUIDRoleUser
|
||||
roleId := defaults.BundleUUIDRoleUser
|
||||
if user.Id.Type == cs3.UserType_USER_TYPE_GUEST {
|
||||
roleId = settingsService.BundleUUIDRoleGuest
|
||||
roleId = defaults.BundleUUIDRoleGuest
|
||||
}
|
||||
d.logger.Info().Str("userid", user.Id.OpaqueId).Msg("user has no role assigned, assigning default user role")
|
||||
ctx = metadata.Set(ctx, middleware.AccountID, user.Id.OpaqueId)
|
||||
|
||||
@@ -107,7 +107,7 @@ func (_c *UserRoleAssigner_ApplyUserRole_Call) RunAndReturn(run func(ctx context
|
||||
}
|
||||
|
||||
// UpdateUserRoleAssignment provides a mock function for the type UserRoleAssigner
|
||||
func (_mock *UserRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) (*userv1beta1.User, error) {
|
||||
func (_mock *UserRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *userv1beta1.User, claims map[string]any) (*userv1beta1.User, error) {
|
||||
ret := _mock.Called(ctx, user, claims)
|
||||
|
||||
if len(ret) == 0 {
|
||||
@@ -116,17 +116,17 @@ func (_mock *UserRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, use
|
||||
|
||||
var r0 *userv1beta1.User
|
||||
var r1 error
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) (*userv1beta1.User, error)); ok {
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) (*userv1beta1.User, error)); ok {
|
||||
return returnFunc(ctx, user, claims)
|
||||
}
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) *userv1beta1.User); ok {
|
||||
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) *userv1beta1.User); ok {
|
||||
r0 = returnFunc(ctx, user, claims)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*userv1beta1.User)
|
||||
}
|
||||
}
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context, *userv1beta1.User, map[string]interface{}) error); ok {
|
||||
if returnFunc, ok := ret.Get(1).(func(context.Context, *userv1beta1.User, map[string]any) error); ok {
|
||||
r1 = returnFunc(ctx, user, claims)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -142,12 +142,12 @@ type UserRoleAssigner_UpdateUserRoleAssignment_Call struct {
|
||||
// UpdateUserRoleAssignment is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - user *userv1beta1.User
|
||||
// - claims map[string]interface{}
|
||||
// - claims map[string]any
|
||||
func (_e *UserRoleAssigner_Expecter) UpdateUserRoleAssignment(ctx interface{}, user interface{}, claims interface{}) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
|
||||
return &UserRoleAssigner_UpdateUserRoleAssignment_Call{Call: _e.mock.On("UpdateUserRoleAssignment", ctx, user, claims)}
|
||||
}
|
||||
|
||||
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{})) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
|
||||
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any)) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
var arg0 context.Context
|
||||
if args[0] != nil {
|
||||
@@ -157,9 +157,9 @@ func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Run(run func(ctx conte
|
||||
if args[1] != nil {
|
||||
arg1 = args[1].(*userv1beta1.User)
|
||||
}
|
||||
var arg2 map[string]interface{}
|
||||
var arg2 map[string]any
|
||||
if args[2] != nil {
|
||||
arg2 = args[2].(map[string]interface{})
|
||||
arg2 = args[2].(map[string]any)
|
||||
}
|
||||
run(
|
||||
arg0,
|
||||
@@ -175,7 +175,7 @@ func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Return(user1 *userv1be
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) (*userv1beta1.User, error)) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
|
||||
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any) (*userv1beta1.User, error)) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
@@ -118,11 +118,11 @@ It can also be used to re-index all spaces:
|
||||
opencloud search index --all-spaces
|
||||
```
|
||||
|
||||
Please note that a reindex only picks up new files. Files that have already been indexed are not indexed again, even if the configuration or the whole extractor has been changed. To force a full reindex you need to use the `force-reindex` flag:
|
||||
Please note that a reindex only picks up new or changed files. Files that have already been indexed are not scanned again, even if the configuration or the whole extractor has been changed. To force a full rescan (re-running the extractor on every file) you need to use the `force-rescan` flag:
|
||||
|
||||
|
||||
```shell
|
||||
opencloud search index --all-spaces --force-reindex
|
||||
opencloud search index --all-spaces --force-rescan
|
||||
```
|
||||
|
||||
## Metrics
|
||||
|
||||
@@ -81,35 +81,26 @@ var _ = Describe("SpaceDebouncer", func() {
|
||||
}
|
||||
}, log.NewLogger())
|
||||
|
||||
// Initial call to start the timers
|
||||
// Reset the debounce timer every 50ms (shorter than the 100ms debounce
|
||||
// duration) but stop before the 250ms timeout fires. Continuing past the
|
||||
// timeout would race with the work function's cleanup of pending state:
|
||||
// a Debounce call arriving right after the timeout fires would find
|
||||
// pending empty and schedule a second workItem, breaking the assertion
|
||||
// below that the work function is invoked exactly once.
|
||||
debouncer.Debounce(spaceid, nil)
|
||||
|
||||
// Continuously reset the debounce timer using a ticker, at an interval
|
||||
// shorter than the debounce time.
|
||||
ticker := time.NewTicker(50 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
case <-ticker.C:
|
||||
debouncer.Debounce(spaceid, nil)
|
||||
}
|
||||
for i := 0; i < 4 && callCount.Load() == 0; i++ {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
if callCount.Load() == 0 {
|
||||
debouncer.Debounce(spaceid, nil)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// The debounce timer (100ms) should be reset every 50ms and thus never fire.
|
||||
// The timeout timer (250ms) should fire regardless.
|
||||
// The debounce timer (100ms) was reset roughly every 50ms and should
|
||||
// not have fired. The timeout timer (250ms) should fire regardless.
|
||||
Eventually(func() int {
|
||||
return int(callCount.Load())
|
||||
}, "300ms").Should(Equal(1))
|
||||
|
||||
// Stop the ticker goroutine
|
||||
close(done)
|
||||
|
||||
// And it should not fire again
|
||||
Consistently(func() int {
|
||||
return int(callCount.Load())
|
||||
|
||||
@@ -1,61 +1,13 @@
|
||||
package svc
|
||||
|
||||
const (
|
||||
// BundleUUIDRoleAdmin represents the admin role
|
||||
BundleUUIDRoleAdmin = "71881883-1768-46bd-a24d-a356a2afdf7f"
|
||||
|
||||
// BundleUUIDRoleSpaceAdmin represents the space admin role
|
||||
BundleUUIDRoleSpaceAdmin = "2aadd357-682c-406b-8874-293091995fdd"
|
||||
|
||||
// BundleUUIDRoleUser represents the user role.
|
||||
BundleUUIDRoleUser = "d7beeea8-8ff4-406b-8fb6-ab2dd81e6b11"
|
||||
|
||||
// BundleUUIDRoleGuest represents the guest role.
|
||||
BundleUUIDRoleGuest = "38071a68-456a-4553-846a-fa67bf5596cc"
|
||||
|
||||
// RoleManagementPermissionID is the hardcoded setting UUID for the role management permission
|
||||
RoleManagementPermissionID string = "a53e601e-571f-4f86-8fec-d4576ef49c62"
|
||||
// RoleManagementPermissionName is the hardcoded setting name for the role management permission
|
||||
RoleManagementPermissionName string = "role-management"
|
||||
|
||||
// SettingsManagementPermissionID is the hardcoded setting UUID for the settings management permission
|
||||
SettingsManagementPermissionID string = "3d58f441-4a05-42f8-9411-ef5874528ae1"
|
||||
// SettingsManagementPermissionName is the hardcoded setting name for the settings management permission
|
||||
SettingsManagementPermissionName string = "settings-management"
|
||||
|
||||
// SetSpaceQuotaPermissionID is the hardcoded setting UUID for the set space quota permission
|
||||
SetSpaceQuotaPermissionID string = "4e6f9709-f9e7-44f1-95d4-b762d27b7896"
|
||||
// SetSpaceQuotaPermissionName is the hardcoded setting name for the set space quota permission
|
||||
SetSpaceQuotaPermissionName string = "set-space-quota"
|
||||
|
||||
// ListAllSpacesPermissionID is the hardcoded setting UUID for the list all spaces permission
|
||||
ListAllSpacesPermissionID string = "016f6ddd-9501-4a0a-8ebe-64a20ee8ec82"
|
||||
// ListAllSpacesPermissionName is the hardcoded setting name for the list all spaces permission
|
||||
ListAllSpacesPermissionName string = "list-all-spaces"
|
||||
|
||||
// CreateSpacePermissionID is the hardcoded setting UUID for the create space permission
|
||||
CreateSpacePermissionID string = "79e13b30-3e22-11eb-bc51-0b9f0bad9a58"
|
||||
// CreateSpacePermissionName is the hardcoded setting name for the create space permission
|
||||
CreateSpacePermissionName string = "create-space"
|
||||
|
||||
// SettingUUIDProfileLanguage is the hardcoded setting UUID for the user profile language
|
||||
SettingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f"
|
||||
|
||||
// AccountManagementPermissionID is the hardcoded setting UUID for the account management permission
|
||||
AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73"
|
||||
// AccountManagementPermissionName is the hardcoded setting name for the account management permission
|
||||
AccountManagementPermissionName string = "account-management"
|
||||
// GroupManagementPermissionID is the hardcoded setting UUID for the group management permission
|
||||
GroupManagementPermissionID string = "522adfbe-5908-45b4-b135-41979de73245"
|
||||
// GroupManagementPermissionName is the hardcoded setting name for the group management permission
|
||||
GroupManagementPermissionName string = "group-management"
|
||||
// SelfManagementPermissionID is the hardcoded setting UUID for the self management permission
|
||||
SelfManagementPermissionID string = "e03070e9-4362-4cc6-a872-1c7cb2eb2b8e"
|
||||
// SelfManagementPermissionName is the hardcoded setting name for the self management permission
|
||||
SelfManagementPermissionName string = "self-management"
|
||||
|
||||
// ChangeLogoPermissionID is the hardcoded setting UUID for the change-logo permission
|
||||
ChangeLogoPermissionID string = "ed83fc10-1f54-4a9e-b5a7-fb517f5f3e01"
|
||||
// ChangeLogoPermissionName is the hardcoded setting name for the change-logo permission
|
||||
ChangeLogoPermissionName string = "change-logo"
|
||||
)
|
||||
|
||||
@@ -14,6 +14,8 @@ const (
|
||||
BundleUUIDRoleUser = "d7beeea8-8ff4-406b-8fb6-ab2dd81e6b11"
|
||||
// BundleUUIDRoleUserLight represents the user light role.
|
||||
BundleUUIDRoleUserLight = "38071a68-456a-4553-846a-fa67bf5596cc"
|
||||
// BundleUUIDRoleGuest represents the guest role.
|
||||
BundleUUIDRoleGuest = "38071a68-456a-4553-846a-fa67bf5596cc"
|
||||
// BundleUUIDProfile represents the user profile.
|
||||
BundleUUIDProfile = "2a506de7-99bd-4f0d-994e-c38e72c28fd9"
|
||||
// BundleUUIDServiceAccount represents the service account role.
|
||||
|
||||
@@ -204,7 +204,7 @@ type PosixDriver struct {
|
||||
|
||||
EnableFSRevisions bool `yaml:"enable_fs_revisions" env:"STORAGE_USERS_POSIX_ENABLE_FS_REVISIONS" desc:"Allow for generating revisions from changes done to the local storage. Note: This doubles the number of bytes stored on disk because a copy of the current revision is stored to be turned into a revision later." introductionVersion:"1.0.0"`
|
||||
|
||||
ScanFS bool `yaml:"scan_fs" env:"STORAGE_USERS_POSIX_SCAN_FS" desc:"Scan the filesystem at startup for changes and update the metadata accordingly." introductionVersion:"%%NEXT%%"`
|
||||
ScanFS bool `yaml:"scan_fs" env:"STORAGE_USERS_POSIX_SCAN_FS" desc:"Scan the filesystem at startup for changes and update the metadata accordingly." introductionVersion:"6.2.0"`
|
||||
WatchFS bool `yaml:"watch_fs" env:"STORAGE_USERS_POSIX_WATCH_FS" desc:"Enable the filesystem watcher to detect changes to the filesystem. This is used to detect changes to the filesystem and update the metadata accordingly." introductionVersion:"2.0.0"`
|
||||
WatchType string `yaml:"watch_type" env:"STORAGE_USERS_POSIX_WATCH_TYPE" desc:"Type of the watcher to use for getting notified about changes to the filesystem. Currently available options are 'inotifywait' (default), 'cephfs', 'gpfswatchfolder' and 'gpfsfileauditlogging'." introductionVersion:"1.0.0"`
|
||||
WatchPath string `yaml:"watch_path" env:"STORAGE_USERS_POSIX_WATCH_PATH" desc:"Path to the watch directory/file. Only applies to the 'gpfsfileauditlogging' and 'inotifywait' watcher, in which case it is the path of the file audit log file/base directory to watch." introductionVersion:"1.0.0"`
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
SHELL := bash
|
||||
NAME := web
|
||||
WEB_ASSETS_VERSION = v6.2.0
|
||||
WEB_ASSETS_VERSION = v7.0.0
|
||||
WEB_ASSETS_BRANCH = main
|
||||
|
||||
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
|
||||
|
||||
@@ -45,6 +45,11 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// register the REPORT method at init so it cannot race with concurrent route setup in other services.
|
||||
func init() {
|
||||
chi.RegisterMethod("REPORT")
|
||||
}
|
||||
|
||||
// Service defines the extension handlers.
|
||||
type Service interface {
|
||||
ServeHTTP(w http.ResponseWriter, r *http.Request)
|
||||
@@ -93,9 +98,6 @@ func NewService(opts ...Option) (Service, error) {
|
||||
svc.thumbnailsClient = nil
|
||||
}
|
||||
|
||||
// register method with chi before any routing is set up
|
||||
chi.RegisterMethod("REPORT")
|
||||
|
||||
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
|
||||
if !svc.config.DisablePreviews {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2016 HashiCorp, Inc.
|
||||
Copyright IBM Corp. 2016, 2025
|
||||
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# Copyright IBM Corp. 2016, 2025
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
version: v1
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) HashiCorp, Inc.
|
||||
# Copyright IBM Corp. 2016, 2025
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
version: v1
|
||||
|
||||
+6
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
@@ -669,7 +669,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
// Setup a temporary certificate for client/server mtls, and send the public
|
||||
// certificate to the plugin.
|
||||
if c.config.AutoMTLS {
|
||||
c.logger.Info("configuring client automatic mTLS")
|
||||
c.logger.Debug("configuring client automatic mTLS")
|
||||
certPEM, keyPEM, err := generateCert()
|
||||
if err != nil {
|
||||
c.logger.Error("failed to generate client certificate", "error", err)
|
||||
@@ -753,9 +753,12 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
// Create a context for when we kill
|
||||
c.doneCtx, c.ctxCancel = context.WithCancel(context.Background())
|
||||
|
||||
// Add two to pipesWaitGroup: one for logStderr, one for the goroutine
|
||||
// below that consumes Stdout. We mustn't continue to Add once we might Wait.
|
||||
c.pipesWaitGroup.Add(2)
|
||||
|
||||
// Start goroutine that logs the stderr
|
||||
c.clientWaitGroup.Add(1)
|
||||
c.pipesWaitGroup.Add(1)
|
||||
// logStderr calls c.pipesWaitGroup.Done()
|
||||
go c.logStderr(runner.Name(), runner.Stderr())
|
||||
|
||||
@@ -791,7 +794,6 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
// out of stdout
|
||||
linesCh := make(chan string)
|
||||
c.clientWaitGroup.Add(1)
|
||||
c.pipesWaitGroup.Add(1)
|
||||
go func() {
|
||||
defer c.clientWaitGroup.Done()
|
||||
defer c.pipesWaitGroup.Done()
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cmdrunner
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cmdrunner
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cmdrunner
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package cmdrunner
|
||||
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package cmdrunner
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cmdrunner
|
||||
|
||||
+6
-2
@@ -1,8 +1,7 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package cmdrunner
|
||||
|
||||
@@ -16,6 +15,11 @@ import (
|
||||
func _pidAlive(pid int) bool {
|
||||
proc, err := os.FindProcess(pid)
|
||||
if err == nil {
|
||||
// On Linux with Go 1.23+, FindProcess opens a pidfd which must be
|
||||
// released or it leaks an FD on every call. Release errors are
|
||||
// intentionally ignored; the handle is short-lived and there's
|
||||
// nothing actionable to recover from a release failure.
|
||||
defer func() { _ = proc.Release() }()
|
||||
err = proc.Signal(syscall.Signal(0))
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cmdrunner
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package grpcmux
|
||||
|
||||
Generated
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package grpcmux
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package grpcmux
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package grpcmux
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package grpcmux
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
syntax = "proto3";
|
||||
package plugin;
|
||||
option go_package = "./plugin";
|
||||
option go_package = "github.com/hashicorp/go-plugin/internal/plugin";
|
||||
|
||||
message ConnInfo {
|
||||
uint32 service_id = 1;
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
syntax = "proto3";
|
||||
package plugin;
|
||||
option go_package = "./plugin";
|
||||
option go_package = "github.com/hashicorp/go-plugin/internal/plugin";
|
||||
|
||||
message Empty {
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
syntax = "proto3";
|
||||
package plugin;
|
||||
option go_package = "./plugin";
|
||||
option go_package = "github.com/hashicorp/go-plugin/internal/plugin";
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// The plugin package exposes functions and helpers for communicating to
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package runner
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
@@ -307,7 +307,7 @@ func Serve(opts *ServeConfig) {
|
||||
// If the client is configured using AutoMTLS, the certificate will be here,
|
||||
// and we need to generate our own in response.
|
||||
if tlsConfig == nil && clientCert != "" {
|
||||
logger.Info("configuring server automatic mTLS")
|
||||
logger.Debug("configuring server automatic mTLS")
|
||||
clientCertPool := x509.NewCertPool()
|
||||
if !clientCertPool.AppendCertsFromPEM([]byte(clientCert)) {
|
||||
logger.Error("client cert provided but failed to parse", "cert", clientCert)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// Copyright IBM Corp. 2016, 2025
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package plugin
|
||||
|
||||
+5
@@ -175,6 +175,11 @@ func (c *Client) appendObjectDo(ctx context.Context, bucketName, objectName stri
|
||||
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
|
||||
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
|
||||
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
|
||||
ChecksumMD5: h.Get(ChecksumMD5.Key()),
|
||||
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
|
||||
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
|
||||
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
|
||||
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
|
||||
ChecksumMode: h.Get(ChecksumFullObjectMode.Key()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
+17
-5
@@ -150,6 +150,11 @@ type UploadInfo struct {
|
||||
ChecksumSHA1 string
|
||||
ChecksumSHA256 string
|
||||
ChecksumCRC64NVME string
|
||||
ChecksumMD5 string
|
||||
ChecksumSHA512 string
|
||||
ChecksumXXHash64 string
|
||||
ChecksumXXHash3 string
|
||||
ChecksumXXHash128 string
|
||||
ChecksumMode string
|
||||
}
|
||||
|
||||
@@ -168,11 +173,12 @@ type ObjectInfo struct {
|
||||
// each parts concatenated into one string.
|
||||
ETag string `json:"etag"`
|
||||
|
||||
Key string `json:"name"` // Name of the object
|
||||
LastModified time.Time `json:"lastModified"` // Date and time the object was last modified.
|
||||
Size int64 `json:"size"` // Size in bytes of the object.
|
||||
ContentType string `json:"contentType"` // A standard MIME type describing the format of the object data.
|
||||
Expires time.Time `json:"expires"` // The date and time at which the object is no longer able to be cached.
|
||||
Key string `json:"name"` // Name of the object
|
||||
LastModified time.Time `json:"lastModified"` // Date and time the object was last modified.
|
||||
Size int64 `json:"size"` // Size in bytes of the object.
|
||||
ContentType string `json:"contentType"` // A standard MIME type describing the format of the object data.
|
||||
ContentEncoding string `json:"contentEncoding"` // A standard MIME type describing encoding of the object data.
|
||||
Expires time.Time `json:"expires"` // The date and time at which the object is no longer able to be cached.
|
||||
|
||||
// Collection of additional metadata on the object.
|
||||
// eg: x-amz-meta-*, content-encoding etc.
|
||||
@@ -226,6 +232,12 @@ type ObjectInfo struct {
|
||||
ChecksumSHA1 string
|
||||
ChecksumSHA256 string
|
||||
ChecksumCRC64NVME string
|
||||
ChecksumMD5 string
|
||||
ChecksumSHA512 string
|
||||
ChecksumXXHash64 string
|
||||
ChecksumXXHash3 string
|
||||
ChecksumXXHash128 string
|
||||
ChecksumAlgorithm string
|
||||
ChecksumMode string `xml:"ChecksumType"`
|
||||
|
||||
Internal *struct {
|
||||
|
||||
+96
-10
@@ -23,6 +23,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/minio/minio-go/v7/pkg/encrypt"
|
||||
@@ -88,10 +89,17 @@ type ObjectAttributesResponse struct {
|
||||
StorageClass string
|
||||
ObjectSize int
|
||||
Checksum struct {
|
||||
ChecksumCRC32 string `xml:",omitempty"`
|
||||
ChecksumCRC32C string `xml:",omitempty"`
|
||||
ChecksumSHA1 string `xml:",omitempty"`
|
||||
ChecksumSHA256 string `xml:",omitempty"`
|
||||
ChecksumCRC32 string `xml:",omitempty"`
|
||||
ChecksumCRC32C string `xml:",omitempty"`
|
||||
ChecksumCRC64NVME string `xml:",omitempty"`
|
||||
ChecksumSHA1 string `xml:",omitempty"`
|
||||
ChecksumSHA256 string `xml:",omitempty"`
|
||||
ChecksumMD5 string `xml:",omitempty"`
|
||||
ChecksumSHA512 string `xml:",omitempty"`
|
||||
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
|
||||
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
|
||||
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
|
||||
ChecksumType string `xml:",omitempty"`
|
||||
}
|
||||
ObjectParts struct {
|
||||
PartsCount int
|
||||
@@ -105,12 +113,90 @@ type ObjectAttributesResponse struct {
|
||||
|
||||
// ObjectAttributePart is used by ObjectAttributesResponse to describe an object part
|
||||
type ObjectAttributePart struct {
|
||||
ChecksumCRC32 string `xml:",omitempty"`
|
||||
ChecksumCRC32C string `xml:",omitempty"`
|
||||
ChecksumSHA1 string `xml:",omitempty"`
|
||||
ChecksumSHA256 string `xml:",omitempty"`
|
||||
PartNumber int
|
||||
Size int
|
||||
ChecksumCRC32 string `xml:",omitempty"`
|
||||
ChecksumCRC32C string `xml:",omitempty"`
|
||||
ChecksumCRC64NVME string `xml:",omitempty"`
|
||||
ChecksumSHA1 string `xml:",omitempty"`
|
||||
ChecksumSHA256 string `xml:",omitempty"`
|
||||
ChecksumMD5 string `xml:",omitempty"`
|
||||
ChecksumSHA512 string `xml:",omitempty"`
|
||||
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
|
||||
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
|
||||
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
|
||||
PartNumber int
|
||||
Size int
|
||||
}
|
||||
|
||||
// ChecksumMap returns a map of checksums for the object.
|
||||
func (o *ObjectAttributesResponse) ChecksumMap() map[string]string {
|
||||
res := make(map[string]string)
|
||||
setif := func(typ ChecksumType, value string) {
|
||||
if value != "" {
|
||||
res[typ.Key()] = value
|
||||
}
|
||||
}
|
||||
setif(ChecksumCRC32C, o.Checksum.ChecksumCRC32C)
|
||||
setif(ChecksumCRC32, o.Checksum.ChecksumCRC32)
|
||||
setif(ChecksumCRC64NVME, o.Checksum.ChecksumCRC64NVME)
|
||||
setif(ChecksumSHA1, o.Checksum.ChecksumSHA1)
|
||||
setif(ChecksumSHA256, o.Checksum.ChecksumSHA256)
|
||||
setif(ChecksumMD5, o.Checksum.ChecksumMD5)
|
||||
setif(ChecksumSHA512, o.Checksum.ChecksumSHA512)
|
||||
setif(ChecksumXXHash64, o.Checksum.ChecksumXXHash64)
|
||||
setif(ChecksumXXHash3, o.Checksum.ChecksumXXHash3)
|
||||
setif(ChecksumXXHash128, o.Checksum.ChecksumXXHash128)
|
||||
return res
|
||||
}
|
||||
|
||||
// ChecksumMode returns the checksum mode of the object.
|
||||
// If unable to determine, returns ChecksumUnknownMode.
|
||||
func (o *ObjectAttributesResponse) ChecksumMode() ChecksumMode {
|
||||
t := o.ChecksumType()
|
||||
if !t.IsSet() {
|
||||
return ChecksumUnknownMode
|
||||
}
|
||||
switch o.Checksum.ChecksumType {
|
||||
case amzChecksumModeComposite:
|
||||
return ChecksumCompositeMode
|
||||
case amzChecksumModeFullObject:
|
||||
return ChecksumFullObjectMode
|
||||
case "":
|
||||
// Likely not supported by the server.
|
||||
if o.Checksum.ChecksumCRC64NVME != "" || !strings.ContainsRune(o.ETag, '-') {
|
||||
// Always full object.
|
||||
return ChecksumFullObjectMode
|
||||
}
|
||||
if !t.CanMergeCRC() {
|
||||
// Only composite possible.
|
||||
return ChecksumCompositeMode
|
||||
}
|
||||
}
|
||||
return ChecksumUnknownMode
|
||||
}
|
||||
|
||||
// ChecksumType returns the checksum type of the object.
|
||||
// If none is set, returns ChecksumNone.
|
||||
func (o *ObjectAttributesResponse) ChecksumType() ChecksumType {
|
||||
t := ChecksumNone
|
||||
setif := func(typ ChecksumType, value string) {
|
||||
if value != "" {
|
||||
t = typ
|
||||
}
|
||||
}
|
||||
setif(ChecksumCRC32C, o.Checksum.ChecksumCRC32C)
|
||||
setif(ChecksumCRC32, o.Checksum.ChecksumCRC32)
|
||||
setif(ChecksumCRC64NVME, o.Checksum.ChecksumCRC64NVME)
|
||||
setif(ChecksumSHA1, o.Checksum.ChecksumSHA1)
|
||||
setif(ChecksumSHA256, o.Checksum.ChecksumSHA256)
|
||||
setif(ChecksumMD5, o.Checksum.ChecksumMD5)
|
||||
setif(ChecksumSHA512, o.Checksum.ChecksumSHA512)
|
||||
setif(ChecksumXXHash64, o.Checksum.ChecksumXXHash64)
|
||||
setif(ChecksumXXHash3, o.Checksum.ChecksumXXHash3)
|
||||
setif(ChecksumXXHash128, o.Checksum.ChecksumXXHash128)
|
||||
if t.IsSet() && o.Checksum.ChecksumType == amzChecksumModeFullObject {
|
||||
t |= ChecksumFullObject
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (o *ObjectAttributes) parseResponse(resp *http.Response) (err error) {
|
||||
|
||||
+7
-1
@@ -404,7 +404,7 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
|
||||
}
|
||||
|
||||
var (
|
||||
keyMarker = ""
|
||||
keyMarker = opts.StartAfter
|
||||
versionIDMarker = ""
|
||||
preName = ""
|
||||
preKey = ""
|
||||
@@ -432,12 +432,18 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
|
||||
UserMetadata: version.UserMetadata,
|
||||
Internal: version.Internal,
|
||||
NumVersions: numVersions,
|
||||
ChecksumAlgorithm: version.ChecksumAlgorithm,
|
||||
ChecksumMode: version.ChecksumType,
|
||||
ChecksumCRC32: version.ChecksumCRC32,
|
||||
ChecksumCRC32C: version.ChecksumCRC32C,
|
||||
ChecksumSHA1: version.ChecksumSHA1,
|
||||
ChecksumSHA256: version.ChecksumSHA256,
|
||||
ChecksumCRC64NVME: version.ChecksumCRC64NVME,
|
||||
ChecksumMD5: version.ChecksumMD5,
|
||||
ChecksumSHA512: version.ChecksumSHA512,
|
||||
ChecksumXXHash64: version.ChecksumXXHash64,
|
||||
ChecksumXXHash3: version.ChecksumXXHash3,
|
||||
ChecksumXXHash128: version.ChecksumXXHash128,
|
||||
}
|
||||
if !yield(info) {
|
||||
return false
|
||||
|
||||
+15
@@ -192,6 +192,11 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj
|
||||
ChecksumSHA1: part.ChecksumSHA1,
|
||||
ChecksumSHA256: part.ChecksumSHA256,
|
||||
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
|
||||
ChecksumMD5: part.ChecksumMD5,
|
||||
ChecksumSHA512: part.ChecksumSHA512,
|
||||
ChecksumXXHash64: part.ChecksumXXHash64,
|
||||
ChecksumXXHash3: part.ChecksumXXHash3,
|
||||
ChecksumXXHash128: part.ChecksumXXHash128,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -353,6 +358,11 @@ func (c *Client) uploadPart(ctx context.Context, p uploadPartParams) (ObjectPart
|
||||
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
|
||||
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
|
||||
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
|
||||
ChecksumMD5: h.Get(ChecksumMD5.Key()),
|
||||
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
|
||||
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
|
||||
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
|
||||
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
|
||||
}
|
||||
objPart.Size = p.size
|
||||
objPart.PartNumber = p.partNumber
|
||||
@@ -458,6 +468,11 @@ func (c *Client) completeMultipartUpload(ctx context.Context, bucketName, object
|
||||
ChecksumCRC32: completeMultipartUploadResult.ChecksumCRC32,
|
||||
ChecksumCRC32C: completeMultipartUploadResult.ChecksumCRC32C,
|
||||
ChecksumCRC64NVME: completeMultipartUploadResult.ChecksumCRC64NVME,
|
||||
ChecksumMD5: completeMultipartUploadResult.ChecksumMD5,
|
||||
ChecksumSHA512: completeMultipartUploadResult.ChecksumSHA512,
|
||||
ChecksumXXHash64: completeMultipartUploadResult.ChecksumXXHash64,
|
||||
ChecksumXXHash3: completeMultipartUploadResult.ChecksumXXHash3,
|
||||
ChecksumXXHash128: completeMultipartUploadResult.ChecksumXXHash128,
|
||||
ChecksumMode: completeMultipartUploadResult.ChecksumType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
+20
@@ -259,6 +259,11 @@ func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketN
|
||||
ChecksumSHA1: uploadRes.Part.ChecksumSHA1,
|
||||
ChecksumSHA256: uploadRes.Part.ChecksumSHA256,
|
||||
ChecksumCRC64NVME: uploadRes.Part.ChecksumCRC64NVME,
|
||||
ChecksumMD5: uploadRes.Part.ChecksumMD5,
|
||||
ChecksumSHA512: uploadRes.Part.ChecksumSHA512,
|
||||
ChecksumXXHash64: uploadRes.Part.ChecksumXXHash64,
|
||||
ChecksumXXHash3: uploadRes.Part.ChecksumXXHash3,
|
||||
ChecksumXXHash128: uploadRes.Part.ChecksumXXHash128,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -418,6 +423,11 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b
|
||||
ChecksumSHA1: part.ChecksumSHA1,
|
||||
ChecksumSHA256: part.ChecksumSHA256,
|
||||
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
|
||||
ChecksumMD5: part.ChecksumMD5,
|
||||
ChecksumSHA512: part.ChecksumSHA512,
|
||||
ChecksumXXHash64: part.ChecksumXXHash64,
|
||||
ChecksumXXHash3: part.ChecksumXXHash3,
|
||||
ChecksumXXHash128: part.ChecksumXXHash128,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -617,6 +627,11 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam
|
||||
ChecksumSHA1: part.ChecksumSHA1,
|
||||
ChecksumSHA256: part.ChecksumSHA256,
|
||||
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
|
||||
ChecksumMD5: part.ChecksumMD5,
|
||||
ChecksumSHA512: part.ChecksumSHA512,
|
||||
ChecksumXXHash64: part.ChecksumXXHash64,
|
||||
ChecksumXXHash3: part.ChecksumXXHash3,
|
||||
ChecksumXXHash128: part.ChecksumXXHash128,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -796,6 +811,11 @@ func (c *Client) putObjectDo(ctx context.Context, bucketName, objectName string,
|
||||
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
|
||||
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
|
||||
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
|
||||
ChecksumMD5: h.Get(ChecksumMD5.Key()),
|
||||
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
|
||||
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
|
||||
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
|
||||
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
|
||||
ChecksumMode: h.Get(ChecksumFullObjectMode.Key()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
+5
@@ -502,6 +502,11 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam
|
||||
ChecksumSHA1: part.ChecksumSHA1,
|
||||
ChecksumSHA256: part.ChecksumSHA256,
|
||||
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
|
||||
ChecksumMD5: part.ChecksumMD5,
|
||||
ChecksumSHA512: part.ChecksumSHA512,
|
||||
ChecksumXXHash64: part.ChecksumXXHash64,
|
||||
ChecksumXXHash3: part.ChecksumXXHash3,
|
||||
ChecksumXXHash128: part.ChecksumXXHash128,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+41
@@ -113,6 +113,12 @@ type Version struct {
|
||||
ChecksumSHA1 string `xml:",omitempty"`
|
||||
ChecksumSHA256 string `xml:",omitempty"`
|
||||
ChecksumCRC64NVME string `xml:",omitempty"`
|
||||
ChecksumMD5 string `xml:",omitempty"`
|
||||
ChecksumSHA512 string `xml:",omitempty"`
|
||||
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
|
||||
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
|
||||
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
|
||||
ChecksumAlgorithm string `xml:",omitempty"`
|
||||
ChecksumType string `xml:",omitempty"`
|
||||
|
||||
isDeleteMarker bool
|
||||
@@ -297,6 +303,11 @@ type ObjectPart struct {
|
||||
ChecksumSHA1 string
|
||||
ChecksumSHA256 string
|
||||
ChecksumCRC64NVME string
|
||||
ChecksumMD5 string
|
||||
ChecksumSHA512 string
|
||||
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
|
||||
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
|
||||
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
|
||||
}
|
||||
|
||||
// Checksum will return the checksum for the given type.
|
||||
@@ -313,6 +324,16 @@ func (c ObjectPart) Checksum(t ChecksumType) string {
|
||||
return c.ChecksumSHA256
|
||||
case t.Is(ChecksumCRC64NVME):
|
||||
return c.ChecksumCRC64NVME
|
||||
case t.Is(ChecksumMD5):
|
||||
return c.ChecksumMD5
|
||||
case t.Is(ChecksumSHA512):
|
||||
return c.ChecksumSHA512
|
||||
case t.Is(ChecksumXXHash64):
|
||||
return c.ChecksumXXHash64
|
||||
case t.Is(ChecksumXXHash3):
|
||||
return c.ChecksumXXHash3
|
||||
case t.Is(ChecksumXXHash128):
|
||||
return c.ChecksumXXHash128
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -382,6 +403,11 @@ type completeMultipartUploadResult struct {
|
||||
ChecksumSHA1 string
|
||||
ChecksumSHA256 string
|
||||
ChecksumCRC64NVME string
|
||||
ChecksumMD5 string
|
||||
ChecksumSHA512 string
|
||||
ChecksumXXHash64 string `xml:"ChecksumXXHASH64"`
|
||||
ChecksumXXHash3 string `xml:"ChecksumXXHASH3"`
|
||||
ChecksumXXHash128 string `xml:"ChecksumXXHASH128"`
|
||||
ChecksumType string
|
||||
}
|
||||
|
||||
@@ -398,6 +424,11 @@ type CompletePart struct {
|
||||
ChecksumSHA1 string `xml:"ChecksumSHA1,omitempty"`
|
||||
ChecksumSHA256 string `xml:"ChecksumSHA256,omitempty"`
|
||||
ChecksumCRC64NVME string `xml:",omitempty"`
|
||||
ChecksumMD5 string `xml:",omitempty"`
|
||||
ChecksumSHA512 string `xml:",omitempty"`
|
||||
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
|
||||
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
|
||||
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
|
||||
}
|
||||
|
||||
// Checksum will return the checksum for the given type.
|
||||
@@ -414,6 +445,16 @@ func (c CompletePart) Checksum(t ChecksumType) string {
|
||||
return c.ChecksumSHA256
|
||||
case t.Is(ChecksumCRC64NVME):
|
||||
return c.ChecksumCRC64NVME
|
||||
case t.Is(ChecksumMD5):
|
||||
return c.ChecksumMD5
|
||||
case t.Is(ChecksumSHA512):
|
||||
return c.ChecksumSHA512
|
||||
case t.Is(ChecksumXXHash64):
|
||||
return c.ChecksumXXHash64
|
||||
case t.Is(ChecksumXXHash3):
|
||||
return c.ChecksumXXHash3
|
||||
case t.Is(ChecksumXXHash128):
|
||||
return c.ChecksumXXHash128
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
+17
-9
@@ -52,6 +52,12 @@ type UpdateObjectEncryptionOptions struct {
|
||||
VersionID string
|
||||
}
|
||||
|
||||
// UpdateObjectEncryptionResult holds the result of an UpdateObjectEncryption call.
|
||||
type UpdateObjectEncryptionResult struct {
|
||||
// VersionID is the version ID of the object that was updated, if versioning is enabled.
|
||||
VersionID string
|
||||
}
|
||||
|
||||
// UpdateObjectEncryption changes the encryption configuration of an existing object in-place.
|
||||
// The object must already be encrypted with SSE-S3 or SSE-KMS. SSE-C objects are not supported.
|
||||
// This operation rotates the data encryption key envelope without re-reading/re-writing object data.
|
||||
@@ -62,19 +68,19 @@ type UpdateObjectEncryptionOptions struct {
|
||||
// - objectName: Name of the object
|
||||
// - opts: Options including KMSKeyArn (required), optional BucketKeyEnabled, and optional VersionID
|
||||
//
|
||||
// Returns an error if the operation fails.
|
||||
func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectName string, opts UpdateObjectEncryptionOptions) error {
|
||||
// Returns the version ID of the updated object (if versioning is enabled) and an error if the operation fails.
|
||||
func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectName string, opts UpdateObjectEncryptionOptions) (UpdateObjectEncryptionResult, error) {
|
||||
// Input validation.
|
||||
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
|
||||
return err
|
||||
return UpdateObjectEncryptionResult{}, err
|
||||
}
|
||||
|
||||
if err := s3utils.CheckValidObjectName(objectName); err != nil {
|
||||
return err
|
||||
return UpdateObjectEncryptionResult{}, err
|
||||
}
|
||||
|
||||
if opts.KMSKeyArn == "" {
|
||||
return errInvalidArgument("KMSKeyArn is required for UpdateObjectEncryption.")
|
||||
return UpdateObjectEncryptionResult{}, errInvalidArgument("KMSKeyArn is required for UpdateObjectEncryption.")
|
||||
}
|
||||
|
||||
// Get resources properly escaped and lined up before
|
||||
@@ -96,7 +102,7 @@ func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectN
|
||||
|
||||
bodyData, err := xml.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return err
|
||||
return UpdateObjectEncryptionResult{}, err
|
||||
}
|
||||
|
||||
reqMetadata := requestMetadata{
|
||||
@@ -113,10 +119,12 @@ func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectN
|
||||
resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata)
|
||||
defer closeResponse(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
return UpdateObjectEncryptionResult{}, err
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return httpRespToErrorResponse(resp, bucketName, objectName)
|
||||
return UpdateObjectEncryptionResult{}, httpRespToErrorResponse(resp, bucketName, objectName)
|
||||
}
|
||||
return nil
|
||||
return UpdateObjectEncryptionResult{
|
||||
VersionID: resp.Header.Get(amzVersionID),
|
||||
}, nil
|
||||
}
|
||||
|
||||
+13
-1
@@ -198,6 +198,9 @@ func New(endpoint string, opts *Options) (*Client, error) {
|
||||
// Amazon S3 endpoints are resolved into dual-stack endpoints by default
|
||||
// for backwards compatibility.
|
||||
clnt.s3DualstackEnabled = true
|
||||
} else if s3utils.IsAmazonOutpostsEndpoint(*clnt.endpointURL) {
|
||||
// S3 on Outposts uses signature v4 with service name s3-outposts.
|
||||
clnt.overrideSignerType = credentials.SignatureV4
|
||||
}
|
||||
|
||||
return clnt, nil
|
||||
@@ -912,7 +915,11 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
|
||||
req = signer.PreSignV2(*req, accessKeyID, secretAccessKey, metadata.expires, isVirtualHost)
|
||||
} else if signerType.IsV4() {
|
||||
// Presign URL with signature v4.
|
||||
req = signer.PreSignV4(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.expires)
|
||||
if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
|
||||
req = signer.PreSignV4Outposts(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.expires)
|
||||
} else {
|
||||
req = signer.PreSignV4(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.expires)
|
||||
}
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
@@ -971,6 +978,9 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
|
||||
if s3utils.IsAmazonExpressRegionalEndpoint(*c.endpointURL) {
|
||||
req = signer.StreamingSignV4Express(req, accessKeyID,
|
||||
secretAccessKey, sessionToken, location, metadata.contentLength, time.Now().UTC(), c.sha256Hasher())
|
||||
} else if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
|
||||
req = signer.StreamingSignV4Outposts(req, accessKeyID,
|
||||
secretAccessKey, sessionToken, location, metadata.contentLength, time.Now().UTC(), c.sha256Hasher())
|
||||
} else {
|
||||
req = signer.StreamingSignV4(req, accessKeyID,
|
||||
secretAccessKey, sessionToken, location, metadata.contentLength, time.Now().UTC(), c.sha256Hasher())
|
||||
@@ -991,6 +1001,8 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
|
||||
|
||||
if s3utils.IsAmazonExpressRegionalEndpoint(*c.endpointURL) {
|
||||
req = signer.SignV4TrailerExpress(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.trailer)
|
||||
} else if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
|
||||
req = signer.SignV4TrailerOutposts(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.trailer)
|
||||
} else {
|
||||
// Add signature version '4' authorization header.
|
||||
req = signer.SignV4Trailer(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.trailer)
|
||||
|
||||
+6
-1
@@ -209,6 +209,11 @@ func (c *Client) getBucketLocationRequest(ctx context.Context, bucketName string
|
||||
}
|
||||
|
||||
req.Header.Set("X-Amz-Content-Sha256", contentSha256)
|
||||
req = signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, "us-east-1")
|
||||
if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
|
||||
region := getDefaultLocation(*c.endpointURL, c.region)
|
||||
req = signer.SignV4Outposts(*req, accessKeyID, secretAccessKey, sessionToken, region)
|
||||
} else {
|
||||
req = signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, "us-east-1")
|
||||
}
|
||||
return req, nil
|
||||
}
|
||||
|
||||
+67
-4
@@ -18,8 +18,10 @@
|
||||
package minio
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
@@ -30,8 +32,10 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/cespare/xxhash/v2"
|
||||
"github.com/klauspost/crc32"
|
||||
"github.com/minio/crc64nvme"
|
||||
"github.com/zeebo/xxh3"
|
||||
)
|
||||
|
||||
// ChecksumMode contains information about the checksum mode on the object
|
||||
@@ -49,6 +53,9 @@ const (
|
||||
|
||||
// checksumModeMask is a mask for valid checksum mode types.
|
||||
checksumModeMask = checksumLastMode - 1
|
||||
|
||||
// ChecksumUnknownMode indicates no or unknown checksum mode.
|
||||
ChecksumUnknownMode ChecksumMode = 0
|
||||
)
|
||||
|
||||
// Is returns if c is all of t.
|
||||
@@ -64,9 +71,9 @@ func (c ChecksumMode) Key() string {
|
||||
func (c ChecksumMode) String() string {
|
||||
switch c & checksumModeMask {
|
||||
case ChecksumFullObjectMode:
|
||||
return "FULL_OBJECT"
|
||||
return amzChecksumModeFullObject
|
||||
case ChecksumCompositeMode:
|
||||
return "COMPOSITE"
|
||||
return amzChecksumModeComposite
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -86,6 +93,16 @@ const (
|
||||
ChecksumCRC32C
|
||||
// ChecksumCRC64NVME indicates CRC64 with 0xad93d23594c93659 polynomial.
|
||||
ChecksumCRC64NVME
|
||||
// ChecksumMD5 indicates an MD5 checksum.
|
||||
ChecksumMD5
|
||||
// ChecksumSHA512 indicates a SHA-512 checksum.
|
||||
ChecksumSHA512
|
||||
// ChecksumXXHash64 indicates an XXHash64 checksum.
|
||||
ChecksumXXHash64
|
||||
// ChecksumXXHash3 indicates an XXH3-64 checksum.
|
||||
ChecksumXXHash3
|
||||
// ChecksumXXHash128 indicates an XXH3-128 checksum.
|
||||
ChecksumXXHash128
|
||||
|
||||
// Keep after all valid checksums
|
||||
checksumLast
|
||||
@@ -112,7 +129,15 @@ const (
|
||||
amzChecksumSHA1 = "x-amz-checksum-sha1"
|
||||
amzChecksumSHA256 = "x-amz-checksum-sha256"
|
||||
amzChecksumCRC64NVME = "x-amz-checksum-crc64nvme"
|
||||
amzChecksumMD5 = "x-amz-checksum-md5"
|
||||
amzChecksumSHA512 = "x-amz-checksum-sha512"
|
||||
amzChecksumXXHash64 = "x-amz-checksum-xxhash64"
|
||||
amzChecksumXXHash3 = "x-amz-checksum-xxhash3"
|
||||
amzChecksumXXHash128 = "x-amz-checksum-xxhash128"
|
||||
amzChecksumMode = "x-amz-checksum-type"
|
||||
|
||||
amzChecksumModeComposite = "COMPOSITE"
|
||||
amzChecksumModeFullObject = "FULL_OBJECT"
|
||||
)
|
||||
|
||||
// Base returns the base type, without modifiers.
|
||||
@@ -139,6 +164,16 @@ func (c ChecksumType) Key() string {
|
||||
return amzChecksumSHA256
|
||||
case ChecksumCRC64NVME:
|
||||
return amzChecksumCRC64NVME
|
||||
case ChecksumMD5:
|
||||
return amzChecksumMD5
|
||||
case ChecksumSHA512:
|
||||
return amzChecksumSHA512
|
||||
case ChecksumXXHash64:
|
||||
return amzChecksumXXHash64
|
||||
case ChecksumXXHash3:
|
||||
return amzChecksumXXHash3
|
||||
case ChecksumXXHash128:
|
||||
return amzChecksumXXHash128
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -146,7 +181,8 @@ func (c ChecksumType) Key() string {
|
||||
// CanComposite will return if the checksum type can be used for composite multipart upload on AWS.
|
||||
func (c ChecksumType) CanComposite() bool {
|
||||
switch c & checksumMask {
|
||||
case ChecksumSHA256, ChecksumSHA1, ChecksumCRC32, ChecksumCRC32C:
|
||||
case ChecksumSHA256, ChecksumSHA1, ChecksumCRC32, ChecksumCRC32C,
|
||||
ChecksumMD5, ChecksumSHA512, ChecksumXXHash64, ChecksumXXHash3, ChecksumXXHash128:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -186,6 +222,14 @@ func (c ChecksumType) RawByteLen() int {
|
||||
return sha256.Size
|
||||
case ChecksumCRC64NVME:
|
||||
return crc64nvme.Size
|
||||
case ChecksumXXHash64, ChecksumXXHash3:
|
||||
return 8
|
||||
case ChecksumMD5:
|
||||
return md5.Size
|
||||
case ChecksumSHA512:
|
||||
return sha512.Size
|
||||
case ChecksumXXHash128:
|
||||
return 16
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -206,6 +250,16 @@ func (c ChecksumType) Hasher() hash.Hash {
|
||||
return sha256.New()
|
||||
case ChecksumCRC64NVME:
|
||||
return crc64nvme.New()
|
||||
case ChecksumMD5:
|
||||
return md5.New()
|
||||
case ChecksumSHA512:
|
||||
return sha512.New()
|
||||
case ChecksumXXHash64:
|
||||
return xxhash.New()
|
||||
case ChecksumXXHash3:
|
||||
return xxh3.New()
|
||||
case ChecksumXXHash128:
|
||||
return xxh3.New128()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -233,7 +287,6 @@ func (c ChecksumType) EncodeToString(b []byte) string {
|
||||
}
|
||||
|
||||
// String returns the type as a string.
|
||||
// CRC32, CRC32C, SHA1, and SHA256 for valid values.
|
||||
// Empty string for unset and "<invalid>" if not valid.
|
||||
func (c ChecksumType) String() string {
|
||||
switch c & checksumMask {
|
||||
@@ -249,6 +302,16 @@ func (c ChecksumType) String() string {
|
||||
return ""
|
||||
case ChecksumCRC64NVME:
|
||||
return "CRC64NVME"
|
||||
case ChecksumMD5:
|
||||
return "MD5"
|
||||
case ChecksumSHA512:
|
||||
return "SHA512"
|
||||
case ChecksumXXHash64:
|
||||
return "XXHASH64"
|
||||
case ChecksumXXHash3:
|
||||
return "XXHASH3"
|
||||
case ChecksumXXHash128:
|
||||
return "XXHASH128"
|
||||
}
|
||||
return "<invalid>"
|
||||
}
|
||||
|
||||
+4
-4
@@ -94,15 +94,15 @@ var awsS3EndpointMap = map[string]awsS3Endpoint{
|
||||
},
|
||||
"us-iso-east-1": {
|
||||
"s3.us-iso-east-1.c2s.ic.gov",
|
||||
"s3.dualstack.us-iso-east-1.c2s.ic.gov",
|
||||
"", // dualstack endpoint doesn't exist
|
||||
},
|
||||
"us-isob-east-1": {
|
||||
"s3.us-isob-east-1.sc2s.sgov.gov",
|
||||
"s3.dualstack.us-isob-east-1.sc2s.sgov.gov",
|
||||
"", // dualstack endpoint doesn't exist
|
||||
},
|
||||
"us-iso-west-1": {
|
||||
"s3.us-iso-west-1.c2s.ic.gov",
|
||||
"s3.dualstack.us-iso-west-1.c2s.ic.gov",
|
||||
"", // dualstack endpoint doesn't exist
|
||||
},
|
||||
"us-west-2": {
|
||||
"s3.us-west-2.amazonaws.com",
|
||||
@@ -269,7 +269,7 @@ func getS3Endpoint(bucketLocation string, useDualstack bool) (endpoint string) {
|
||||
}
|
||||
return "s3.us-east-1.amazonaws.com"
|
||||
}
|
||||
if useDualstack {
|
||||
if useDualstack && s3Endpoint.dualstackEndpoint != "" {
|
||||
return s3Endpoint.dualstackEndpoint
|
||||
}
|
||||
return s3Endpoint.endpoint
|
||||
|
||||
+160
-4
@@ -73,8 +73,25 @@ const (
|
||||
enableKMS = "ENABLE_KMS"
|
||||
appVersion = "0.1.0"
|
||||
skipCERTValidation = "SKIP_CERT_VALIDATION"
|
||||
|
||||
// TODO: remove when server supports the 2026 checksum types.
|
||||
ignore2026Checksums = true
|
||||
)
|
||||
|
||||
func ignore2026ChecksumError(cs minio.ChecksumType, err error) bool {
|
||||
if !ignore2026Checksums {
|
||||
return false
|
||||
}
|
||||
switch cs.Base() {
|
||||
case minio.ChecksumMD5, minio.ChecksumSHA512,
|
||||
minio.ChecksumXXHash64, minio.ChecksumXXHash3, minio.ChecksumXXHash128:
|
||||
default:
|
||||
return false
|
||||
}
|
||||
var er minio.ErrorResponse
|
||||
return errors.As(err, &er) && er.Code == "InvalidArgument"
|
||||
}
|
||||
|
||||
func createHTTPTransport() (transport *http.Transport) {
|
||||
var err error
|
||||
transport, err = minio.DefaultTransport(mustParseBool(os.Getenv(enableHTTPS)))
|
||||
@@ -2096,6 +2113,11 @@ func testPutObjectWithChecksums() {
|
||||
tests := []struct {
|
||||
cs minio.ChecksumType
|
||||
}{
|
||||
{cs: minio.ChecksumMD5},
|
||||
{cs: minio.ChecksumSHA512},
|
||||
{cs: minio.ChecksumXXHash64},
|
||||
{cs: minio.ChecksumXXHash3},
|
||||
{cs: minio.ChecksumXXHash128},
|
||||
{cs: minio.ChecksumCRC32C},
|
||||
{cs: minio.ChecksumCRC32},
|
||||
{cs: minio.ChecksumSHA1},
|
||||
@@ -2160,6 +2182,10 @@ func testPutObjectWithChecksums() {
|
||||
UserMetadata: meta,
|
||||
})
|
||||
if err != nil {
|
||||
if ignore2026ChecksumError(test.cs, err) {
|
||||
logIgnored(testName, function, args, startTime, "server does not support "+test.cs.String())
|
||||
continue
|
||||
}
|
||||
logError(testName, function, args, startTime, "", "PutObject failed", err)
|
||||
return
|
||||
}
|
||||
@@ -2168,6 +2194,11 @@ func testPutObjectWithChecksums() {
|
||||
cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
|
||||
cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
|
||||
cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
|
||||
cmpChecksum(resp.ChecksumMD5, meta["x-amz-checksum-md5"])
|
||||
cmpChecksum(resp.ChecksumSHA512, meta["x-amz-checksum-sha512"])
|
||||
cmpChecksum(resp.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
|
||||
cmpChecksum(resp.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
|
||||
cmpChecksum(resp.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
|
||||
if resp.ChecksumMode != minio.ChecksumFullObjectMode.String() {
|
||||
logError(testName, function, args, startTime, "", "Checksum mode is not full object", fmt.Errorf("got %s, want %s", resp.ChecksumMode, minio.ChecksumFullObjectMode.String()))
|
||||
}
|
||||
@@ -2191,6 +2222,11 @@ func testPutObjectWithChecksums() {
|
||||
cmpChecksum(st.ChecksumCRC32, meta["x-amz-checksum-crc32"])
|
||||
cmpChecksum(st.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
|
||||
cmpChecksum(st.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
|
||||
cmpChecksum(st.ChecksumMD5, meta["x-amz-checksum-md5"])
|
||||
cmpChecksum(st.ChecksumSHA512, meta["x-amz-checksum-sha512"])
|
||||
cmpChecksum(st.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
|
||||
cmpChecksum(st.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
|
||||
cmpChecksum(st.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
|
||||
if st.ChecksumMode != minio.ChecksumFullObjectMode.String() {
|
||||
logError(testName, function, args, startTime, "", "Checksum mode is not full object", fmt.Errorf("got %s, want %s", st.ChecksumMode, minio.ChecksumFullObjectMode.String()))
|
||||
}
|
||||
@@ -2238,6 +2274,11 @@ func testPutObjectWithChecksums() {
|
||||
cmpChecksum(st.ChecksumCRC32, "")
|
||||
cmpChecksum(st.ChecksumCRC32C, "")
|
||||
cmpChecksum(st.ChecksumCRC64NVME, "")
|
||||
cmpChecksum(st.ChecksumMD5, "")
|
||||
cmpChecksum(st.ChecksumSHA512, "")
|
||||
cmpChecksum(st.ChecksumXXHash64, "")
|
||||
cmpChecksum(st.ChecksumXXHash3, "")
|
||||
cmpChecksum(st.ChecksumXXHash128, "")
|
||||
|
||||
delete(args, "range")
|
||||
delete(args, "metadata")
|
||||
@@ -2283,6 +2324,11 @@ func testPutObjectWithTrailingChecksums() {
|
||||
tests := []struct {
|
||||
cs minio.ChecksumType
|
||||
}{
|
||||
{cs: minio.ChecksumMD5},
|
||||
{cs: minio.ChecksumSHA512},
|
||||
{cs: minio.ChecksumXXHash64},
|
||||
{cs: minio.ChecksumXXHash3},
|
||||
{cs: minio.ChecksumXXHash128},
|
||||
{cs: minio.ChecksumCRC64NVME},
|
||||
{cs: minio.ChecksumCRC32C},
|
||||
{cs: minio.ChecksumCRC32},
|
||||
@@ -2329,6 +2375,10 @@ func testPutObjectWithTrailingChecksums() {
|
||||
Checksum: test.cs,
|
||||
})
|
||||
if err != nil {
|
||||
if ignore2026ChecksumError(test.cs, err) {
|
||||
logIgnored(testName, function, args, startTime, "server does not support "+test.cs.String())
|
||||
continue
|
||||
}
|
||||
logError(testName, function, args, startTime, "", "PutObject failed", err)
|
||||
return
|
||||
}
|
||||
@@ -2341,6 +2391,11 @@ func testPutObjectWithTrailingChecksums() {
|
||||
cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
|
||||
cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
|
||||
cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
|
||||
cmpChecksum(resp.ChecksumMD5, meta["x-amz-checksum-md5"])
|
||||
cmpChecksum(resp.ChecksumSHA512, meta["x-amz-checksum-sha512"])
|
||||
cmpChecksum(resp.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
|
||||
cmpChecksum(resp.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
|
||||
cmpChecksum(resp.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
|
||||
|
||||
// Read the data back
|
||||
gopts := minio.GetObjectOptions{Checksum: true}
|
||||
@@ -2361,7 +2416,12 @@ func testPutObjectWithTrailingChecksums() {
|
||||
cmpChecksum(st.ChecksumSHA1, meta["x-amz-checksum-sha1"])
|
||||
cmpChecksum(st.ChecksumCRC32, meta["x-amz-checksum-crc32"])
|
||||
cmpChecksum(st.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
|
||||
cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
|
||||
cmpChecksum(st.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
|
||||
cmpChecksum(st.ChecksumMD5, meta["x-amz-checksum-md5"])
|
||||
cmpChecksum(st.ChecksumSHA512, meta["x-amz-checksum-sha512"])
|
||||
cmpChecksum(st.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
|
||||
cmpChecksum(st.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
|
||||
cmpChecksum(st.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
|
||||
|
||||
if st.Size != int64(bufSize) {
|
||||
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
|
||||
@@ -2407,6 +2467,11 @@ func testPutObjectWithTrailingChecksums() {
|
||||
cmpChecksum(st.ChecksumCRC32, "")
|
||||
cmpChecksum(st.ChecksumCRC32C, "")
|
||||
cmpChecksum(st.ChecksumCRC64NVME, "")
|
||||
cmpChecksum(st.ChecksumMD5, "")
|
||||
cmpChecksum(st.ChecksumSHA512, "")
|
||||
cmpChecksum(st.ChecksumXXHash64, "")
|
||||
cmpChecksum(st.ChecksumXXHash3, "")
|
||||
cmpChecksum(st.ChecksumXXHash128, "")
|
||||
|
||||
function = "GetObjectAttributes(...)"
|
||||
s, err := c.GetObjectAttributes(context.Background(), bucketName, objectName, minio.ObjectAttributesOptions{})
|
||||
@@ -2418,6 +2483,16 @@ func testPutObjectWithTrailingChecksums() {
|
||||
cmpChecksum(s.Checksum.ChecksumSHA1, meta["x-amz-checksum-sha1"])
|
||||
cmpChecksum(s.Checksum.ChecksumCRC32, meta["x-amz-checksum-crc32"])
|
||||
cmpChecksum(s.Checksum.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
|
||||
cmpChecksum(s.Checksum.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
|
||||
cmpChecksum(s.Checksum.ChecksumMD5, meta["x-amz-checksum-md5"])
|
||||
cmpChecksum(s.Checksum.ChecksumSHA512, meta["x-amz-checksum-sha512"])
|
||||
cmpChecksum(s.Checksum.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
|
||||
cmpChecksum(s.Checksum.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
|
||||
cmpChecksum(s.Checksum.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
|
||||
if s.Checksum.ChecksumType != "" && s.Checksum.ChecksumType != minio.ChecksumFullObjectMode.String() {
|
||||
logError(testName, function, args, startTime, "", "ChecksumType mismatch in GetObjectAttributes", fmt.Errorf("want %s, got %s", minio.ChecksumFullObjectMode.String(), s.Checksum.ChecksumType))
|
||||
return
|
||||
}
|
||||
|
||||
delete(args, "range")
|
||||
delete(args, "metadata")
|
||||
@@ -2495,6 +2570,11 @@ func testPutMultipartObjectWithChecksums() {
|
||||
tests := []struct {
|
||||
cs minio.ChecksumType
|
||||
}{
|
||||
{cs: minio.ChecksumMD5},
|
||||
{cs: minio.ChecksumSHA512},
|
||||
{cs: minio.ChecksumXXHash64},
|
||||
{cs: minio.ChecksumXXHash3},
|
||||
{cs: minio.ChecksumXXHash128},
|
||||
{cs: minio.ChecksumFullObjectCRC32},
|
||||
{cs: minio.ChecksumFullObjectCRC32C},
|
||||
{cs: minio.ChecksumCRC64NVME},
|
||||
@@ -2552,6 +2632,10 @@ func testPutMultipartObjectWithChecksums() {
|
||||
Checksum: cs,
|
||||
})
|
||||
if err != nil {
|
||||
if ignore2026ChecksumError(test.cs, err) {
|
||||
logIgnored(testName, function, args, startTime, "server does not support "+test.cs.String())
|
||||
continue
|
||||
}
|
||||
logError(testName, function, args, startTime, "", "PutObject failed", err)
|
||||
return
|
||||
}
|
||||
@@ -2567,6 +2651,16 @@ func testPutMultipartObjectWithChecksums() {
|
||||
cmpChecksum(resp.ChecksumSHA256, wantChksm)
|
||||
case minio.ChecksumCRC64NVME:
|
||||
cmpChecksum(resp.ChecksumCRC64NVME, wantChksm)
|
||||
case minio.ChecksumMD5:
|
||||
cmpChecksum(resp.ChecksumMD5, wantChksm)
|
||||
case minio.ChecksumSHA512:
|
||||
cmpChecksum(resp.ChecksumSHA512, wantChksm)
|
||||
case minio.ChecksumXXHash64:
|
||||
cmpChecksum(resp.ChecksumXXHash64, wantChksm)
|
||||
case minio.ChecksumXXHash3:
|
||||
cmpChecksum(resp.ChecksumXXHash3, wantChksm)
|
||||
case minio.ChecksumXXHash128:
|
||||
cmpChecksum(resp.ChecksumXXHash128, wantChksm)
|
||||
}
|
||||
|
||||
args["section"] = "HeadObject"
|
||||
@@ -2586,6 +2680,16 @@ func testPutMultipartObjectWithChecksums() {
|
||||
cmpChecksum(st.ChecksumSHA256, wantChksm)
|
||||
case minio.ChecksumCRC64NVME:
|
||||
cmpChecksum(st.ChecksumCRC64NVME, wantChksm)
|
||||
case minio.ChecksumMD5:
|
||||
cmpChecksum(st.ChecksumMD5, wantChksm)
|
||||
case minio.ChecksumSHA512:
|
||||
cmpChecksum(st.ChecksumSHA512, wantChksm)
|
||||
case minio.ChecksumXXHash64:
|
||||
cmpChecksum(st.ChecksumXXHash64, wantChksm)
|
||||
case minio.ChecksumXXHash3:
|
||||
cmpChecksum(st.ChecksumXXHash3, wantChksm)
|
||||
case minio.ChecksumXXHash128:
|
||||
cmpChecksum(st.ChecksumXXHash128, wantChksm)
|
||||
}
|
||||
|
||||
// Use the CopyObject API to make a copy, in the case it was a composite checksum,
|
||||
@@ -2622,6 +2726,16 @@ func testPutMultipartObjectWithChecksums() {
|
||||
cmpChecksum(st.ChecksumSHA256, wantFullObjectChksm)
|
||||
case minio.ChecksumCRC64NVME:
|
||||
cmpChecksum(st.ChecksumCRC64NVME, wantFullObjectChksm)
|
||||
case minio.ChecksumMD5:
|
||||
cmpChecksum(st.ChecksumMD5, wantFullObjectChksm)
|
||||
case minio.ChecksumSHA512:
|
||||
cmpChecksum(st.ChecksumSHA512, wantFullObjectChksm)
|
||||
case minio.ChecksumXXHash64:
|
||||
cmpChecksum(st.ChecksumXXHash64, wantFullObjectChksm)
|
||||
case minio.ChecksumXXHash3:
|
||||
cmpChecksum(st.ChecksumXXHash3, wantFullObjectChksm)
|
||||
case minio.ChecksumXXHash128:
|
||||
cmpChecksum(st.ChecksumXXHash128, wantFullObjectChksm)
|
||||
}
|
||||
|
||||
args["section"] = "GetObjectAttributes"
|
||||
@@ -2644,6 +2758,35 @@ func testPutMultipartObjectWithChecksums() {
|
||||
cmpChecksum(s.Checksum.ChecksumSHA1, wantChksm)
|
||||
case minio.ChecksumSHA256:
|
||||
cmpChecksum(s.Checksum.ChecksumSHA256, wantChksm)
|
||||
case minio.ChecksumCRC64NVME:
|
||||
cmpChecksum(s.Checksum.ChecksumCRC64NVME, wantChksm)
|
||||
case minio.ChecksumMD5:
|
||||
cmpChecksum(s.Checksum.ChecksumMD5, wantChksm)
|
||||
case minio.ChecksumSHA512:
|
||||
cmpChecksum(s.Checksum.ChecksumSHA512, wantChksm)
|
||||
case minio.ChecksumXXHash64:
|
||||
cmpChecksum(s.Checksum.ChecksumXXHash64, wantChksm)
|
||||
case minio.ChecksumXXHash3:
|
||||
cmpChecksum(s.Checksum.ChecksumXXHash3, wantChksm)
|
||||
case minio.ChecksumXXHash128:
|
||||
cmpChecksum(s.Checksum.ChecksumXXHash128, wantChksm)
|
||||
}
|
||||
|
||||
if s.Checksum.ChecksumType != "" {
|
||||
var wantType string
|
||||
if test.cs.FullObjectRequested() {
|
||||
wantType = minio.ChecksumFullObjectMode.String()
|
||||
} else {
|
||||
wantType = minio.ChecksumCompositeMode.String()
|
||||
}
|
||||
cmpChecksum(s.Checksum.ChecksumType, wantType)
|
||||
}
|
||||
|
||||
for _, part := range s.ObjectParts.Parts {
|
||||
if test.cs == minio.ChecksumCRC64NVME && part.ChecksumCRC64NVME == "" {
|
||||
logError(testName, function, args, startTime, "", "Part missing CRC64NVME checksum in GetObjectAttributes", fmt.Errorf("part %d", part.PartNumber))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Read the data back
|
||||
@@ -2684,6 +2827,16 @@ func testPutMultipartObjectWithChecksums() {
|
||||
if st.ChecksumCRC64NVME != "" {
|
||||
cmpChecksum(st.ChecksumCRC64NVME, wantChksm)
|
||||
}
|
||||
case minio.ChecksumMD5:
|
||||
cmpChecksum(st.ChecksumMD5, wantChksm)
|
||||
case minio.ChecksumSHA512:
|
||||
cmpChecksum(st.ChecksumSHA512, wantChksm)
|
||||
case minio.ChecksumXXHash64:
|
||||
cmpChecksum(st.ChecksumXXHash64, wantChksm)
|
||||
case minio.ChecksumXXHash3:
|
||||
cmpChecksum(st.ChecksumXXHash3, wantChksm)
|
||||
case minio.ChecksumXXHash128:
|
||||
cmpChecksum(st.ChecksumXXHash128, wantChksm)
|
||||
}
|
||||
|
||||
delete(args, "metadata")
|
||||
@@ -3475,6 +3628,8 @@ func validateObjectAttributeRequest(OA *minio.ObjectAttributes, opts *minio.Obje
|
||||
checksumFound = true
|
||||
} else if v.ChecksumCRC32C != "" {
|
||||
checksumFound = true
|
||||
} else if v.ChecksumCRC64NVME != "" {
|
||||
checksumFound = true
|
||||
}
|
||||
if !checksumFound {
|
||||
partsMissingChecksum = true
|
||||
@@ -3497,6 +3652,7 @@ func validateObjectAttributeRequest(OA *minio.ObjectAttributes, opts *minio.Obje
|
||||
|
||||
hasFullObjectChecksum := (OA.Checksum.ChecksumCRC32 != "" ||
|
||||
OA.Checksum.ChecksumCRC32C != "" ||
|
||||
OA.Checksum.ChecksumCRC64NVME != "" ||
|
||||
OA.Checksum.ChecksumSHA1 != "" ||
|
||||
OA.Checksum.ChecksumSHA256 != "")
|
||||
|
||||
@@ -14789,6 +14945,9 @@ func main() {
|
||||
|
||||
// execute tests
|
||||
if isFullMode() {
|
||||
testPutObjectWithChecksums()
|
||||
testPutObjectWithTrailingChecksums()
|
||||
testPutMultipartObjectWithChecksums()
|
||||
testCopyObjectWithChecksums()
|
||||
testReplaceObjectWithChecksums()
|
||||
testCorsSetGetDelete()
|
||||
@@ -14808,9 +14967,6 @@ func main() {
|
||||
testComposeObjectErrorCasesV2()
|
||||
testCompose10KSourcesV2()
|
||||
testUserMetadataCopyingV2()
|
||||
testPutObjectWithChecksums()
|
||||
testPutObjectWithTrailingChecksums()
|
||||
testPutMultipartObjectWithChecksums()
|
||||
testPutObject0ByteV2()
|
||||
testPutObjectMetadataNonUSASCIIV2()
|
||||
testPutObjectNoLengthV2()
|
||||
|
||||
+21
@@ -119,6 +119,10 @@ var elbAmazonCnRegex = regexp.MustCompile(`elb(.*?).amazonaws.com.cn$`)
|
||||
// amazonS3HostPrivateLink - regular expression used to determine if an arg is s3 host in AWS PrivateLink interface endpoints style
|
||||
var amazonS3HostPrivateLink = regexp.MustCompile(`^(?:bucket|accesspoint).vpce-.*?.s3.(.*?).vpce.amazonaws.com$`)
|
||||
|
||||
// amazonS3HostOutposts - regular expression used to determine if an arg is S3 on Outposts endpoint.
|
||||
// Pattern: <something>.s3-outposts.<region>.amazonaws.com
|
||||
var amazonS3HostOutposts = regexp.MustCompile(`^(.+)\.s3-outposts\.([a-z0-9-]+)\.amazonaws\.com$`)
|
||||
|
||||
// GetRegionFromURL - returns a region from url host.
|
||||
func GetRegionFromURL(endpointURL url.URL) string {
|
||||
if endpointURL == sentinelURL {
|
||||
@@ -181,6 +185,11 @@ func GetRegionFromURL(endpointURL url.URL) string {
|
||||
return parts[1]
|
||||
}
|
||||
|
||||
parts = amazonS3HostOutposts.FindStringSubmatch(endpointURL.Hostname())
|
||||
if len(parts) > 2 {
|
||||
return parts[2]
|
||||
}
|
||||
|
||||
parts = amazonS3HostDot.FindStringSubmatch(endpointURL.Hostname())
|
||||
if len(parts) > 1 {
|
||||
if strings.HasPrefix(parts[1], "xpress-") {
|
||||
@@ -210,8 +219,20 @@ func IsAmazonExpressZonalEndpoint(endpointURL url.URL) bool {
|
||||
return amazonS3HostExpress.MatchString(endpointURL.Hostname())
|
||||
}
|
||||
|
||||
// IsAmazonOutpostsEndpoint - Match if the endpoint is S3 on Outposts endpoint.
|
||||
func IsAmazonOutpostsEndpoint(endpointURL url.URL) bool {
|
||||
if endpointURL == sentinelURL {
|
||||
return false
|
||||
}
|
||||
return amazonS3HostOutposts.MatchString(endpointURL.Hostname())
|
||||
}
|
||||
|
||||
// IsAmazonEndpoint - Match if it is exactly Amazon S3 endpoint.
|
||||
// S3 on Outposts is not treated as Amazon S3 here so that the client keeps path-style and does not replace the host.
|
||||
func IsAmazonEndpoint(endpointURL url.URL) bool {
|
||||
if IsAmazonOutpostsEndpoint(endpointURL) {
|
||||
return false
|
||||
}
|
||||
if endpointURL.Hostname() == "s3-external-1.amazonaws.com" || endpointURL.Hostname() == "s3.amazonaws.com" {
|
||||
return true
|
||||
}
|
||||
|
||||
+80
-30
@@ -90,32 +90,34 @@ func getStreamLength(dataLen, chunkSize int64, trailers http.Header) int64 {
|
||||
return streamLen
|
||||
}
|
||||
|
||||
// buildChunkStringToSign - returns the string to sign given chunk data
|
||||
// and previous signature.
|
||||
func buildChunkStringToSign(t time.Time, region, previousSig, chunkChecksum string) string {
|
||||
// buildChunkStringToSignWithService - like buildChunkStringToSign but with configurable service type.
|
||||
func buildChunkStringToSignWithService(t time.Time, region, previousSig, chunkChecksum, serviceType string) string {
|
||||
if serviceType == "" {
|
||||
serviceType = ServiceTypeS3
|
||||
}
|
||||
stringToSignParts := []string{
|
||||
streamingPayloadHdr,
|
||||
t.Format(iso8601DateFormat),
|
||||
getScope(region, t, ServiceTypeS3),
|
||||
getScope(region, t, serviceType),
|
||||
previousSig,
|
||||
emptySHA256,
|
||||
chunkChecksum,
|
||||
}
|
||||
|
||||
return strings.Join(stringToSignParts, "\n")
|
||||
}
|
||||
|
||||
// buildTrailerChunkStringToSign - returns the string to sign given chunk data
|
||||
// and previous signature.
|
||||
func buildTrailerChunkStringToSign(t time.Time, region, previousSig, chunkChecksum string) string {
|
||||
// buildTrailerChunkStringToSignWithService - like buildTrailerChunkStringToSign but with configurable service type.
|
||||
func buildTrailerChunkStringToSignWithService(t time.Time, region, previousSig, chunkChecksum, serviceType string) string {
|
||||
if serviceType == "" {
|
||||
serviceType = ServiceTypeS3
|
||||
}
|
||||
stringToSignParts := []string{
|
||||
streamingTrailerHdr,
|
||||
t.Format(iso8601DateFormat),
|
||||
getScope(region, t, ServiceTypeS3),
|
||||
getScope(region, t, serviceType),
|
||||
previousSig,
|
||||
chunkChecksum,
|
||||
}
|
||||
|
||||
return strings.Join(stringToSignParts, "\n")
|
||||
}
|
||||
|
||||
@@ -150,36 +152,42 @@ func buildChunkHeader(chunkLen int64, signature string) []byte {
|
||||
}
|
||||
|
||||
// buildChunkSignature - returns chunk signature for a given chunk and previous signature.
|
||||
// serviceType defaults to ServiceTypeS3 when empty.
|
||||
func buildChunkSignature(chunkCheckSum string, reqTime time.Time, region,
|
||||
previousSignature, secretAccessKey string,
|
||||
previousSignature, secretAccessKey, serviceType string,
|
||||
) string {
|
||||
chunkStringToSign := buildChunkStringToSign(reqTime, region,
|
||||
previousSignature, chunkCheckSum)
|
||||
signingKey := getSigningKey(secretAccessKey, region, reqTime, ServiceTypeS3)
|
||||
if serviceType == "" {
|
||||
serviceType = ServiceTypeS3
|
||||
}
|
||||
chunkStringToSign := buildChunkStringToSignWithService(reqTime, region,
|
||||
previousSignature, chunkCheckSum, serviceType)
|
||||
signingKey := getSigningKey(secretAccessKey, region, reqTime, serviceType)
|
||||
return getSignature(signingKey, chunkStringToSign)
|
||||
}
|
||||
|
||||
// buildChunkSignature - returns chunk signature for a given chunk and previous signature.
|
||||
// buildTrailerChunkSignature - returns chunk signature for trailer chunk.
|
||||
// serviceType defaults to ServiceTypeS3 when empty.
|
||||
func buildTrailerChunkSignature(chunkChecksum string, reqTime time.Time, region,
|
||||
previousSignature, secretAccessKey string,
|
||||
previousSignature, secretAccessKey, serviceType string,
|
||||
) string {
|
||||
chunkStringToSign := buildTrailerChunkStringToSign(reqTime, region,
|
||||
previousSignature, chunkChecksum)
|
||||
signingKey := getSigningKey(secretAccessKey, region, reqTime, ServiceTypeS3)
|
||||
if serviceType == "" {
|
||||
serviceType = ServiceTypeS3
|
||||
}
|
||||
chunkStringToSign := buildTrailerChunkStringToSignWithService(reqTime, region,
|
||||
previousSignature, chunkChecksum, serviceType)
|
||||
signingKey := getSigningKey(secretAccessKey, region, reqTime, serviceType)
|
||||
return getSignature(signingKey, chunkStringToSign)
|
||||
}
|
||||
|
||||
// getSeedSignature - returns the seed signature for a given request.
|
||||
func (s *StreamingReader) setSeedSignature(req *http.Request) {
|
||||
// Get canonical request
|
||||
serviceType := s.serviceType
|
||||
if serviceType == "" {
|
||||
serviceType = ServiceTypeS3
|
||||
}
|
||||
canonicalRequest := getCanonicalRequest(*req, ignoredStreamingHeaders, getHashedPayload(*req))
|
||||
|
||||
// Get string to sign from canonical request.
|
||||
stringToSign := getStringToSignV4(s.reqTime, s.region, canonicalRequest, ServiceTypeS3)
|
||||
|
||||
signingKey := getSigningKey(s.secretAccessKey, s.region, s.reqTime, ServiceTypeS3)
|
||||
|
||||
// Calculate signature.
|
||||
stringToSign := getStringToSignV4(s.reqTime, s.region, canonicalRequest, serviceType)
|
||||
signingKey := getSigningKey(s.secretAccessKey, s.region, s.reqTime, serviceType)
|
||||
s.seedSignature = getSignature(signingKey, stringToSign)
|
||||
}
|
||||
|
||||
@@ -190,6 +198,7 @@ type StreamingReader struct {
|
||||
secretAccessKey string
|
||||
sessionToken string
|
||||
region string
|
||||
serviceType string // e.g. ServiceTypeS3, ServiceTypeS3Outposts; empty means S3
|
||||
prevSignature string
|
||||
seedSignature string
|
||||
contentLen int64 // Content-Length from req header
|
||||
@@ -214,8 +223,12 @@ func (s *StreamingReader) signChunk(chunkLen int, addCrLf bool) {
|
||||
s.sh256.Write(s.chunkBuf[:chunkLen])
|
||||
chunckChecksum := hex.EncodeToString(s.sh256.Sum(nil))
|
||||
|
||||
serviceType := s.serviceType
|
||||
if serviceType == "" {
|
||||
serviceType = ServiceTypeS3
|
||||
}
|
||||
signature := buildChunkSignature(chunckChecksum, s.reqTime,
|
||||
s.region, s.prevSignature, s.secretAccessKey)
|
||||
s.region, s.prevSignature, s.secretAccessKey, serviceType)
|
||||
|
||||
// For next chunk signature computation
|
||||
s.prevSignature = signature
|
||||
@@ -249,9 +262,12 @@ func (s *StreamingReader) addSignedTrailer(h http.Header) {
|
||||
s.sh256.Reset()
|
||||
s.sh256.Write(s.chunkBuf)
|
||||
chunkChecksum := hex.EncodeToString(s.sh256.Sum(nil))
|
||||
// Compute chunk signature
|
||||
serviceType := s.serviceType
|
||||
if serviceType == "" {
|
||||
serviceType = ServiceTypeS3
|
||||
}
|
||||
signature := buildTrailerChunkSignature(chunkChecksum, s.reqTime,
|
||||
s.region, s.prevSignature, s.secretAccessKey)
|
||||
s.region, s.prevSignature, s.secretAccessKey, serviceType)
|
||||
|
||||
// For next chunk signature computation
|
||||
s.prevSignature = signature
|
||||
@@ -376,6 +392,40 @@ func StreamingSignV4(req *http.Request, accessKeyID, secretAccessKey, sessionTok
|
||||
return req
|
||||
}
|
||||
|
||||
// StreamingSignV4Outposts - provides chunked upload signatureV4 support for S3 on Outposts (service name s3-outposts).
|
||||
func StreamingSignV4Outposts(req *http.Request, accessKeyID, secretAccessKey, sessionToken,
|
||||
region string, dataLen int64, reqTime time.Time, sh256 md5simd.Hasher,
|
||||
) *http.Request {
|
||||
prepareStreamingRequest(req, sessionToken, dataLen, reqTime)
|
||||
if req.Body == nil {
|
||||
req.Body = io.NopCloser(bytes.NewReader([]byte("")))
|
||||
}
|
||||
stReader := &StreamingReader{
|
||||
baseReadCloser: req.Body,
|
||||
accessKeyID: accessKeyID,
|
||||
secretAccessKey: secretAccessKey,
|
||||
sessionToken: sessionToken,
|
||||
region: region,
|
||||
serviceType: ServiceTypeS3Outposts,
|
||||
reqTime: reqTime,
|
||||
chunkBuf: make([]byte, payloadChunkSize),
|
||||
contentLen: dataLen,
|
||||
chunkNum: 1,
|
||||
totalChunks: int((dataLen+payloadChunkSize-1)/payloadChunkSize) + 1,
|
||||
lastChunkSize: int(dataLen % payloadChunkSize),
|
||||
sh256: sh256,
|
||||
}
|
||||
if len(req.Trailer) > 0 {
|
||||
stReader.trailer = req.Trailer
|
||||
req.Trailer = nil
|
||||
}
|
||||
stReader.setSeedSignature(req)
|
||||
stReader.setStreamingAuthHeader(req, ServiceTypeS3Outposts)
|
||||
stReader.prevSignature = stReader.seedSignature
|
||||
req.Body = stReader
|
||||
return req
|
||||
}
|
||||
|
||||
// Read - this method performs chunk upload signature providing a
|
||||
// io.Reader interface.
|
||||
func (s *StreamingReader) Read(buf []byte) (int, error) {
|
||||
|
||||
+51
-3
@@ -38,9 +38,10 @@ const (
|
||||
|
||||
// Different service types
|
||||
const (
|
||||
ServiceTypeS3 = "s3"
|
||||
ServiceTypeSTS = "sts"
|
||||
ServiceTypeS3Express = "s3express"
|
||||
ServiceTypeS3 = "s3"
|
||||
ServiceTypeSTS = "sts"
|
||||
ServiceTypeS3Express = "s3express"
|
||||
ServiceTypeS3Outposts = "s3-outposts"
|
||||
)
|
||||
|
||||
// Excerpts from @lsegal -
|
||||
@@ -256,6 +257,38 @@ func PreSignV4(req http.Request, accessKeyID, secretAccessKey, sessionToken, loc
|
||||
return &req
|
||||
}
|
||||
|
||||
// PreSignV4Outposts presign the request for S3 on Outposts (service name s3-outposts).
|
||||
func PreSignV4Outposts(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string, expires int64) *http.Request {
|
||||
// Presign is not needed for anonymous credentials.
|
||||
if accessKeyID == "" || secretAccessKey == "" {
|
||||
return &req
|
||||
}
|
||||
|
||||
t := time.Now().UTC()
|
||||
credential := GetCredential(accessKeyID, location, t, ServiceTypeS3Outposts)
|
||||
signedHeaders := getSignedHeaders(req, v4IgnoredHeaders)
|
||||
query := req.URL.Query()
|
||||
query.Set("X-Amz-Algorithm", signV4Algorithm)
|
||||
query.Set("X-Amz-Date", t.Format(iso8601DateFormat))
|
||||
query.Set("X-Amz-Expires", strconv.FormatInt(expires, 10))
|
||||
query.Set("X-Amz-SignedHeaders", signedHeaders)
|
||||
query.Set("X-Amz-Credential", credential)
|
||||
if sessionToken != "" {
|
||||
if v := req.Header.Get("x-amz-s3session-token"); v != "" {
|
||||
query.Set("X-Amz-S3session-Token", sessionToken)
|
||||
} else {
|
||||
query.Set("X-Amz-Security-Token", sessionToken)
|
||||
}
|
||||
}
|
||||
req.URL.RawQuery = query.Encode()
|
||||
canonicalRequest := getCanonicalRequest(req, v4IgnoredHeaders, getHashedPayload(req))
|
||||
stringToSign := getStringToSignV4(t, location, canonicalRequest, ServiceTypeS3Outposts)
|
||||
signingKey := getSigningKey(secretAccessKey, location, t, ServiceTypeS3Outposts)
|
||||
signature := getSignature(signingKey, stringToSign)
|
||||
req.URL.RawQuery += "&X-Amz-Signature=" + signature
|
||||
return &req
|
||||
}
|
||||
|
||||
// PostPresignSignatureV4 - presigned signature for PostPolicy
|
||||
// requests.
|
||||
func PostPresignSignatureV4(policyBase64 string, t time.Time, secretAccessKey, location string) string {
|
||||
@@ -393,3 +426,18 @@ func SignV4TrailerExpress(req http.Request, accessKeyID, secretAccessKey, sessio
|
||||
func SignV4Trailer(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string, trailer http.Header) *http.Request {
|
||||
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, ServiceTypeS3, trailer)
|
||||
}
|
||||
|
||||
// SignV4Outposts sign the request for S3 on Outposts (service name s3-outposts).
|
||||
func SignV4Outposts(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string) *http.Request {
|
||||
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, ServiceTypeS3Outposts, nil)
|
||||
}
|
||||
|
||||
// SignV4WithServiceType signs a request with AWS Signature Version 4 using a custom service type.
|
||||
func SignV4WithServiceType(req http.Request, accessKeyID, secretAccessKey, sessionToken, location, serviceType string) *http.Request {
|
||||
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, serviceType, nil)
|
||||
}
|
||||
|
||||
// SignV4TrailerOutposts sign the request with trailer for S3 on Outposts (service name s3-outposts).
|
||||
func SignV4TrailerOutposts(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string, trailer http.Header) *http.Request {
|
||||
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, ServiceTypeS3Outposts, trailer)
|
||||
}
|
||||
|
||||
+21
@@ -18,6 +18,7 @@
|
||||
package tags
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"net/url"
|
||||
@@ -293,6 +294,26 @@ func (tags Tags) ToMap() map[string]string {
|
||||
return tags.TagSet.toMap()
|
||||
}
|
||||
|
||||
// MarshalJSON encodes Tags as a flat JSON object {"key":"value",...}.
|
||||
func (tags Tags) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(tags.ToMap())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes a flat JSON object {"key":"value",...} into Tags.
|
||||
func (tags *Tags) UnmarshalJSON(data []byte) error {
|
||||
var m map[string]string
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return err
|
||||
}
|
||||
if tags.TagSet == nil {
|
||||
tags.TagSet = &tagSet{
|
||||
tagMap: make(map[string]string),
|
||||
}
|
||||
}
|
||||
tags.TagSet.tagMap = m
|
||||
return nil
|
||||
}
|
||||
|
||||
// MapToObjectTags converts an input map of key and value into
|
||||
// *Tags data structure with validation.
|
||||
func MapToObjectTags(tagMap map[string]string) (*Tags, error) {
|
||||
|
||||
+27
@@ -179,6 +179,11 @@ func isValidEndpointURL(endpointURL url.URL) error {
|
||||
return errInvalidArgument("Google Cloud Storage endpoint should be 'storage.googleapis.com'.")
|
||||
}
|
||||
}
|
||||
if strings.Contains(host, "s3-outposts") {
|
||||
if !s3utils.IsAmazonOutpostsEndpoint(endpointURL) {
|
||||
return errInvalidArgument("S3 Outposts endpoint must match <prefix>.s3-outposts.<region>.amazonaws.com")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -304,6 +309,21 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
||||
Region: h.Get("x-amz-bucket-region"),
|
||||
}
|
||||
}
|
||||
mtimeStr := h.Get("X-Minio-Source-Mtime")
|
||||
if mtimeStr != "" {
|
||||
mtime, err = time.Parse(time.RFC3339Nano, mtimeStr)
|
||||
if err != nil {
|
||||
return ObjectInfo{}, ErrorResponse{
|
||||
Code: InternalError,
|
||||
Message: fmt.Sprintf("X-Minio-Source-Mtime is not in supported format: %v", err),
|
||||
BucketName: bucketName,
|
||||
Key: objectName,
|
||||
RequestID: h.Get("x-amz-request-id"),
|
||||
HostID: h.Get("x-amz-id-2"),
|
||||
Region: h.Get("x-amz-bucket-region"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch content type if any present.
|
||||
contentType := strings.TrimSpace(h.Get("Content-Type"))
|
||||
@@ -381,6 +401,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
||||
Size: size,
|
||||
LastModified: mtime,
|
||||
ContentType: contentType,
|
||||
ContentEncoding: strings.TrimSpace(h.Get("Content-Encoding")),
|
||||
Expires: expiry,
|
||||
VersionID: h.Get(amzVersionID),
|
||||
IsDeleteMarker: deleteMarker,
|
||||
@@ -402,6 +423,12 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
|
||||
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
|
||||
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
|
||||
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
|
||||
ChecksumMD5: h.Get(ChecksumMD5.Key()),
|
||||
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
|
||||
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
|
||||
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
|
||||
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
|
||||
ChecksumAlgorithm: h.Get(amzChecksumAlgo),
|
||||
ChecksumMode: h.Get(ChecksumFullObjectMode.Key()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
+14
@@ -1,3 +1,17 @@
|
||||
## 2.28.3
|
||||
|
||||
### Maintenance
|
||||
Bump all dependencies
|
||||
|
||||
## 2.28.2
|
||||
|
||||
- Add ArtifactDir() to support Go 1.26 testing.TB interface [f3a36b6]
|
||||
- Implement shell completion [94151c8]
|
||||
- Add asan CLI option mirroring msan implementation [4d21dbb]
|
||||
- Bump uri from 1.0.3 to 1.0.4 in /docs (#1630) [c102161]
|
||||
- fix aspect ratio [9619647]
|
||||
- update logos [5779304]
|
||||
|
||||
## 2.28.1
|
||||
|
||||
Update all dependencies. This auto-updated the required version of Go to 1.24, consistent with the fact that Go 1.23 has been out of support for almost six months.
|
||||
|
||||
+1
-1
@@ -120,6 +120,6 @@ Sponsors commit to a [sponsorship](https://github.com/sponsors/onsi) for a year.
|
||||
|
||||
<p style="font-size:21px; color:black;">Browser testing via
|
||||
<a href="https://www.testmu.ai/" target="_blank">
|
||||
<img src="https://www.testmu.ai/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
|
||||
<img src="https://assets.testmu.ai/resources/images/logos/white-logo.png" style="vertical-align: middle;" width="250" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
+164
@@ -1,9 +1,13 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2/formatter"
|
||||
@@ -158,6 +162,166 @@ func (p Program) handleHelpRequestsAndExit(writer io.Writer, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
type completionOptions = struct {
|
||||
Complete bool
|
||||
Install bool
|
||||
}
|
||||
|
||||
func (p *Program) BuildCompletionCommand() Command {
|
||||
opts := completionOptions{}
|
||||
flags, err := types.NewGinkgoFlagSet(
|
||||
types.GinkgoFlags{
|
||||
{Name: "complete", KeyPath: "Complete", Usage: "Generate completion for arguments after --"},
|
||||
{Name: "install", KeyPath: "Install", Usage: "Install shell completion script into $XDG_DATA_HOME, ~/.local/share"},
|
||||
},
|
||||
&opts,
|
||||
types.GinkgoFlagSections{},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return Command{
|
||||
Name: "completion",
|
||||
Usage: "ginkgo completion <FLAGS> <SHELL> [-- <COMPLETE>]",
|
||||
Flags: flags,
|
||||
ShortDoc: "Generate shell completion",
|
||||
Documentation: `To use install completion script for your shell (bash, fish, zsh).
|
||||
Or load completion code by: {{bold}}source <(ginkgo completion <SHELL>){{/}}.`,
|
||||
Command: func(args []string, completeArgs []string) {
|
||||
p.handleCompletionAndExit(args, completeArgs, opts)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p Program) generateShellCompletionScript(shell string) (scriptPath string, script string) {
|
||||
switch shell {
|
||||
case "bash":
|
||||
scriptPath = fmt.Sprintf("bash-completion/completions/%s", p.Name)
|
||||
script = fmt.Sprintf(`__%s_complete_bash() {
|
||||
mapfile -t COMPREPLY < <("${COMP_WORDS[0]}" completion --complete bash -- "${COMP_WORDS[@]:1:COMP_CWORD}")
|
||||
}
|
||||
complete -o bashdefault -o default -F __%[1]s_complete_bash %[1]s
|
||||
`, p.Name)
|
||||
|
||||
case "fish":
|
||||
scriptPath = fmt.Sprintf("fish/vendor_completions.d/%s.fish", p.Name)
|
||||
script = fmt.Sprintf(`function __fish_%[1]s_complete
|
||||
set -l args (commandline -opc) (commandline -ct)
|
||||
set -e args[1]
|
||||
%[1]s completion --complete fish -- $args
|
||||
end
|
||||
complete -c %[1]s -a "(__fish_%[1]s_complete)"
|
||||
`, p.Name)
|
||||
|
||||
case "zsh":
|
||||
scriptPath = fmt.Sprintf("zsh/site-functions/_%s", p.Name)
|
||||
script = fmt.Sprintf(`#compdef %[1]s
|
||||
_%[1]s() {
|
||||
local -a completions
|
||||
completions=(${(f)"$("${words[1]}" completion --complete zsh -- "${words[@]:1:$((CURRENT-1))}")"})
|
||||
if (( ${#completions[@]} )); then
|
||||
_describe 'completions' completions
|
||||
else
|
||||
_default
|
||||
fi
|
||||
}
|
||||
compdef _%[1]s %[1]s
|
||||
if [ "$funcstack[1]" = "_%[1]s" ]; then
|
||||
_%[1]s
|
||||
fi
|
||||
`, p.Name)
|
||||
|
||||
case "":
|
||||
AbortWithUsage("Shell is not specified")
|
||||
default:
|
||||
AbortWith("Shell %q is not supported yet. Choose: bash, fish, zsh", shell)
|
||||
}
|
||||
|
||||
return scriptPath, script
|
||||
}
|
||||
|
||||
func (p Program) handleCompletionAndExit(args, completeArgs []string, opts completionOptions) {
|
||||
writer := p.OutWriter
|
||||
if writer == nil {
|
||||
writer = os.Stdout
|
||||
}
|
||||
buffer := bufio.NewWriter(writer)
|
||||
defer buffer.Flush()
|
||||
|
||||
var shell string
|
||||
if len(args) > 0 {
|
||||
shell = args[0]
|
||||
}
|
||||
|
||||
if !opts.Complete {
|
||||
scriptPath, script := p.generateShellCompletionScript(shell)
|
||||
if opts.Install {
|
||||
dataHomeDir := os.Getenv("XDG_DATA_HOME")
|
||||
if dataHomeDir == "" {
|
||||
userHomeDir, err := os.UserHomeDir()
|
||||
AbortIfError("Failed to find home", err)
|
||||
dataHomeDir = filepath.Join(userHomeDir, ".local/share")
|
||||
}
|
||||
scriptPath = filepath.Join(dataHomeDir, scriptPath)
|
||||
fmt.Fprintf(buffer, "Installing completion script: %v\n", scriptPath)
|
||||
err := os.WriteFile(scriptPath, []byte(script), 0644)
|
||||
AbortIfError("Failed to install completion script", err)
|
||||
} else {
|
||||
buffer.Write([]byte(script))
|
||||
}
|
||||
Abort(AbortDetails{})
|
||||
}
|
||||
|
||||
var lastArg string
|
||||
var result map[string]string
|
||||
if len(completeArgs) > 0 {
|
||||
lastArg = completeArgs[len(completeArgs)-1]
|
||||
}
|
||||
|
||||
if delim := slices.Index(completeArgs, "--"); delim >= 0 && delim != len(completeArgs)-1 {
|
||||
// No completion for pass-through arguments after "--"
|
||||
} else if len(lastArg) > 0 && lastArg[0] == '-' {
|
||||
// Complete flags
|
||||
cmd := &p.DefaultCommand
|
||||
for i := range p.Commands {
|
||||
if p.Commands[i].Name == completeArgs[0] {
|
||||
cmd = &p.Commands[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
result = cmd.Flags.Completion(lastArg)
|
||||
} else if len(completeArgs) <= 1 {
|
||||
// Complete commands
|
||||
result = make(map[string]string, len(p.Commands)+1)
|
||||
for _, cmd := range append(p.Commands, p.DefaultCommand) {
|
||||
if strings.HasPrefix(cmd.Name, lastArg) {
|
||||
result[cmd.Name] = cmd.Usage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
width := 0
|
||||
for suggest := range result {
|
||||
width = max(width, len(suggest))
|
||||
}
|
||||
|
||||
for _, suggest := range slices.Sorted(maps.Keys(result)) {
|
||||
usage := result[suggest]
|
||||
switch {
|
||||
case shell == "bash" && usage != "" && len(result) > 1:
|
||||
fmt.Fprintf(buffer, "%*s (%s)\n", -width-2, suggest, usage)
|
||||
case shell == "fish":
|
||||
fmt.Fprintf(buffer, "%s\t%s\n", suggest, usage)
|
||||
case shell == "zsh":
|
||||
fmt.Fprintf(buffer, "%s:%s\n", suggest, usage)
|
||||
default:
|
||||
fmt.Fprintln(buffer, suggest)
|
||||
}
|
||||
}
|
||||
|
||||
Abort(AbortDetails{})
|
||||
}
|
||||
|
||||
func (p Program) EmitUsage(writer io.Writer) {
|
||||
fmt.Fprintln(writer, formatter.F(p.Heading))
|
||||
fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(p.Heading))))
|
||||
|
||||
+1
@@ -41,6 +41,7 @@ func main() {
|
||||
{Name: "nodot", Deprecation: types.Deprecations.Nodot()},
|
||||
},
|
||||
}
|
||||
program.Commands = append(program.Commands, program.BuildCompletionCommand())
|
||||
|
||||
program.RunAndExit(os.Args)
|
||||
}
|
||||
|
||||
+4
@@ -72,6 +72,7 @@ type GinkgoTInterface interface {
|
||||
TempDir() string
|
||||
Attr(key, value string)
|
||||
Output() io.Writer
|
||||
ArtifactDir() string
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -196,3 +197,6 @@ func (g *GinkgoTBWrapper) Attr(key, value string) {
|
||||
func (g *GinkgoTBWrapper) Output() io.Writer {
|
||||
return g.GinkgoT.Output()
|
||||
}
|
||||
func (g *GinkgoTBWrapper) ArtifactDir() string {
|
||||
return g.GinkgoT.ArtifactDir()
|
||||
}
|
||||
|
||||
+9
@@ -181,6 +181,15 @@ func (t *ginkgoTestingTProxy) TempDir() string {
|
||||
return tmpDir
|
||||
}
|
||||
|
||||
func (t *ginkgoTestingTProxy) ArtifactDir() string {
|
||||
artifactDir, err := os.MkdirTemp("", "ginkgo")
|
||||
if err != nil {
|
||||
t.fail(fmt.Sprintf("Failed to create artifact directory: %v", err), 1)
|
||||
return ""
|
||||
}
|
||||
return artifactDir
|
||||
}
|
||||
|
||||
// FullGinkgoTInterface
|
||||
func (t *ginkgoTestingTProxy) AddReportEntryVisibilityAlways(name string, args ...any) {
|
||||
finalArgs := []any{internal.Offset(1), types.ReportEntryVisibilityAlways}
|
||||
|
||||
+3
@@ -215,6 +215,7 @@ type GoFlagsConfig struct {
|
||||
N bool
|
||||
ModFile string
|
||||
ModCacheRW bool
|
||||
ASan bool
|
||||
MSan bool
|
||||
PkgDir string
|
||||
Tags string
|
||||
@@ -570,6 +571,8 @@ var GoBuildFlags = GinkgoFlags{
|
||||
Usage: "leave newly-created directories in the module cache read-write instead of making them read-only."},
|
||||
{KeyPath: "Go.ModFile", Name: "modfile", UsageArgument: "file", SectionKey: "go-build",
|
||||
Usage: `in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named go.mod must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".`},
|
||||
{KeyPath: "Go.ASan", Name: "asan", SectionKey: "go-build",
|
||||
Usage: "enable interoperation with address sanitizer."},
|
||||
{KeyPath: "Go.MSan", Name: "msan", SectionKey: "go-build",
|
||||
Usage: "enable interoperation with memory sanitizer. Supported only on linux/amd64, linux/arm64 and only with Clang/LLVM as the host C compiler. On linux/arm64, pie build mode will be used."},
|
||||
{KeyPath: "Go.N", Name: "n", SectionKey: "go-build",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user