aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/BUG.md39
-rw-r--r--.github/ISSUE_TEMPLATE/FEATURE.md17
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md51
-rw-r--r--.github/workflows/tests.yml55
-rw-r--r--.golangci.yml19
-rw-r--r--README.md2
-rw-r--r--build.go2
-rw-r--r--changelog/unreleased/issue-1899
-rw-r--r--changelog/unreleased/pull-3229
-rw-r--r--cmd/rest-server/listener_unix_test.go5
-rw-r--r--cmd/rest-server/main.go23
-rw-r--r--cmd/rest-server/main_test.go12
-rw-r--r--go.mod29
-rw-r--r--go.sum67
-rw-r--r--handlers.go48
-rw-r--r--handlers_test.go21
-rw-r--r--htpasswd_test.go3
-rw-r--r--quota/quota.go2
-rw-r--r--repo/repo.go81
19 files changed, 282 insertions, 212 deletions
diff --git a/.github/ISSUE_TEMPLATE/BUG.md b/.github/ISSUE_TEMPLATE/BUG.md
index 99ba4b8..0bbe234 100644
--- a/.github/ISSUE_TEMPLATE/BUG.md
+++ b/.github/ISSUE_TEMPLATE/BUG.md
@@ -3,8 +3,8 @@ name: Bug report
about: Report a problem with rest-server to help us resolve it and improve
---
-
<!--
+
Welcome! - We kindly ask that you:
1. Fill out the issue template below - not doing so needs a good reason.
@@ -24,6 +24,7 @@ for tracking bugs and feature requests directly relating to the development of
the software itself, rather than the project.
Thanks for understanding, and for contributing to the project!
+
-->
@@ -31,22 +32,24 @@ Output of `rest-server --version` <!-- If using docker, output of `docker images
---------------------------------
-How did you run rest-server exactly?
-------------------------------------
+
+Problem description / Steps to reproduce
+----------------------------------------
<!--
This section should include at least:
+ * A description of the problem you are having with rest-server.
+
* The complete command line and any environment variables you used to
- configure rest-server's backend access. Make sure to replace sensitive values!
+ configure rest-server. Make sure to replace sensitive values!
* The output of the commands, what rest-server prints gives may give us much
information to diagnose the problem!
--->
-
-What backend/server/service did you use to store the repository?
-----------------------------------------------------------------
+ * The more time you spend describing an easy way to reproduce the behavior (if
+ this is possible), the easier it is for the project developers to fix it!
+-->
Expected behavior
@@ -56,30 +59,20 @@ Expected behavior
Describe what you'd like rest-server to do differently.
-->
-
Actual behavior
---------------
<!--
-Please try to concentrate on observations, so only describe what you observed directly.
+In this section, please try to concentrate on observations, so only describe
+what you observed directly.
-->
-
-Steps to reproduce the behavior
--------------------------------
-
-<!--
-The more time you spend describing an easy way to reproduce the behavior (if
-this is possible), the easier it is for the project developers to fix it!
--->
-
-
Do you have any idea what may have caused this?
-----------------------------------------------
-
-Do you have an idea how to solve the issue?
--------------------------------------------
+<!--
+Did something noteworthy happen on your system, Internet connection, backend services, etc?
+-->
Did rest-server help you today? Did it make you happy in any way?
diff --git a/.github/ISSUE_TEMPLATE/FEATURE.md b/.github/ISSUE_TEMPLATE/FEATURE.md
index a1be40f..a5fc46a 100644
--- a/.github/ISSUE_TEMPLATE/FEATURE.md
+++ b/.github/ISSUE_TEMPLATE/FEATURE.md
@@ -1,10 +1,10 @@
---
-name: Feature request/enhancement
+name: Feature request
about: Suggest a new feature or enhancement for rest-server
---
-
<!--
+
Welcome! - We kindly ask that you:
1. Fill out the issue template below - not doing so needs a good reason.
@@ -18,6 +18,7 @@ for tracking bugs and feature requests directly relating to the development of
the software itself, rather than the project.
Thanks for understanding, and for contributing to the project!
+
-->
@@ -30,24 +31,22 @@ later to see what has changed in rest-server when we revisit this issue after so
time.
-->
-
-What should rest-server do differently?
----------------------------------------
+What should rest-server do differently? Which functionality do you think we should add?
+---------------------------------------------------------------------------------------
<!--
-Please describe the feature you'd like to see added or changed here.
+Please describe the feature you'd like us to add here.
-->
-What are you trying to do? What is your use case?
--------------------------------------------------
+What are you trying to do? What problem would this solve?
+---------------------------------------------------------
<!--
This section should contain a brief description what you're trying to do, which
would be possible after implementing the new feature.
-->
-
Did rest-server help you today? Did it make you happy in any way?
-----------------------------------------------------------------
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 574054d..00d5da1 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,42 +1,41 @@
<!--
-Thank you very much for contributing code or documentation to rest-server!
-
-Please note that each PR should be preceded by an issue where the suggested
-change can be discussed in general and without focus on specific code. That
-way, work done in the PR will better match what's been agreed in the issue.
-
-Please fill out the following questions to make it easier for us to review
-your changes. You don't have to check all the checkboxes at once, instead
-feel free to add more commits over time.
+Thank you very much for contributing code or documentation to rest-server! Please
+fill out the following questions to make it easier for us to review your
+changes.
-->
-
-What is the purpose of this change? What does it change?
---------------------------------------------------------
+What does this PR change? What problem does it solve?
+-----------------------------------------------------
<!--
-Describe the changes here, as detailed as needed.
+Describe the changes and their purpose here, as detailed as needed.
-->
-
-Was the change discussed in an issue or in the forum before?
-------------------------------------------------------------
+Was the change previously discussed in an issue or on the forum?
+----------------------------------------------------------------
<!--
Link issues and relevant forum posts here.
-If this PR resolves an issue on GitHub, write "Closes #1234" such
-that the issue is closed automatically when this PR is merged.
+If this PR resolves an issue on GitHub, use "Closes #1234" so that the issue
+is closed automatically when this PR is merged.
-->
-
Checklist
---------
-- [ ] I have enabled [maintainer edits for this PR](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork)
-- [ ] I have added tests for all changes in this PR
-- [ ] I have added documentation for the changes (in the manual)
-- [ ] There's a new file in `changelog/unreleased/` that describes the changes for our users (template [here](https://github.com/restic/rest-server/blob/master/changelog/TEMPLATE))
-- [ ] I have run `gofmt` on the code in all commits
-- [ ] All commit messages are formatted in the same style as [the other commits in the repo](https://github.com/restic/rest-server/commits/master)
-- [ ] I'm done, this Pull Request is ready for review
+<!--
+You do not need to check all the boxes below all at once. Feel free to take
+your time and add more commits. If you're done and ready for review, please
+check the last box. Enable a checkbox by replacing [ ] with [x].
+
+Please always follow these steps:
+- Enable [maintainer edits](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork).
+- Run `gofmt` on the code in all commits.
+- Format all commit messages in the same style as [the other commits in the repository](https://github.com/restic/rest-server/blob/master/CONTRIBUTING.md#git-commits).
+-->
+
+- [ ] I have added tests for all code changes.
+- [ ] I have added documentation for relevant changes (in the manual).
+- [ ] There's a new file in `changelog/unreleased/` that describes the changes for our users (see [template](https://github.com/restic/rest-server/blob/master/changelog/TEMPLATE)).
+- [ ] I'm done! This pull request is ready for review.
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 7baec42..00e6c99 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -7,9 +7,13 @@ on:
# run tests for all pull requests
pull_request:
+ merge_group:
+
+permissions:
+ contents: read
env:
- latest_go: "1.21.x"
+ latest_go: "1.23.x"
GO111MODULE: on
jobs:
@@ -17,10 +21,8 @@ jobs:
strategy:
matrix:
go:
- - 1.18.x
- - 1.19.x
- - 1.20.x
- - 1.21.x
+ - 1.23.x
+ - 1.22.x
runs-on: ubuntu-latest
name: Go ${{ matrix.go }}
@@ -28,25 +30,21 @@ jobs:
GOPROXY: https://proxy.golang.org
steps:
+ - name: Check out code
+ uses: actions/checkout@v4
+
- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- - name: Check out code
- uses: actions/checkout@v4
-
- - name: Build
- run: |
- go build ./cmd/rest-server
-
- name: Build with build.go
run: |
go run build.go --goos linux
go run build.go --goos windows
go run build.go --goos darwin
- - name: Run tests
+ - name: Run local Tests
run: |
go test ./...
@@ -61,23 +59,25 @@ jobs:
lint:
name: lint
runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ # allow annotating code in the PR
+ checks: write
steps:
+ - name: Check out code
+ uses: actions/checkout@v4
+
- name: Set up Go ${{ env.latest_go }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.latest_go }}
- - name: Check out code
- uses: actions/checkout@v4
-
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
- version: v1.51
- # Optional: show only new issues if it's a pull request. The default value is `false`.
- only-new-issues: true
- args: --verbose --timeout 10m
+ version: v1.63.4
+ args: --verbose --timeout 5m
# only run golangci-lint for pull requests, otherwise ALL hints get
# reported. We need to slowly address all issues until we can enable
@@ -89,3 +89,18 @@ jobs:
echo "check if go.mod and go.sum are up to date"
go mod tidy
git diff --exit-code go.mod go.sum
+
+ analyze:
+ name: Analyze results
+ needs: [test, lint]
+ if: always()
+
+ permissions: # no need to access code
+ contents: none
+
+ runs-on: ubuntu-latest
+ steps:
+ - name: Decide whether the needed jobs succeeded or failed
+ uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe
+ with:
+ jobs: ${{ toJSON(needs) }}
diff --git a/.golangci.yml b/.golangci.yml
index 44dfcdc..b44c2c1 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -10,13 +10,10 @@ linters:
# make sure all errors returned by functions are handled
- errcheck
- # find unused code
- - deadcode
-
# show how code can be simplified
- gosimple
- # # make sure code is formatted
+ # make sure code is formatted
- gofmt
# examine code and report suspicious constructs, such as Printf calls whose
@@ -35,15 +32,14 @@ linters:
# find unused variables, functions, structs, types, etc.
- unused
- # find unused struct fields
- - structcheck
-
- # find unused global variables
- - varcheck
-
# parse and typecheck code
- typecheck
+ # ensure that http response bodies are closed
+ - bodyclose
+
+ - importas
+
issues:
# don't use the default exclude rules, this hides (among others) ignored
# errors from Close() calls
@@ -55,3 +51,6 @@ issues:
- exported (function|method|var|type|const) .* should have comment or be unexported
# revive: ignore constants in all caps
- don't use ALL_CAPS in Go names; use CamelCase
+ # revive: lots of packages don't have such a comment
+ - "package-comments: should have a package comment"
+ - "redefines-builtin-id:"
diff --git a/README.md b/README.md
index d4fa296..6a5ba1a 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ Rest Server is a high performance HTTP server that implements restic's [REST bac
## Requirements
-Rest Server requires Go 1.18 or higher to build. The only tested compiler is the official Go compiler. Building server with `gccgo` may work, but is not supported.
+Rest Server requires Go 1.22 or higher to build. The only tested compiler is the official Go compiler.
The required version of restic backup client to use with `rest-server` is [v0.7.1](https://github.com/restic/restic/releases/tag/v0.7.1) or higher.
diff --git a/build.go b/build.go
index 3ddc7e9..12d4c8c 100644
--- a/build.go
+++ b/build.go
@@ -58,7 +58,7 @@ var config = Config{
Namespace: "github.com/restic/rest-server", // subdir of GOPATH, e.g. "github.com/foo/bar"
Main: "github.com/restic/rest-server/cmd/rest-server", // package name for the main package
Tests: []string{"./..."}, // tests to run
- MinVersion: GoVersion{Major: 1, Minor: 15, Patch: 0}, // minimum Go version supported
+ MinVersion: GoVersion{Major: 1, Minor: 22, Patch: 0}, // minimum Go version supported
}
// Config configures the build.
diff --git a/changelog/unreleased/issue-189 b/changelog/unreleased/issue-189
new file mode 100644
index 0000000..f60bcd5
--- /dev/null
+++ b/changelog/unreleased/issue-189
@@ -0,0 +1,9 @@
+Enhancement: Support group accessible repositories
+
+Rest-server now supports making repositories accessible to the filesystem group
+by setting the `--group-accessible-repos` option. Note that permissions of
+existing files are not modified. Use `chmod -R g+rwX /path/to/repo` to make
+the repository group-accessible.
+
+https://github.com/restic/rest-server/issues/189
+https://github.com/restic/rest-server/pull/308
diff --git a/changelog/unreleased/pull-322 b/changelog/unreleased/pull-322
new file mode 100644
index 0000000..24bc274
--- /dev/null
+++ b/changelog/unreleased/pull-322
@@ -0,0 +1,9 @@
+Change: Update dependencies and require Go 1.22 or newer
+
+We have updated all dependencies. Since some libraries require newer Go standard
+library features, support for Go 1.18 to 1.21 has been dropped, which means
+that rest-server now requires at least Go 1.22 to build.
+
+This also disables support for TLS versions older than TLS 1.2.
+
+https://github.com/restic/rest-server/pull/322
diff --git a/cmd/rest-server/listener_unix_test.go b/cmd/rest-server/listener_unix_test.go
index a4f32f4..2143135 100644
--- a/cmd/rest-server/listener_unix_test.go
+++ b/cmd/rest-server/listener_unix_test.go
@@ -61,7 +61,10 @@ func TestUnixSocket(t *testing.T) {
if err != nil {
return err
}
- resp.Body.Close()
+ err = resp.Body.Close()
+ if err != nil {
+ return err
+ }
if resp.StatusCode != test.StatusCode {
return fmt.Errorf("expected %d from server, instead got %d (path %s)", test.StatusCode, resp.StatusCode, test.Path)
}
diff --git a/cmd/rest-server/main.go b/cmd/rest-server/main.go
index 5f0adb4..6658b0e 100644
--- a/cmd/rest-server/main.go
+++ b/cmd/rest-server/main.go
@@ -22,7 +22,7 @@ import (
type restServerApp struct {
CmdRoot *cobra.Command
Server restserver.Server
- CpuProfile string
+ CPUProfile string
listenerAddressMu sync.Mutex
listenerAddress net.Addr // set after startup
@@ -36,7 +36,7 @@ func newRestServerApp() *restServerApp {
Short: "Run a REST server for use with restic",
SilenceErrors: true,
SilenceUsage: true,
- Args: func(cmd *cobra.Command, args []string) error {
+ Args: func(_ *cobra.Command, args []string) error {
if len(args) != 0 {
return fmt.Errorf("rest-server expects no arguments - unknown argument: %s", args[0])
}
@@ -52,7 +52,7 @@ func newRestServerApp() *restServerApp {
rv.CmdRoot.RunE = rv.runRoot
flags := rv.CmdRoot.Flags()
- flags.StringVar(&rv.CpuProfile, "cpu-profile", rv.CpuProfile, "write CPU profile to file")
+ flags.StringVar(&rv.CPUProfile, "cpu-profile", rv.CPUProfile, "write CPU profile to file")
flags.BoolVar(&rv.Server.Debug, "debug", rv.Server.Debug, "output debug messages")
flags.StringVar(&rv.Server.Listen, "listen", rv.Server.Listen, "listen address")
flags.StringVar(&rv.Server.Log, "log", rv.Server.Log, "write HTTP requests in the combined log format to the specified `filename` (use \"-\" for logging to stdout)")
@@ -69,6 +69,7 @@ func newRestServerApp() *restServerApp {
flags.BoolVar(&rv.Server.PrivateRepos, "private-repos", rv.Server.PrivateRepos, "users can only access their private repo")
flags.BoolVar(&rv.Server.Prometheus, "prometheus", rv.Server.Prometheus, "enable Prometheus metrics")
flags.BoolVar(&rv.Server.PrometheusNoAuth, "prometheus-no-auth", rv.Server.PrometheusNoAuth, "disable auth for Prometheus /metrics endpoint")
+ flags.BoolVar(&rv.Server.GroupAccessibleRepos, "group-accessible-repos", rv.Server.GroupAccessibleRepos, "let filesystem group be able to access repo files")
// Ldap Options
flags.StringVar(&rv.Server.LdapAddr, "ldap-addr", rv.Server.LdapAddr, "ldap server address")
@@ -108,17 +109,19 @@ func (app *restServerApp) ListenerAddress() net.Addr {
return app.listenerAddress
}
-func (app *restServerApp) runRoot(cmd *cobra.Command, args []string) error {
+func (app *restServerApp) runRoot(_ *cobra.Command, _ []string) error {
log.SetFlags(0)
log.Printf("Data directory: %s", app.Server.Path)
- if app.CpuProfile != "" {
- f, err := os.Create(app.CpuProfile)
+ if app.CPUProfile != "" {
+ f, err := os.Create(app.CPUProfile)
if err != nil {
return err
}
- defer f.Close()
+ defer func() {
+ _ = f.Close()
+ }()
if err := pprof.StartCPUProfile(f); err != nil {
return err
@@ -152,6 +155,12 @@ func (app *restServerApp) runRoot(cmd *cobra.Command, args []string) error {
log.Println("Private repositories disabled")
}
+ if app.Server.GroupAccessibleRepos {
+ log.Println("Group accessible repos enabled")
+ } else {
+ log.Println("Group accessible repos disabled")
+ }
+
enabledTLS, privateKey, publicKey, err := app.tlsSettings()
if err != nil {
return err
diff --git a/cmd/rest-server/main_test.go b/cmd/rest-server/main_test.go
index 7366981..1171530 100644
--- a/cmd/rest-server/main_test.go
+++ b/cmd/rest-server/main_test.go
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
- "io/ioutil"
"net/http"
"net/url"
"os"
@@ -94,7 +93,7 @@ func TestTLSSettings(t *testing.T) {
}
func TestGetHandler(t *testing.T) {
- dir, err := ioutil.TempDir("", "rest-server-test")
+ dir, err := os.MkdirTemp("", "rest-server-test")
if err != nil {
t.Fatal(err)
}
@@ -120,7 +119,7 @@ func TestGetHandler(t *testing.T) {
}
// With NoAuth = false and custom .htpasswd
- htpFile, err := ioutil.TempFile(dir, "custom")
+ htpFile, err := os.CreateTemp(dir, "custom")
if err != nil {
t.Fatal(err)
}
@@ -137,7 +136,7 @@ func TestGetHandler(t *testing.T) {
// Create .htpasswd
htpasswd := filepath.Join(dir, ".htpasswd")
- err = ioutil.WriteFile(htpasswd, []byte(""), 0644)
+ err = os.WriteFile(htpasswd, []byte(""), 0644)
if err != nil {
t.Fatal(err)
}
@@ -262,7 +261,10 @@ func TestHttpListen(t *testing.T) {
if err != nil {
return err
}
- resp.Body.Close()
+ err = resp.Body.Close()
+ if err != nil {
+ return err
+ }
if resp.StatusCode != test.StatusCode {
return fmt.Errorf("expected %d from server, instead got %d (path %s)", test.StatusCode, resp.StatusCode, test.Path)
}
diff --git a/go.mod b/go.mod
index ed3f725..f6cbc15 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/restic/rest-server
-go 1.18
+go 1.22
require (
github.com/coreos/go-systemd/v22 v22.5.0
@@ -8,25 +8,26 @@ require (
github.com/gorilla/handlers v1.5.2
github.com/minio/sha256-simd v1.0.1
github.com/miolini/datacounter v1.0.3
- github.com/prometheus/client_golang v1.18.0
- github.com/spf13/cobra v1.8.1
- golang.org/x/crypto v0.27.0
+ github.com/prometheus/client_golang v1.20.5
+ github.com/spf13/cobra v1.9.1
+ golang.org/x/crypto v0.33.0
)
require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/beorn7/perks v1.0.1 // indirect
- github.com/cespare/xxhash/v2 v2.2.0 // indirect
- github.com/felixge/httpsnoop v1.0.3 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/klauspost/cpuid/v2 v2.2.5 // indirect
- github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
- github.com/prometheus/client_model v0.5.0 // indirect
- github.com/prometheus/common v0.45.0 // indirect
- github.com/prometheus/procfs v0.12.0 // indirect
- github.com/spf13/pflag v1.0.5 // indirect
- golang.org/x/sys v0.25.0 // indirect
- google.golang.org/protobuf v1.33.0 // indirect
+ github.com/klauspost/compress v1.17.9 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.9 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/prometheus/client_model v0.6.1 // indirect
+ github.com/prometheus/common v0.62.0 // indirect
+ github.com/prometheus/procfs v0.15.1 // indirect
+ github.com/spf13/pflag v1.0.6 // indirect
+ golang.org/x/sys v0.30.0 // indirect
+ google.golang.org/protobuf v1.36.5 // indirect
)
diff --git a/go.sum b/go.sum
index 6134709..ae941b4 100644
--- a/go.sum
+++ b/go.sum
@@ -4,22 +4,23 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
-github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
-github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
@@ -43,45 +44,50 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
-github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
-github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
-github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
-github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
+github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
+github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
+github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/miolini/datacounter v1.0.3 h1:tanOZPVblGXQl7/bSZWoEM8l4KK83q24qwQLMrO/HOA=
github.com/miolini/datacounter v1.0.3/go.mod h1:C45dc2hBumHjDpEU64IqPwR6TDyPVpzOqqRTN7zmBUA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
-github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
-github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
-github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
-github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
-github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
-github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
-github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
+github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
+github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
+github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
+github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
+github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
+github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
+github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
-github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
-github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
-github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
+github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
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/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -92,8 +98,9 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.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.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -106,8 +113,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -125,8 +132,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
-google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/handlers.go b/handlers.go
index fe8b027..ddd2df8 100644
--- a/handlers.go
+++ b/handlers.go
@@ -15,23 +15,24 @@ import (
// Server encapsulates the rest-server's settings and repo management logic
type Server struct {
- Path string
- HtpasswdPath string
- Listen string
- Log string
- CPUProfile string
- TLSKey string
- TLSCert string
- TLS bool
- NoAuth bool
- AppendOnly bool
- PrivateRepos bool
- Prometheus bool
- PrometheusNoAuth bool
- Debug bool
- MaxRepoSize int64
- PanicOnError bool
- NoVerifyUpload bool
+ Path string
+ HtpasswdPath string
+ Listen string
+ Log string
+ CPUProfile string
+ TLSKey string
+ TLSCert string
+ TLS bool
+ NoAuth bool
+ AppendOnly bool
+ PrivateRepos bool
+ Prometheus bool
+ PrometheusNoAuth bool
+ Debug bool
+ MaxRepoSize int64
+ PanicOnError bool
+ NoVerifyUpload bool
+ GroupAccessibleRepos bool
// LDAP Options
LdapAddr string
@@ -94,12 +95,13 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Pass the request to the repo.Handler
opt := repo.Options{
- AppendOnly: s.AppendOnly,
- Debug: s.Debug,
- QuotaManager: s.quotaManager, // may be nil
- PanicOnError: s.PanicOnError,
- NoVerifyUpload: s.NoVerifyUpload,
- FsyncWarning: &s.fsyncWarning,
+ AppendOnly: s.AppendOnly,
+ Debug: s.Debug,
+ QuotaManager: s.quotaManager, // may be nil
+ PanicOnError: s.PanicOnError,
+ NoVerifyUpload: s.NoVerifyUpload,
+ FsyncWarning: &s.fsyncWarning,
+ GroupAccessible: s.GroupAccessibleRepos,
}
if s.Prometheus {
opt.BlobMetricFunc = makeBlobMetricFunc(username, folderPath)
diff --git a/handlers_test.go b/handlers_test.go
index 279951f..38773a2 100644
--- a/handlers_test.go
+++ b/handlers_test.go
@@ -6,7 +6,6 @@ import (
"encoding/hex"
"fmt"
"io"
- "io/ioutil"
"net/http"
"net/http/httptest"
"os"
@@ -165,7 +164,7 @@ func createOverwriteDeleteSeq(t testing.TB, path string, data string) []TestRequ
return req
}
-func createTestHandler(t *testing.T, conf Server) (http.Handler, string, string, string, func()) {
+func createTestHandler(t *testing.T, conf *Server) (http.Handler, string, string, string, func()) {
buf := make([]byte, 32)
_, err := io.ReadFull(rand.Reader, buf)
if err != nil {
@@ -176,7 +175,7 @@ func createTestHandler(t *testing.T, conf Server) (http.Handler, string, string,
fileID := hex.EncodeToString(dataHash[:])
// setup the server with a local backend in a temporary directory
- tempdir, err := ioutil.TempDir("", "rest-server-test-")
+ tempdir, err := os.MkdirTemp("", "rest-server-test-")
if err != nil {
t.Fatal(err)
}
@@ -190,7 +189,7 @@ func createTestHandler(t *testing.T, conf Server) (http.Handler, string, string,
}
conf.Path = tempdir
- mux, err := NewHandler(&conf)
+ mux, err := NewHandler(conf)
if err != nil {
t.Fatalf("error from NewHandler: %v", err)
}
@@ -199,7 +198,7 @@ func createTestHandler(t *testing.T, conf Server) (http.Handler, string, string,
// TestResticAppendOnlyHandler runs tests on the restic handler code, especially in append-only mode.
func TestResticAppendOnlyHandler(t *testing.T) {
- mux, data, fileID, _, cleanup := createTestHandler(t, Server{
+ mux, data, fileID, _, cleanup := createTestHandler(t, &Server{
AppendOnly: true,
NoAuth: true,
Debug: true,
@@ -300,7 +299,7 @@ func createIdempotentDeleteSeq(t testing.TB, path string, data string) []TestReq
// TestResticHandler runs tests on the restic handler code, especially in append-only mode.
func TestResticHandler(t *testing.T) {
- mux, data, fileID, _, cleanup := createTestHandler(t, Server{
+ mux, data, fileID, _, cleanup := createTestHandler(t, &Server{
NoAuth: true,
Debug: true,
PanicOnError: true,
@@ -331,7 +330,7 @@ func TestResticHandler(t *testing.T) {
// TestResticErrorHandler runs tests on the restic handler error handling.
func TestResticErrorHandler(t *testing.T) {
- mux, _, _, tempdir, cleanup := createTestHandler(t, Server{
+ mux, _, _, tempdir, cleanup := createTestHandler(t, &Server{
AppendOnly: true,
NoAuth: true,
Debug: true,
@@ -380,7 +379,7 @@ func TestResticErrorHandler(t *testing.T) {
}
func TestEmptyList(t *testing.T) {
- mux, _, _, _, cleanup := createTestHandler(t, Server{
+ mux, _, _, _, cleanup := createTestHandler(t, &Server{
AppendOnly: true,
NoAuth: true,
Debug: true,
@@ -404,7 +403,7 @@ func TestEmptyList(t *testing.T) {
}
func TestListWithUnexpectedFiles(t *testing.T) {
- mux, _, _, tempdir, cleanup := createTestHandler(t, Server{
+ mux, _, _, tempdir, cleanup := createTestHandler(t, &Server{
AppendOnly: true,
NoAuth: true,
Debug: true,
@@ -510,7 +509,7 @@ func newDelayedErrorReader(err error) *delayErrorReader {
}
}
-func (d *delayErrorReader) Read(p []byte) (int, error) {
+func (d *delayErrorReader) Read(_ []byte) (int, error) {
d.firstReadOnce.Do(func() {
// close the channel to signal that the first read has happened
close(d.FirstRead)
@@ -522,7 +521,7 @@ func (d *delayErrorReader) Read(p []byte) (int, error) {
// TestAbortedRequest runs tests with concurrent upload requests for the same file.
func TestAbortedRequest(t *testing.T) {
// the race condition doesn't happen for append-only repositories
- mux, _, _, _, cleanup := createTestHandler(t, Server{
+ mux, _, _, _, cleanup := createTestHandler(t, &Server{
NoAuth: true,
Debug: true,
PanicOnError: true,
diff --git a/htpasswd_test.go b/htpasswd_test.go
index 869883b..fe3a46e 100644
--- a/htpasswd_test.go
+++ b/htpasswd_test.go
@@ -1,7 +1,6 @@
package restserver
import (
- "io/ioutil"
"os"
"testing"
)
@@ -12,7 +11,7 @@ func TestValidate(t *testing.T) {
rawPwd := "test"
wrongPwd := "wrong"
- tmpfile, err := ioutil.TempFile("", "rest-validate-")
+ tmpfile, err := os.CreateTemp("", "rest-validate-")
if err != nil {
t.Fatal(err)
}
diff --git a/quota/quota.go b/quota/quota.go
index 0b1020e..8437f65 100644
--- a/quota/quota.go
+++ b/quota/quota.go
@@ -113,7 +113,7 @@ func tallySize(path string) (int64, error) {
path = "."
}
var size int64
- err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
+ err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error {
if err != nil {
return err
}
diff --git a/repo/repo.go b/repo/repo.go
index d04879a..0e38bb6 100644
--- a/repo/repo.go
+++ b/repo/repo.go
@@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"log"
"math/rand"
"net/http"
@@ -29,8 +28,6 @@ import (
type Options struct {
AppendOnly bool // if set, delete actions are not allowed
Debug bool
- DirMode os.FileMode
- FileMode os.FileMode
NoVerifyUpload bool
// If set, we will panic when an internal server error happens. This
@@ -40,6 +37,13 @@ type Options struct {
BlobMetricFunc BlobMetricFunc
QuotaManager *quota.Manager
FsyncWarning *sync.Once
+
+ // If set makes files group accessible
+ GroupAccessible bool
+
+ // Defaults dir and file mode
+ dirMode os.FileMode
+ fileMode os.FileMode
}
// DefaultDirMode is the file mode used for directory creation if not
@@ -50,6 +54,14 @@ const DefaultDirMode os.FileMode = 0700
// overridden in the Options
const DefaultFileMode os.FileMode = 0600
+// GroupAccessibleDirMode is the file mode used for directory creation when
+// group access is enabled
+const GroupAccessibleDirMode os.FileMode = 0770
+
+// GroupAccessibleFileMode is the file mode used for file creation when
+// group access is enabled
+const GroupAccessibleFileMode os.FileMode = 0660
+
// New creates a new Handler for a single Restic backup repo.
// path is the full filesystem path to this repo directory.
// opt is a set of options.
@@ -57,12 +69,15 @@ func New(path string, opt Options) (*Handler, error) {
if path == "" {
return nil, fmt.Errorf("path is required")
}
- if opt.DirMode == 0 {
- opt.DirMode = DefaultDirMode
- }
- if opt.FileMode == 0 {
- opt.FileMode = DefaultFileMode
+
+ opt.dirMode = DefaultDirMode
+ opt.fileMode = DefaultFileMode
+
+ if opt.GroupAccessible {
+ opt.dirMode = GroupAccessibleDirMode
+ opt.fileMode = GroupAccessibleFileMode
}
+
h := Handler{
path: path,
opt: opt,
@@ -251,7 +266,7 @@ func (h *Handler) wrapFileWriter(r *http.Request, w io.Writer) (io.Writer, int,
}
// checkConfig checks whether a configuration exists.
-func (h *Handler) checkConfig(w http.ResponseWriter, r *http.Request) {
+func (h *Handler) checkConfig(w http.ResponseWriter, _ *http.Request) {
if h.opt.Debug {
log.Println("checkConfig()")
}
@@ -267,13 +282,13 @@ func (h *Handler) checkConfig(w http.ResponseWriter, r *http.Request) {
}
// getConfig allows for a config to be retrieved.
-func (h *Handler) getConfig(w http.ResponseWriter, r *http.Request) {
+func (h *Handler) getConfig(w http.ResponseWriter, _ *http.Request) {
if h.opt.Debug {
log.Println("getConfig()")
}
cfg := h.getSubPath("config")
- bytes, err := ioutil.ReadFile(cfg)
+ bytes, err := os.ReadFile(cfg)
if err != nil {
h.fileAccessError(w, err)
return
@@ -289,7 +304,7 @@ func (h *Handler) saveConfig(w http.ResponseWriter, r *http.Request) {
}
cfg := h.getSubPath("config")
- f, err := os.OpenFile(cfg, os.O_CREATE|os.O_WRONLY|os.O_EXCL, h.opt.FileMode)
+ f, err := os.OpenFile(cfg, os.O_CREATE|os.O_WRONLY|os.O_EXCL, h.opt.fileMode)
if err != nil && os.IsExist(err) {
if h.opt.Debug {
log.Print(err)
@@ -314,7 +329,7 @@ func (h *Handler) saveConfig(w http.ResponseWriter, r *http.Request) {
}
// deleteConfig removes a config.
-func (h *Handler) deleteConfig(w http.ResponseWriter, r *http.Request) {
+func (h *Handler) deleteConfig(w http.ResponseWriter, _ *http.Request) {
if h.opt.Debug {
log.Println("deleteConfig()")
}
@@ -369,7 +384,7 @@ func (h *Handler) listBlobsV1(w http.ResponseWriter, r *http.Request) {
}
path := h.getSubPath(objectType)
- items, err := ioutil.ReadDir(path)
+ items, err := os.ReadDir(path)
if err != nil {
h.fileAccessError(w, err)
return
@@ -383,8 +398,8 @@ func (h *Handler) listBlobsV1(w http.ResponseWriter, r *http.Request) {
continue
}
subpath := filepath.Join(path, i.Name())
- var subitems []os.FileInfo
- subitems, err = ioutil.ReadDir(subpath)
+ var subitems []os.DirEntry
+ subitems, err = os.ReadDir(subpath)
if err != nil {
h.fileAccessError(w, err)
return
@@ -428,7 +443,7 @@ func (h *Handler) listBlobsV2(w http.ResponseWriter, r *http.Request) {
}
path := h.getSubPath(objectType)
- items, err := ioutil.ReadDir(path)
+ items, err := os.ReadDir(path)
if err != nil {
h.fileAccessError(w, err)
return
@@ -442,17 +457,27 @@ func (h *Handler) listBlobsV2(w http.ResponseWriter, r *http.Request) {
continue
}
subpath := filepath.Join(path, i.Name())
- var subitems []os.FileInfo
- subitems, err = ioutil.ReadDir(subpath)
+ var subitems []os.DirEntry
+ subitems, err = os.ReadDir(subpath)
if err != nil {
h.fileAccessError(w, err)
return
}
for _, f := range subitems {
- blobs = append(blobs, Blob{Name: f.Name(), Size: f.Size()})
+ fi, err := f.Info()
+ if err != nil {
+ h.fileAccessError(w, err)
+ return
+ }
+ blobs = append(blobs, Blob{Name: f.Name(), Size: fi.Size()})
}
} else {
- blobs = append(blobs, Blob{Name: i.Name(), Size: i.Size()})
+ fi, err := i.Info()
+ if err != nil {
+ h.fileAccessError(w, err)
+ return
+ }
+ blobs = append(blobs, Blob{Name: i.Name(), Size: fi.Size()})
}
}
@@ -545,15 +570,15 @@ func (h *Handler) saveBlob(w http.ResponseWriter, r *http.Request) {
}
tmpFn := filepath.Join(filepath.Dir(path), objectID+".rest-server-temp")
- tf, err := tempFile(tmpFn, h.opt.FileMode)
+ tf, err := tempFile(tmpFn, h.opt.fileMode)
if os.IsNotExist(err) {
// the error is caused by a missing directory, create it and retry
- mkdirErr := os.MkdirAll(filepath.Dir(path), h.opt.DirMode)
+ mkdirErr := os.MkdirAll(filepath.Dir(path), h.opt.dirMode)
if mkdirErr != nil {
log.Print(mkdirErr)
} else {
// try again
- tf, err = tempFile(tmpFn, h.opt.FileMode)
+ tf, err = tempFile(tmpFn, h.opt.fileMode)
}
}
if err != nil {
@@ -652,7 +677,7 @@ func (h *Handler) saveBlob(w http.ResponseWriter, r *http.Request) {
h.sendMetric(objectType, BlobWrite, uint64(written))
}
-// tempFile implements a custom version of ioutil.TempFile which allows modifying the file permissions
+// tempFile implements a custom version of os.CreateTemp which allows modifying the file permissions
func tempFile(fn string, perm os.FileMode) (f *os.File, err error) {
for i := 0; i < 10; i++ {
name := fn + strconv.FormatInt(rand.Int63(), 10)
@@ -750,13 +775,13 @@ func (h *Handler) createRepo(w http.ResponseWriter, r *http.Request) {
log.Printf("Creating repository directories in %s\n", h.path)
- if err := os.MkdirAll(h.path, h.opt.DirMode); err != nil {
+ if err := os.MkdirAll(h.path, h.opt.dirMode); err != nil {
h.internalServerError(w, err)
return
}
for _, d := range ObjectTypes {
- if err := os.Mkdir(filepath.Join(h.path, d), h.opt.DirMode); err != nil && !os.IsExist(err) {
+ if err := os.Mkdir(filepath.Join(h.path, d), h.opt.dirMode); err != nil && !os.IsExist(err) {
h.internalServerError(w, err)
return
}
@@ -764,7 +789,7 @@ func (h *Handler) createRepo(w http.ResponseWriter, r *http.Request) {
for i := 0; i < 256; i++ {
dirPath := filepath.Join(h.path, "data", fmt.Sprintf("%02x", i))
- if err := os.Mkdir(dirPath, h.opt.DirMode); err != nil && !os.IsExist(err) {
+ if err := os.Mkdir(dirPath, h.opt.dirMode); err != nil && !os.IsExist(err) {
h.internalServerError(w, err)
return
}