aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Massimo Lusetti <197125+mlusetti@users.noreply.github.com> 2025-02-17 22:17:54 +0100
committerGravatar GitHub <noreply@github.com> 2025-02-17 22:17:54 +0100
commitf053e334865c5ec402c75d55bdf09b745342080d (patch)
tree98f43563d7d7b441c827f301677f325388ac9062
parent10a06dcbf1b33242ce78d02fe8fcbfa32ee06026 (diff)
downloadrest-server-f053e334865c5ec402c75d55bdf09b745342080d.tar.gz
rest-server-f053e334865c5ec402c75d55bdf09b745342080d.tar.zst
rest-server-f053e334865c5ec402c75d55bdf09b745342080d.zip
Add group-accessible-repos option (#308)
* Add group-accessible-repos option The group-accessible-repos option will let filesystem group id be able to access files and dir within the restic repo Default stick with old behaviour to be owner restricted While here make dirMode and fileMode within Options struct private --------- Co-authored-by: Michael Eischer <michael.eischer@fau.de>
-rw-r--r--changelog/unreleased/issue-1899
-rw-r--r--cmd/rest-server/main.go7
-rw-r--r--handlers.go48
-rw-r--r--repo/repo.go44
4 files changed, 71 insertions, 37 deletions
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/cmd/rest-server/main.go b/cmd/rest-server/main.go
index aa921c9..cabc565 100644
--- a/cmd/rest-server/main.go
+++ b/cmd/rest-server/main.go
@@ -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")
return rv
}
@@ -149,6 +150,12 @@ func (app *restServerApp) runRoot(_ *cobra.Command, _ []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/handlers.go b/handlers.go
index 1bccc60..cde0637 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
htpasswdFile *HtpasswdFile
quotaManager *quota.Manager
@@ -88,12 +89,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/repo/repo.go b/repo/repo.go
index cd84929..0e38bb6 100644
--- a/repo/repo.go
+++ b/repo/repo.go
@@ -28,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
@@ -39,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
@@ -49,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.
@@ -56,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,
@@ -288,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)
@@ -554,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 {
@@ -759,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
}
@@ -773,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
}