From 63cf93d4333854e12f535077a1c8cca1c34c9ce7 Mon Sep 17 00:00:00 2001 From: Massimo Lusetti Date: Thu, 14 Apr 2022 19:31:36 +0200 Subject: [PATCH 1/3] expose command line option to configure umask for directories and files add a changelog as requested by pull checklist make it go1.14 buildable expose command line option to configure umask for directories and files implement "group readable repos" instead of custom DirMode & FileMode --- changelog/0.11.0_2022-02-10/issue-189 | 8 ++++ cmd/rest-server/main.go | 5 +++ handlers.go | 37 +++++++++--------- repo/repo.go | 54 ++++++++++++++++++--------- 4 files changed, 70 insertions(+), 34 deletions(-) create mode 100644 changelog/0.11.0_2022-02-10/issue-189 diff --git a/changelog/0.11.0_2022-02-10/issue-189 b/changelog/0.11.0_2022-02-10/issue-189 new file mode 100644 index 00000000..14e0008c --- /dev/null +++ b/changelog/0.11.0_2022-02-10/issue-189 @@ -0,0 +1,8 @@ +Feature: Expose command line option to configure FileMode and DirMode + +Just expose a CLI option to configure Server FileMode and DirMode to +be able to have files stored in the repo shared with other processes +(maybe just read only) + +https://github.com/restic/rest-server/issues/189 +https://github.com/restic/rest-server/pull/190 diff --git a/cmd/rest-server/main.go b/cmd/rest-server/main.go index 4287b97a..f4c9202d 100644 --- a/cmd/rest-server/main.go +++ b/cmd/rest-server/main.go @@ -53,6 +53,7 @@ func init() { flags.BoolVar(&server.PrivateRepos, "private-repos", server.PrivateRepos, "users can only access their private repo") flags.BoolVar(&server.Prometheus, "prometheus", server.Prometheus, "enable Prometheus metrics") flags.BoolVar(&server.PrometheusNoAuth, "prometheus-no-auth", server.PrometheusNoAuth, "disable auth for Prometheus /metrics endpoint") + flags.BoolVar(&server.GroupAccessibleRepos, "group-accessible-repositories", server.GroupAccessibleRepos, "filesyste repo files group readableCosi` ") } var version = "0.11.0" @@ -125,6 +126,10 @@ func runRoot(cmd *cobra.Command, args []string) error { log.Println("Private repositories disabled") } + if server.GroupAccessibleRepos { + log.Println("Repositories are group accessible") + } + enabledTLS, privateKey, publicKey, err := tlsSettings() if err != nil { return err diff --git a/handlers.go b/handlers.go index 9df6adf8..eddeccc9 100644 --- a/handlers.go +++ b/handlers.go @@ -14,22 +14,23 @@ import ( // Server encapsulates the rest-server's settings and repo management logic type Server struct { - Path 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 + 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 @@ -90,6 +91,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { QuotaManager: s.quotaManager, // may be nil PanicOnError: s.PanicOnError, NoVerifyUpload: s.NoVerifyUpload, + GroupReadable: s.GroupAccessibleRepos, } if s.Prometheus { opt.BlobMetricFunc = makeBlobMetricFunc(username, folderPath) @@ -154,7 +156,8 @@ func join(base string, names ...string) (string, error) { // splitURLPath splits the URL path into a folderPath of the subrepo, and // a remainder that can be passed to repo.Handler. // Example: /foo/bar/locks/0123... will be split into: -// ["foo", "bar"] and "/locks/0123..." +// +// ["foo", "bar"] and "/locks/0123..." func splitURLPath(urlPath string, maxDepth int) (folderPath []string, remainder string) { if !strings.HasPrefix(urlPath, "/") { // Really should start with "/" diff --git a/repo/repo.go b/repo/repo.go index 812bee2a..2ab289cf 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 @@ -38,16 +36,31 @@ type Options struct { BlobMetricFunc BlobMetricFunc QuotaManager *quota.Manager + + // If set, we will panic when an internal server error happens. This + // makes it easier to debug such errors. + GroupReadable bool + + dirMode os.FileMode + fileMode os.FileMode } -// DefaultDirMode is the file mode used for directory creation if not +// DefaultGroupReadable shows if files and dirs written should be group readable // overridden in the Options +const DefaultGroupReadable = false + +// DefaultDirMode is the file mode used for directory creation by default const DefaultDirMode os.FileMode = 0700 -// DefaultFileMode is the file mode used for file creation if not -// overridden in the Options +// DefaultFileMode is the file mode used for file creation by default const DefaultFileMode os.FileMode = 0600 +// GroupReadableDirMode is the file mode used for directory creation if group readable +const GroupReadableDirMode os.FileMode = 0750 + +// GroupReadableFileMode is the file mode used for directory creation if group readable +const GroupReadableFileMode os.FileMode = 0640 + // 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. @@ -55,11 +68,18 @@ 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 + // if opt.dirMode == 0 { + // opt.dirMode = DefaultDirMode + // } + // if opt.fileMode == 0 { + // opt.fileMode = DefaultFileMode + // } + if opt.GroupReadable { + opt.dirMode = GroupReadableDirMode + opt.fileMode = GroupReadableFileMode + } else { + opt.dirMode = DefaultDirMode + opt.fileMode = DefaultFileMode } h := Handler{ path: path, @@ -293,7 +313,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) @@ -562,15 +582,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 { @@ -749,13 +769,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 } @@ -763,7 +783,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 } From 265648e08240ae41a43a334b17c72d9199a64023 Mon Sep 17 00:00:00 2001 From: Massimo Lusetti Date: Thu, 7 Sep 2023 15:54:43 +0200 Subject: [PATCH 2/3] update changelog entry --- changelog/0.11.0_2022-02-10/issue-189 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/changelog/0.11.0_2022-02-10/issue-189 b/changelog/0.11.0_2022-02-10/issue-189 index 14e0008c..2142a4d7 100644 --- a/changelog/0.11.0_2022-02-10/issue-189 +++ b/changelog/0.11.0_2022-02-10/issue-189 @@ -1,8 +1,6 @@ -Feature: Expose command line option to configure FileMode and DirMode +Feature: Implement boolean flag "group-readable-repositores" -Just expose a CLI option to configure Server FileMode and DirMode to -be able to have files stored in the repo shared with other processes -(maybe just read only) +A CLI option to write dirs and files with a group readable permission grant https://github.com/restic/rest-server/issues/189 https://github.com/restic/rest-server/pull/190 From 843b03c7a0104352ebce66c18ea4d6dd796e9e53 Mon Sep 17 00:00:00 2001 From: Massimo Lusetti Date: Thu, 7 Sep 2023 15:57:21 +0200 Subject: [PATCH 3/3] typo --- cmd/rest-server/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/rest-server/main.go b/cmd/rest-server/main.go index f4c9202d..92754e3e 100644 --- a/cmd/rest-server/main.go +++ b/cmd/rest-server/main.go @@ -53,7 +53,7 @@ func init() { flags.BoolVar(&server.PrivateRepos, "private-repos", server.PrivateRepos, "users can only access their private repo") flags.BoolVar(&server.Prometheus, "prometheus", server.Prometheus, "enable Prometheus metrics") flags.BoolVar(&server.PrometheusNoAuth, "prometheus-no-auth", server.PrometheusNoAuth, "disable auth for Prometheus /metrics endpoint") - flags.BoolVar(&server.GroupAccessibleRepos, "group-accessible-repositories", server.GroupAccessibleRepos, "filesyste repo files group readableCosi` ") + flags.BoolVar(&server.GroupAccessibleRepos, "group-accessible-repositories", server.GroupAccessibleRepos, "make filesystem repo files group readable") } var version = "0.11.0"