Skip to content

Commit f053e33

Browse files
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>
1 parent 10a06dc commit f053e33

File tree

4 files changed

+71
-37
lines changed

4 files changed

+71
-37
lines changed

changelog/unreleased/issue-189

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Enhancement: Support group accessible repositories
2+
3+
Rest-server now supports making repositories accessible to the filesystem group
4+
by setting the `--group-accessible-repos` option. Note that permissions of
5+
existing files are not modified. Use `chmod -R g+rwX /path/to/repo` to make
6+
the repository group-accessible.
7+
8+
https://github.com/restic/rest-server/issues/189
9+
https://github.com/restic/rest-server/pull/308

cmd/rest-server/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ func newRestServerApp() *restServerApp {
6969
flags.BoolVar(&rv.Server.PrivateRepos, "private-repos", rv.Server.PrivateRepos, "users can only access their private repo")
7070
flags.BoolVar(&rv.Server.Prometheus, "prometheus", rv.Server.Prometheus, "enable Prometheus metrics")
7171
flags.BoolVar(&rv.Server.PrometheusNoAuth, "prometheus-no-auth", rv.Server.PrometheusNoAuth, "disable auth for Prometheus /metrics endpoint")
72+
flags.BoolVar(&rv.Server.GroupAccessibleRepos, "group-accessible-repos", rv.Server.GroupAccessibleRepos, "let filesystem group be able to access repo files")
7273

7374
return rv
7475
}
@@ -149,6 +150,12 @@ func (app *restServerApp) runRoot(_ *cobra.Command, _ []string) error {
149150
log.Println("Private repositories disabled")
150151
}
151152

153+
if app.Server.GroupAccessibleRepos {
154+
log.Println("Group accessible repos enabled")
155+
} else {
156+
log.Println("Group accessible repos disabled")
157+
}
158+
152159
enabledTLS, privateKey, publicKey, err := app.tlsSettings()
153160
if err != nil {
154161
return err

handlers.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,24 @@ import (
1515

1616
// Server encapsulates the rest-server's settings and repo management logic
1717
type Server struct {
18-
Path string
19-
HtpasswdPath string
20-
Listen string
21-
Log string
22-
CPUProfile string
23-
TLSKey string
24-
TLSCert string
25-
TLS bool
26-
NoAuth bool
27-
AppendOnly bool
28-
PrivateRepos bool
29-
Prometheus bool
30-
PrometheusNoAuth bool
31-
Debug bool
32-
MaxRepoSize int64
33-
PanicOnError bool
34-
NoVerifyUpload bool
18+
Path string
19+
HtpasswdPath string
20+
Listen string
21+
Log string
22+
CPUProfile string
23+
TLSKey string
24+
TLSCert string
25+
TLS bool
26+
NoAuth bool
27+
AppendOnly bool
28+
PrivateRepos bool
29+
Prometheus bool
30+
PrometheusNoAuth bool
31+
Debug bool
32+
MaxRepoSize int64
33+
PanicOnError bool
34+
NoVerifyUpload bool
35+
GroupAccessibleRepos bool
3536

3637
htpasswdFile *HtpasswdFile
3738
quotaManager *quota.Manager
@@ -88,12 +89,13 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
8889

8990
// Pass the request to the repo.Handler
9091
opt := repo.Options{
91-
AppendOnly: s.AppendOnly,
92-
Debug: s.Debug,
93-
QuotaManager: s.quotaManager, // may be nil
94-
PanicOnError: s.PanicOnError,
95-
NoVerifyUpload: s.NoVerifyUpload,
96-
FsyncWarning: &s.fsyncWarning,
92+
AppendOnly: s.AppendOnly,
93+
Debug: s.Debug,
94+
QuotaManager: s.quotaManager, // may be nil
95+
PanicOnError: s.PanicOnError,
96+
NoVerifyUpload: s.NoVerifyUpload,
97+
FsyncWarning: &s.fsyncWarning,
98+
GroupAccessible: s.GroupAccessibleRepos,
9799
}
98100
if s.Prometheus {
99101
opt.BlobMetricFunc = makeBlobMetricFunc(username, folderPath)

repo/repo.go

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@ import (
2828
type Options struct {
2929
AppendOnly bool // if set, delete actions are not allowed
3030
Debug bool
31-
DirMode os.FileMode
32-
FileMode os.FileMode
3331
NoVerifyUpload bool
3432

3533
// If set, we will panic when an internal server error happens. This
@@ -39,6 +37,13 @@ type Options struct {
3937
BlobMetricFunc BlobMetricFunc
4038
QuotaManager *quota.Manager
4139
FsyncWarning *sync.Once
40+
41+
// If set makes files group accessible
42+
GroupAccessible bool
43+
44+
// Defaults dir and file mode
45+
dirMode os.FileMode
46+
fileMode os.FileMode
4247
}
4348

4449
// DefaultDirMode is the file mode used for directory creation if not
@@ -49,19 +54,30 @@ const DefaultDirMode os.FileMode = 0700
4954
// overridden in the Options
5055
const DefaultFileMode os.FileMode = 0600
5156

57+
// GroupAccessibleDirMode is the file mode used for directory creation when
58+
// group access is enabled
59+
const GroupAccessibleDirMode os.FileMode = 0770
60+
61+
// GroupAccessibleFileMode is the file mode used for file creation when
62+
// group access is enabled
63+
const GroupAccessibleFileMode os.FileMode = 0660
64+
5265
// New creates a new Handler for a single Restic backup repo.
5366
// path is the full filesystem path to this repo directory.
5467
// opt is a set of options.
5568
func New(path string, opt Options) (*Handler, error) {
5669
if path == "" {
5770
return nil, fmt.Errorf("path is required")
5871
}
59-
if opt.DirMode == 0 {
60-
opt.DirMode = DefaultDirMode
61-
}
62-
if opt.FileMode == 0 {
63-
opt.FileMode = DefaultFileMode
72+
73+
opt.dirMode = DefaultDirMode
74+
opt.fileMode = DefaultFileMode
75+
76+
if opt.GroupAccessible {
77+
opt.dirMode = GroupAccessibleDirMode
78+
opt.fileMode = GroupAccessibleFileMode
6479
}
80+
6581
h := Handler{
6682
path: path,
6783
opt: opt,
@@ -288,7 +304,7 @@ func (h *Handler) saveConfig(w http.ResponseWriter, r *http.Request) {
288304
}
289305
cfg := h.getSubPath("config")
290306

291-
f, err := os.OpenFile(cfg, os.O_CREATE|os.O_WRONLY|os.O_EXCL, h.opt.FileMode)
307+
f, err := os.OpenFile(cfg, os.O_CREATE|os.O_WRONLY|os.O_EXCL, h.opt.fileMode)
292308
if err != nil && os.IsExist(err) {
293309
if h.opt.Debug {
294310
log.Print(err)
@@ -554,15 +570,15 @@ func (h *Handler) saveBlob(w http.ResponseWriter, r *http.Request) {
554570
}
555571

556572
tmpFn := filepath.Join(filepath.Dir(path), objectID+".rest-server-temp")
557-
tf, err := tempFile(tmpFn, h.opt.FileMode)
573+
tf, err := tempFile(tmpFn, h.opt.fileMode)
558574
if os.IsNotExist(err) {
559575
// the error is caused by a missing directory, create it and retry
560-
mkdirErr := os.MkdirAll(filepath.Dir(path), h.opt.DirMode)
576+
mkdirErr := os.MkdirAll(filepath.Dir(path), h.opt.dirMode)
561577
if mkdirErr != nil {
562578
log.Print(mkdirErr)
563579
} else {
564580
// try again
565-
tf, err = tempFile(tmpFn, h.opt.FileMode)
581+
tf, err = tempFile(tmpFn, h.opt.fileMode)
566582
}
567583
}
568584
if err != nil {
@@ -759,21 +775,21 @@ func (h *Handler) createRepo(w http.ResponseWriter, r *http.Request) {
759775

760776
log.Printf("Creating repository directories in %s\n", h.path)
761777

762-
if err := os.MkdirAll(h.path, h.opt.DirMode); err != nil {
778+
if err := os.MkdirAll(h.path, h.opt.dirMode); err != nil {
763779
h.internalServerError(w, err)
764780
return
765781
}
766782

767783
for _, d := range ObjectTypes {
768-
if err := os.Mkdir(filepath.Join(h.path, d), h.opt.DirMode); err != nil && !os.IsExist(err) {
784+
if err := os.Mkdir(filepath.Join(h.path, d), h.opt.dirMode); err != nil && !os.IsExist(err) {
769785
h.internalServerError(w, err)
770786
return
771787
}
772788
}
773789

774790
for i := 0; i < 256; i++ {
775791
dirPath := filepath.Join(h.path, "data", fmt.Sprintf("%02x", i))
776-
if err := os.Mkdir(dirPath, h.opt.DirMode); err != nil && !os.IsExist(err) {
792+
if err := os.Mkdir(dirPath, h.opt.dirMode); err != nil && !os.IsExist(err) {
777793
h.internalServerError(w, err)
778794
return
779795
}

0 commit comments

Comments
 (0)