backup/admin.go

197 lines
4.7 KiB
Go
Raw Normal View History

2023-07-31 18:11:29 +02:00
package main
import (
"context"
2023-08-20 16:57:53 +02:00
"embed"
2024-11-17 23:37:42 +01:00
"fmt"
2023-08-20 16:57:53 +02:00
"html/template"
"io/fs"
2023-07-31 18:11:29 +02:00
"net/http"
"os/signal"
"syscall"
"time"
"github.com/gin-gonic/gin"
"github.com/robfig/cron/v3"
"github.com/sethvargo/go-password/password"
log "github.com/sirupsen/logrus"
)
type AdminConfig struct {
2023-08-20 16:57:53 +02:00
Users []*User `json:"users"`
Secrets *SecretsConfig `json:"secrets"`
Addr string `json:"addr"`
2024-11-17 23:37:42 +01:00
URL string `json:"url"`
2023-07-31 18:11:29 +02:00
}
type SecretsConfig struct {
PasswordPepper string `json:"password_pepper"`
ContextKey string `json:"context_key"`
ContextExpiration int `json:"context_expiration"`
ScryptN int `json:"scrypt_n"`
ScryptR int `json:"scrypt_r"`
ScryptP int `json:"scrypt_p"`
}
2023-08-20 16:57:53 +02:00
//go:embed assets
var assets embed.FS
2023-07-31 18:11:29 +02:00
func NewAdmin() *AdminConfig {
2023-08-20 16:57:53 +02:00
log.WithFields(log.Fields{}).Debugf("starting")
defer log.WithFields(log.Fields{}).Debugf("done")
2023-07-31 18:11:29 +02:00
a := &AdminConfig{
2023-08-20 16:57:53 +02:00
Addr: "0.0.0.0:8080",
Secrets: NewSecrets(),
Users: make([]*User, 0),
2024-11-17 23:37:42 +01:00
URL: "https://backup.example.com/",
2023-07-31 18:11:29 +02:00
}
return a
}
2023-08-20 16:57:53 +02:00
func NewSecrets() *SecretsConfig {
log.WithFields(log.Fields{}).Debugf("starting")
defer log.WithFields(log.Fields{}).Debugf("done")
pepper, _ := password.Generate(20, 5, 0, false, false)
ctx, _ := password.Generate(20, 5, 0, false, false)
return &SecretsConfig{
PasswordPepper: pepper,
ContextKey: ctx,
ContextExpiration: 3600,
ScryptN: 32768,
ScryptR: 8,
ScryptP: 1,
}
}
func (a *AdminConfig) NewAdminUser() {
log.WithFields(log.Fields{}).Debugf("starting")
defer log.WithFields(log.Fields{}).Debugf("done")
p, _ := password.Generate(20, 5, 0, false, false)
u, _ := NewUser("admin", p)
a.Users = append(a.Users, u)
log.WithFields(log.Fields{}).Warnf("Admin user password : %s", p)
}
2023-07-31 18:11:29 +02:00
func (a *AdminConfig) Run() {
log.WithFields(log.Fields{}).Debugf("starting")
defer log.WithFields(log.Fields{}).Debugf("done")
// Create context that listens for the interrupt signal from the OS.
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
2023-07-31 18:19:28 +02:00
if !*debug {
gin.SetMode(gin.ReleaseMode)
}
2023-07-31 18:11:29 +02:00
r := gin.Default()
2023-08-20 16:57:53 +02:00
if t, err := template.ParseFS(assets, "assets/templates/*.html"); err != nil {
log.WithFields(log.Fields{"call": "template.ParseFS", "error": err}).Errorf("")
return
} else {
r.SetHTMLTemplate(t)
}
r.GET("/", HttpAnyIndex)
r.POST("/", HttpAnyIndex)
2023-07-31 20:47:24 +02:00
r.GET("/run", func(c *gin.Context) {
cfg.Run()
c.JSON(http.StatusOK, gin.H{
"message": "done",
})
})
2024-11-17 16:25:39 +01:00
r.GET("/save", func(c *gin.Context) {
if err := cfg.Save(); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{
"message": "error",
})
} else {
c.JSON(http.StatusOK, gin.H{
"message": "done",
})
}
})
2024-11-17 19:21:17 +01:00
/*
r.GET("/test", func(c *gin.Context) {
res := make(map[string]string)
for k, v := range cfg.box {
if err := v.Open(); err != nil {
res[k] = fmt.Sprintf("%s", err)
} else {
res[k] = "ok"
}
v.Close()
2024-11-17 18:36:38 +01:00
}
2024-11-17 19:21:17 +01:00
c.JSON(http.StatusOK, gin.H{
"message": res,
})
2024-11-17 18:36:38 +01:00
})
2024-11-17 19:21:17 +01:00
*/
2023-08-20 16:57:53 +02:00
fsys, _ := fs.Sub(assets, "assets/static")
r.StaticFS("/assets", http.FS(fsys))
protected := r.Group("p", HttpAuth())
protected.GET("test", HttpAnyHome)
2024-11-17 15:14:36 +01:00
protected.GET("home", HttpAnyHome)
2023-08-20 16:57:53 +02:00
unprotected := r.Group("u", HttpNoAuth())
2024-11-17 23:37:42 +01:00
unprotected.POST("submit", HttpPostSubmit)
2024-11-17 15:14:36 +01:00
unprotected.GET("recover", HttpGetRecover)
2023-08-20 16:57:53 +02:00
2023-07-31 18:11:29 +02:00
srv := &http.Server{
2023-07-31 18:19:28 +02:00
Addr: a.Addr,
2023-07-31 18:11:29 +02:00
Handler: r,
}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.WithFields(log.Fields{"call": "http.ListenAndServe", "attr": a.Addr, "error": err}).Errorf("")
}
}()
c := cron.New(cron.WithLocation(time.UTC))
2023-08-01 10:09:37 +02:00
if _, err := c.AddFunc("0 * * * *", func() { cfg.Run() }); err != nil {
2023-08-01 01:22:59 +02:00
log.WithFields(log.Fields{"call": "cron.AddFunc", "error": err}).Errorf("")
}
2023-08-01 00:15:54 +02:00
c.Start()
2023-08-01 09:35:45 +02:00
log.WithFields(log.Fields{"call": "cron.Start"}).Debugf("cron started")
2023-07-31 18:11:29 +02:00
// Listen for the interrupt signal.
<-ctx.Done()
// Restore default behavior on the interrupt signal and notify user of shutdown.
stop()
log.WithFields(log.Fields{"call": "stop"}).Warnf("shutting down")
// The context is used to inform the server it has 5 seconds to finish
// the request it is currently handling
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.WithFields(log.Fields{"call": "http.Shutdown", "error": err}).Errorf("shutting down")
}
}
2024-11-17 23:37:42 +01:00
func FindUserID(user string) (uint64, error) {
log.WithFields(log.Fields{}).Debugf("starting")
defer log.WithFields(log.Fields{}).Debugf("done")
for _, v := range cfg.Admin.Users {
if v.Username == user {
return v.ID, nil
}
}
return 0, fmt.Errorf("no user")
}