v2 #2
							
								
								
									
										95
									
								
								admin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								admin.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"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 {
 | 
				
			||||||
 | 
						Users   []User        `json:"users"`
 | 
				
			||||||
 | 
						Secrets SecretsConfig `json:"secrets"`
 | 
				
			||||||
 | 
						Addr    string        `json:"addr"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewAdmin() *AdminConfig {
 | 
				
			||||||
 | 
						pepper, _ := password.Generate(20, 5, 0, false, false)
 | 
				
			||||||
 | 
						ctx, _ := password.Generate(20, 5, 0, false, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						a := &AdminConfig{
 | 
				
			||||||
 | 
							Addr: "0.0.0.0:8080",
 | 
				
			||||||
 | 
							Secrets: SecretsConfig{
 | 
				
			||||||
 | 
								PasswordPepper:    pepper,
 | 
				
			||||||
 | 
								ContextKey:        ctx,
 | 
				
			||||||
 | 
								ContextExpiration: 3600,
 | 
				
			||||||
 | 
								ScryptN:           32768,
 | 
				
			||||||
 | 
								ScryptR:           8,
 | 
				
			||||||
 | 
								ScryptP:           1,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							Users: make([]User, 0),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return a
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						r := gin.Default()
 | 
				
			||||||
 | 
						r.GET("/ping", func(c *gin.Context) {
 | 
				
			||||||
 | 
							c.JSON(http.StatusOK, gin.H{
 | 
				
			||||||
 | 
								"message": "pong",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						srv := &http.Server{
 | 
				
			||||||
 | 
							Addr:    ":8080",
 | 
				
			||||||
 | 
							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))
 | 
				
			||||||
 | 
						c.AddFunc("00 * * *", func() { cfg.Run() })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 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")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								backup.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								backup.go
									
									
									
									
									
								
							@ -51,22 +51,12 @@ func main() {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if *isDaemon {
 | 
						if *isDaemon {
 | 
				
			||||||
		cfg.Start(nil)
 | 
							if cfg.Admin == nil {
 | 
				
			||||||
		server := NewServer(cfg.Admin.Addr, cfg.Admin.Username, cfg.Admin.Password)
 | 
								cfg.Admin = NewAdmin()
 | 
				
			||||||
		server.Run()
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		e := NewEmail(time.Now())
 | 
					 | 
				
			||||||
		cfg.Start(e)
 | 
					 | 
				
			||||||
		defer cfg.Stop(e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		cfg.Run(e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		cfg.Cleanup(e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if err := e.Send(); err != nil {
 | 
					 | 
				
			||||||
			log.Printf("Cannot send email (%s)", err)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							cfg.Admin.Run()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cfg.Run()
 | 
				
			||||||
		os.Exit(0)
 | 
							os.Exit(0)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										47
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								config.go
									
									
									
									
									
								
							@ -19,19 +19,13 @@ type Config struct {
 | 
				
			|||||||
	Email            EmailConfig          `json:"email"`
 | 
						Email            EmailConfig          `json:"email"`
 | 
				
			||||||
	Apps             []AppConfig          `json:"apps"`
 | 
						Apps             []AppConfig          `json:"apps"`
 | 
				
			||||||
	Timezone         string               `json:"timezone"`
 | 
						Timezone         string               `json:"timezone"`
 | 
				
			||||||
 | 
						Admin            *AdminConfig         `json:"admin"`
 | 
				
			||||||
	Debug            bool                 `json:"debug"`
 | 
						Debug            bool                 `json:"debug"`
 | 
				
			||||||
	Admin            AdminConfig          `json:"admin"`
 | 
					 | 
				
			||||||
	box              map[string]*Box      `json:"-"`
 | 
						box              map[string]*Box      `json:"-"`
 | 
				
			||||||
	apps             map[string]*App      `json:"-"`
 | 
						apps             map[string]*App      `json:"-"`
 | 
				
			||||||
	timezone         *time.Location       `json:"-"`
 | 
						timezone         *time.Location       `json:"-"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type AdminConfig struct {
 | 
					 | 
				
			||||||
	Addr     string `json:"addr"`
 | 
					 | 
				
			||||||
	Username string `json:"username"`
 | 
					 | 
				
			||||||
	Password string `json:"password"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type BoxConfig struct {
 | 
					type BoxConfig struct {
 | 
				
			||||||
	Addr string `json:"addr"`
 | 
						Addr string `json:"addr"`
 | 
				
			||||||
	User string `json:"user"`
 | 
						User string `json:"user"`
 | 
				
			||||||
@ -159,34 +153,31 @@ func (c *Config) LoadFile(path string) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Config) Start(e *Email) {
 | 
					// Run config
 | 
				
			||||||
 | 
					func (c *Config) Run() {
 | 
				
			||||||
	log.WithFields(log.Fields{}).Debugf("starting")
 | 
						log.WithFields(log.Fields{}).Debugf("starting")
 | 
				
			||||||
	defer log.WithFields(log.Fields{}).Debugf("done")
 | 
						defer log.WithFields(log.Fields{}).Debugf("done")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						e := NewEmail(time.Now())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var wg sync.WaitGroup
 | 
						var wg sync.WaitGroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Setup boxes
 | 
				
			||||||
	for _, b := range c.box {
 | 
						for _, b := range c.box {
 | 
				
			||||||
		wg.Add(1)
 | 
							wg.Add(1)
 | 
				
			||||||
		go func(box *Box) {
 | 
							go func(box *Box) {
 | 
				
			||||||
			defer wg.Done()
 | 
								defer wg.Done()
 | 
				
			||||||
			if err := box.Open(); err != nil {
 | 
								if err := box.Open(); err != nil {
 | 
				
			||||||
				log.WithFields(log.Fields{"name": box.name, "call": "Open", "error": err}).Errorf("")
 | 
									log.WithFields(log.Fields{"name": box.name, "call": "Open", "error": err}).Errorf("")
 | 
				
			||||||
				if e != nil {
 | 
					 | 
				
			||||||
				e.AddItem(fmt.Sprintf(" - Box : %s is down", box.name))
 | 
									e.AddItem(fmt.Sprintf(" - Box : %s is down", box.name))
 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}(b)
 | 
							}(b)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wg.Wait()
 | 
						wg.Wait()
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Run config
 | 
						// Run each app
 | 
				
			||||||
func (c *Config) Run(e *Email) {
 | 
					 | 
				
			||||||
	log.WithFields(log.Fields{}).Debugf("starting")
 | 
					 | 
				
			||||||
	defer log.WithFields(log.Fields{}).Debugf("done")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var wg sync.WaitGroup
 | 
					 | 
				
			||||||
	for _, a := range cfg.apps {
 | 
						for _, a := range cfg.apps {
 | 
				
			||||||
		wg.Add(1)
 | 
							wg.Add(1)
 | 
				
			||||||
		go func(app *App) {
 | 
							go func(app *App) {
 | 
				
			||||||
@ -199,13 +190,7 @@ func (c *Config) Run(e *Email) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	wg.Wait()
 | 
						wg.Wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						// Cleanup
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Config) Cleanup(e *Email) {
 | 
					 | 
				
			||||||
	log.WithFields(log.Fields{}).Debugf("starting")
 | 
					 | 
				
			||||||
	defer log.WithFields(log.Fields{}).Debugf("done")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, a := range cfg.apps {
 | 
						for _, a := range cfg.apps {
 | 
				
			||||||
		for _, src := range a.sources {
 | 
							for _, src := range a.sources {
 | 
				
			||||||
			if b, ok := c.box[src.Box()]; ok {
 | 
								if b, ok := c.box[src.Box()]; ok {
 | 
				
			||||||
@ -233,23 +218,15 @@ func (c *Config) Cleanup(e *Email) {
 | 
				
			|||||||
					log.WithFields(log.Fields{"box": b.name, "fs": fs.path}).Warnf("not backed up")
 | 
										log.WithFields(log.Fields{"box": b.name, "fs": fs.path}).Warnf("not backed up")
 | 
				
			||||||
					e.AddItem(fmt.Sprintf(" - Src : Folder not backed up (%s)", b.name+":"+fs.path))
 | 
										e.AddItem(fmt.Sprintf(" - Src : Folder not backed up (%s)", b.name+":"+fs.path))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if len(fs.destApps) == 0 && len(fs.srcApps) == 0 && fs.managed {
 | 
									if len(fs.destApps) == 0 && !fs.backedUp && fs.managed {
 | 
				
			||||||
					log.WithFields(log.Fields{"box": b.name, "fs": fs.path}).Warnf("managed")
 | 
										log.WithFields(log.Fields{"box": b.name, "fs": fs.path}).Warnf("managed")
 | 
				
			||||||
					e.AddItem(fmt.Sprintf(" - Dest : Folder managed (%s)", b.name+":"+fs.path))
 | 
										e.AddItem(fmt.Sprintf(" - Dest : Folder managed (%s)", b.name+":"+fs.path))
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if fs.managed {
 | 
					 | 
				
			||||||
					log.WithFields(log.Fields{"box": b.name, "fs": fs.path, "src": len(fs.srcApps), "dest": len(fs.destApps)}).Warnf("managed")
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
						// Stop
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (c *Config) Stop(e *Email) {
 | 
					 | 
				
			||||||
	log.WithFields(log.Fields{}).Debugf("starting")
 | 
					 | 
				
			||||||
	defer log.WithFields(log.Fields{}).Debugf("done")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for _, b := range c.box {
 | 
						for _, b := range c.box {
 | 
				
			||||||
		if err := b.Close(); err != nil {
 | 
							if err := b.Close(); err != nil {
 | 
				
			||||||
			log.WithFields(log.Fields{"name": b.name, "call": "Close", "error": err}).Errorf("")
 | 
								log.WithFields(log.Fields{"name": b.name, "call": "Close", "error": err}).Errorf("")
 | 
				
			||||||
@ -261,4 +238,6 @@ func (c *Config) Stop(e *Email) {
 | 
				
			|||||||
			log.WithFields(log.Fields{"call": "email.Send", "error": err}).Errorf("")
 | 
								log.WithFields(log.Fields{"call": "email.Send", "error": err}).Errorf("")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@ -4,6 +4,8 @@ go 1.16
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
	github.com/gin-gonic/gin v1.9.1 // indirect
 | 
						github.com/gin-gonic/gin v1.9.1 // indirect
 | 
				
			||||||
 | 
						github.com/robfig/cron/v3 v3.0.1 // indirect
 | 
				
			||||||
 | 
						github.com/sethvargo/go-password v0.2.0 // indirect
 | 
				
			||||||
	github.com/silenceper/pool v1.0.0 // indirect
 | 
						github.com/silenceper/pool v1.0.0 // indirect
 | 
				
			||||||
	github.com/sirupsen/logrus v1.9.3 // indirect
 | 
						github.com/sirupsen/logrus v1.9.3 // indirect
 | 
				
			||||||
	github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
 | 
						github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							@ -44,6 +44,10 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
 | 
				
			|||||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
 | 
					github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
 | 
				
			||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
 | 
					github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
 | 
				
			||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
					github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
				
			||||||
 | 
					github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 | 
				
			||||||
 | 
					github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 | 
				
			||||||
 | 
					github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI=
 | 
				
			||||||
 | 
					github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE=
 | 
				
			||||||
github.com/silenceper/pool v1.0.0 h1:JTCaA+U6hJAA0P8nCx+JfsRCHMwLTfatsm5QXelffmU=
 | 
					github.com/silenceper/pool v1.0.0 h1:JTCaA+U6hJAA0P8nCx+JfsRCHMwLTfatsm5QXelffmU=
 | 
				
			||||||
github.com/silenceper/pool v1.0.0/go.mod h1:3DN13bqAbq86Lmzf6iUXWEPIWFPOSYVfaoceFvilKKI=
 | 
					github.com/silenceper/pool v1.0.0/go.mod h1:3DN13bqAbq86Lmzf6iUXWEPIWFPOSYVfaoceFvilKKI=
 | 
				
			||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 | 
					github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										44
									
								
								server.go
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								server.go
									
									
									
									
									
								
							@ -1,44 +0,0 @@
 | 
				
			|||||||
package main
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"net/http"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/gin-gonic/gin"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Server struct {
 | 
					 | 
				
			||||||
	Addr     string
 | 
					 | 
				
			||||||
	Username string
 | 
					 | 
				
			||||||
	Password string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewServer(addr, username, password string) *Server {
 | 
					 | 
				
			||||||
	s := &Server{
 | 
					 | 
				
			||||||
		Addr:     serverAddr,
 | 
					 | 
				
			||||||
		Username: serverUsername,
 | 
					 | 
				
			||||||
		Password: serverPassword,
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if addr != "" {
 | 
					 | 
				
			||||||
		s.Addr = addr
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if username != "" {
 | 
					 | 
				
			||||||
		s.Username = username
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if password != "" {
 | 
					 | 
				
			||||||
		s.Password = password
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return s
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (s *Server) Run() {
 | 
					 | 
				
			||||||
	r := gin.Default()
 | 
					 | 
				
			||||||
	r.GET("/ping", func(c *gin.Context) {
 | 
					 | 
				
			||||||
		c.JSON(http.StatusOK, gin.H{
 | 
					 | 
				
			||||||
			"message": "pong",
 | 
					 | 
				
			||||||
		})
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	r.Run(s.Addr) // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										76
									
								
								user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								user.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"crypto/hmac"
 | 
				
			||||||
 | 
						"crypto/rand"
 | 
				
			||||||
 | 
						"crypto/sha256"
 | 
				
			||||||
 | 
						"encoding/hex"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log "github.com/sirupsen/logrus"
 | 
				
			||||||
 | 
						"golang.org/x/crypto/scrypt"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type User struct {
 | 
				
			||||||
 | 
						Username string `json:"username"`
 | 
				
			||||||
 | 
						Salt     string `json:"salt"`
 | 
				
			||||||
 | 
						Passwd   string `json:"passwd"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewUser(name, passwd string) (*User, error) {
 | 
				
			||||||
 | 
						log.WithFields(log.Fields{"name": name}).Debugf("starting")
 | 
				
			||||||
 | 
						defer log.WithFields(log.Fields{"name": name}).Debugf("done")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, v := range cfg.Admin.Users {
 | 
				
			||||||
 | 
							if v.Username == name {
 | 
				
			||||||
 | 
								err := errors.New("user already exists")
 | 
				
			||||||
 | 
								log.WithFields(log.Fields{"name": name, "error": err}).Errorf("")
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u := &User{
 | 
				
			||||||
 | 
							Username: name,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						salt := make([]byte, 32)
 | 
				
			||||||
 | 
						if _, err := rand.Read(salt); err != nil {
 | 
				
			||||||
 | 
							log.WithFields(log.Fields{"name": name, "call": "rand.Read", "error": err}).Errorf("")
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						u.Salt = hex.EncodeToString(salt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if pass, err := u.HashPassword(passwd); err != nil {
 | 
				
			||||||
 | 
							log.WithFields(log.Fields{"name": name, "call": "HashPassword", "error": err}).Errorf("")
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							u.Passwd = hex.EncodeToString(pass)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return u, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (u *User) HashPassword(passwd string) ([]byte, error) {
 | 
				
			||||||
 | 
						log.WithFields(log.Fields{}).Debugf("starting")
 | 
				
			||||||
 | 
						defer log.WithFields(log.Fields{}).Debugf("done")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//peppering the pass
 | 
				
			||||||
 | 
						hash := hmac.New(sha256.New, []byte(cfg.Admin.Secrets.PasswordPepper))
 | 
				
			||||||
 | 
						hash.Write([]byte(passwd))
 | 
				
			||||||
 | 
						hashPass := hash.Sum(nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//salting the hash
 | 
				
			||||||
 | 
						salt := make([]byte, 32)
 | 
				
			||||||
 | 
						if _, err := hex.Decode(salt, []byte(u.Salt)); err != nil {
 | 
				
			||||||
 | 
							log.WithFields(log.Fields{"call": "hex.Decode", "error": err}).Errorf("")
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if h, err := scrypt.Key(hashPass, salt, cfg.Admin.Secrets.ScryptN, cfg.Admin.Secrets.ScryptR, cfg.Admin.Secrets.ScryptP, 32); err != nil {
 | 
				
			||||||
 | 
							log.WithFields(log.Fields{"call": "scrypt.Key", "error": err}).Errorf("")
 | 
				
			||||||
 | 
							return h, err
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return h, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user