package web import ( "bytes" "embed" "errors" "fmt" "html/template" "net/http" "strings" "time" "git.ulra.eu/adro/miniwol/config" "git.ulra.eu/adro/miniwol/lib" "github.com/google/uuid" "github.com/labstack/echo/v4" "golang.org/x/crypto/bcrypt" ) //go:embed template/* var templateFS embed.FS var templates *template.Template func init() { var err error templates, err = template.ParseFS(templateFS, "template/*.html.tmpl") if err != nil { panic(err) } } func Run() error { e := echo.New() e.GET("/", index) e.POST("/auth", auth) e.POST("/wake", withAuth(wake)) return e.Start(config.Config.Server) } func Page(c echo.Context, code int, title string, page string, data interface{}) error { var contentBuffer bytes.Buffer err := templates.ExecuteTemplate(&contentBuffer, page, data) if err != nil { return err } var pageBuffer bytes.Buffer err = templates.ExecuteTemplate(&pageBuffer, "page.html.tmpl", struct { Title string Content template.HTML }{ Title: title, Content: template.HTML(contentBuffer.String()), }) if err != nil { return err } return c.HTML(code, pageBuffer.String()) } // Handlers func index(c echo.Context) error { session, err := c.Cookie("session") if err != nil || checkAuth(session.Value) != nil { return Page(c, 200, "Login", "login.html.tmpl", nil) } else { return Page(c, 200, "Device", "device.html.tmpl", config.Config) } } func auth(c echo.Context) error { password := c.FormValue("password") if bcrypt.CompareHashAndPassword([]byte(config.Config.PassHash), []byte(password)) != nil { return c.String(401, "Wrong Password") } token := uuid.New().String() sessions[token] = time.Now().Add(time.Second * time.Duration(config.Config.SessionTTL*60)) c.SetCookie(&http.Cookie{ Name: "session", Value: token, Path: "/", Secure: true, HttpOnly: true, SameSite: http.SameSiteStrictMode, Expires: sessions[token], }) return c.Redirect(http.StatusSeeOther, "/") } func wake(c echo.Context) error { for i, device := range config.Config.Device { if c.FormValue("alias") == device.Alias && c.FormValue("index") == fmt.Sprint(i) { if !strings.Contains(device.IP, ":") { device.IP += ":9" } err := lib.SendPacket(":0", device.IP, device.MAC) if err != nil { return err } return c.Redirect(http.StatusSeeOther, "/") } } return errors.New("device not found") }