mirror of
https://github.com/restic/rest-server.git
synced 2025-10-19 15:43:21 +00:00
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
This commit is contained in:
parent
e35c6e39d9
commit
92216a10ba
3 changed files with 62 additions and 38 deletions
|
@ -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 read repo files")
|
||||
|
||||
return rv
|
||||
}
|
||||
|
@ -147,6 +148,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
|
||||
|
|
51
handlers.go
51
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)
|
||||
|
@ -158,7 +160,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 "/"
|
||||
|
|
42
repo/repo.go
42
repo/repo.go
|
@ -29,8 +29,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 +38,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 +55,12 @@ const DefaultDirMode os.FileMode = 0700
|
|||
// overridden in the Options
|
||||
const DefaultFileMode os.FileMode = 0600
|
||||
|
||||
// File mode used for directory creation when group access is enabled
|
||||
const GroupAccessibleDirMode os.FileMode = 0770
|
||||
|
||||
// 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 +68,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,
|
||||
|
@ -289,7 +303,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)
|
||||
|
@ -545,15 +559,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 {
|
||||
|
@ -750,13 +764,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 +778,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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue