mirror of
https://github.com/restic/rest-server.git
synced 2025-12-07 09:36:13 -08:00
Compare commits
3 Commits
master
...
bcbd35bf4c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcbd35bf4c | ||
|
|
f15b03ae9d | ||
|
|
92216a10ba |
@@ -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.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.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.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
|
return rv
|
||||||
}
|
}
|
||||||
@@ -147,6 +148,12 @@ func (app *restServerApp) runRoot(cmd *cobra.Command, args []string) error {
|
|||||||
log.Println("Private repositories disabled")
|
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()
|
enabledTLS, privateKey, publicKey, err := app.tlsSettings()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
51
handlers.go
51
handlers.go
@@ -15,23 +15,24 @@ import (
|
|||||||
|
|
||||||
// Server encapsulates the rest-server's settings and repo management logic
|
// Server encapsulates the rest-server's settings and repo management logic
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Path string
|
Path string
|
||||||
HtpasswdPath string
|
HtpasswdPath string
|
||||||
Listen string
|
Listen string
|
||||||
Log string
|
Log string
|
||||||
CPUProfile string
|
CPUProfile string
|
||||||
TLSKey string
|
TLSKey string
|
||||||
TLSCert string
|
TLSCert string
|
||||||
TLS bool
|
TLS bool
|
||||||
NoAuth bool
|
NoAuth bool
|
||||||
AppendOnly bool
|
AppendOnly bool
|
||||||
PrivateRepos bool
|
PrivateRepos bool
|
||||||
Prometheus bool
|
Prometheus bool
|
||||||
PrometheusNoAuth bool
|
PrometheusNoAuth bool
|
||||||
Debug bool
|
Debug bool
|
||||||
MaxRepoSize int64
|
MaxRepoSize int64
|
||||||
PanicOnError bool
|
PanicOnError bool
|
||||||
NoVerifyUpload bool
|
NoVerifyUpload bool
|
||||||
|
GroupAccessibleRepos bool
|
||||||
|
|
||||||
htpasswdFile *HtpasswdFile
|
htpasswdFile *HtpasswdFile
|
||||||
quotaManager *quota.Manager
|
quotaManager *quota.Manager
|
||||||
@@ -88,12 +89,13 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Pass the request to the repo.Handler
|
// Pass the request to the repo.Handler
|
||||||
opt := repo.Options{
|
opt := repo.Options{
|
||||||
AppendOnly: s.AppendOnly,
|
AppendOnly: s.AppendOnly,
|
||||||
Debug: s.Debug,
|
Debug: s.Debug,
|
||||||
QuotaManager: s.quotaManager, // may be nil
|
QuotaManager: s.quotaManager, // may be nil
|
||||||
PanicOnError: s.PanicOnError,
|
PanicOnError: s.PanicOnError,
|
||||||
NoVerifyUpload: s.NoVerifyUpload,
|
NoVerifyUpload: s.NoVerifyUpload,
|
||||||
FsyncWarning: &s.fsyncWarning,
|
FsyncWarning: &s.fsyncWarning,
|
||||||
|
GroupAccessible: s.GroupAccessibleRepos,
|
||||||
}
|
}
|
||||||
if s.Prometheus {
|
if s.Prometheus {
|
||||||
opt.BlobMetricFunc = makeBlobMetricFunc(username, folderPath)
|
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
|
// splitURLPath splits the URL path into a folderPath of the subrepo, and
|
||||||
// a remainder that can be passed to repo.Handler.
|
// a remainder that can be passed to repo.Handler.
|
||||||
// Example: /foo/bar/locks/0123... will be split into:
|
// 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) {
|
func splitURLPath(urlPath string, maxDepth int) (folderPath []string, remainder string) {
|
||||||
if !strings.HasPrefix(urlPath, "/") {
|
if !strings.HasPrefix(urlPath, "/") {
|
||||||
// Really should start with "/"
|
// Really should start with "/"
|
||||||
|
|||||||
42
repo/repo.go
42
repo/repo.go
@@ -29,8 +29,6 @@ import (
|
|||||||
type Options struct {
|
type Options struct {
|
||||||
AppendOnly bool // if set, delete actions are not allowed
|
AppendOnly bool // if set, delete actions are not allowed
|
||||||
Debug bool
|
Debug bool
|
||||||
DirMode os.FileMode
|
|
||||||
FileMode os.FileMode
|
|
||||||
NoVerifyUpload bool
|
NoVerifyUpload bool
|
||||||
|
|
||||||
// If set, we will panic when an internal server error happens. This
|
// If set, we will panic when an internal server error happens. This
|
||||||
@@ -40,6 +38,13 @@ type Options struct {
|
|||||||
BlobMetricFunc BlobMetricFunc
|
BlobMetricFunc BlobMetricFunc
|
||||||
QuotaManager *quota.Manager
|
QuotaManager *quota.Manager
|
||||||
FsyncWarning *sync.Once
|
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
|
// DefaultDirMode is the file mode used for directory creation if not
|
||||||
@@ -50,6 +55,12 @@ const DefaultDirMode os.FileMode = 0700
|
|||||||
// overridden in the Options
|
// overridden in the Options
|
||||||
const DefaultFileMode os.FileMode = 0600
|
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.
|
// New creates a new Handler for a single Restic backup repo.
|
||||||
// path is the full filesystem path to this repo directory.
|
// path is the full filesystem path to this repo directory.
|
||||||
// opt is a set of options.
|
// opt is a set of options.
|
||||||
@@ -57,12 +68,15 @@ func New(path string, opt Options) (*Handler, error) {
|
|||||||
if path == "" {
|
if path == "" {
|
||||||
return nil, fmt.Errorf("path is required")
|
return nil, fmt.Errorf("path is required")
|
||||||
}
|
}
|
||||||
if opt.DirMode == 0 {
|
|
||||||
opt.DirMode = DefaultDirMode
|
opt.dirMode = DefaultDirMode
|
||||||
}
|
opt.fileMode = DefaultFileMode
|
||||||
if opt.FileMode == 0 {
|
|
||||||
opt.FileMode = DefaultFileMode
|
if opt.GroupAccessible {
|
||||||
|
opt.dirMode = GroupAccessibleDirMode
|
||||||
|
opt.fileMode = GroupAccessibleFileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
h := Handler{
|
h := Handler{
|
||||||
path: path,
|
path: path,
|
||||||
opt: opt,
|
opt: opt,
|
||||||
@@ -289,7 +303,7 @@ func (h *Handler) saveConfig(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
cfg := h.getSubPath("config")
|
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 err != nil && os.IsExist(err) {
|
||||||
if h.opt.Debug {
|
if h.opt.Debug {
|
||||||
log.Print(err)
|
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")
|
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) {
|
if os.IsNotExist(err) {
|
||||||
// the error is caused by a missing directory, create it and retry
|
// 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 {
|
if mkdirErr != nil {
|
||||||
log.Print(mkdirErr)
|
log.Print(mkdirErr)
|
||||||
} else {
|
} else {
|
||||||
// try again
|
// try again
|
||||||
tf, err = tempFile(tmpFn, h.opt.FileMode)
|
tf, err = tempFile(tmpFn, h.opt.fileMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
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)
|
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)
|
h.internalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range ObjectTypes {
|
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)
|
h.internalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -764,7 +778,7 @@ func (h *Handler) createRepo(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
for i := 0; i < 256; i++ {
|
for i := 0; i < 256; i++ {
|
||||||
dirPath := filepath.Join(h.path, "data", fmt.Sprintf("%02x", 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)
|
h.internalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user