| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- package main
- import (
- "crypto/rand"
- "encoding/hex"
- "fmt"
- "github.com/gorilla/sessions"
- "github.com/labstack/echo"
- "github.com/labstack/echo-contrib/session"
- "github.com/labstack/echo/middleware"
- "net/http"
- "regexp"
- "strconv"
- "strings"
- "time"
- )
- type userConfig struct {
- Admins []string `json:"admins"`
- Boards []configBoard `json:"boards"`
- }
- func genConfig() *userConfig {
- u := &userConfig{
- make([]string, 0, len(config.Admins)),
- make([]configBoard, 0, len(config.Boards)),
- }
- for k := range config.Admins { u.Admins = append(u.Admins, k) }
- for b := range config.Boards { u.Boards = append(u.Boards, config.Boards[b]) }
- return u
- }
- func serveIndex(c echo.Context) error {
- return c.File("server/templates/head.html")
- }
- func serveLogin(c echo.Context) error {
- return c.File("server/templates/login.html")
- }
- func serveInterface(address string) {
- e := echo.New()
- e.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5}))
- e.Use(session.Middleware(sessions.NewCookieStore([]byte(config.Secret))))
- e.GET("/", func(c echo.Context) error {
- sess, _ := session.Get("session", c)
- if auth, ok := sess.Values["authorised"]; ok && auth.(bool) {
- return c.Redirect(http.StatusTemporaryRedirect, "/admin")
- }
- return c.Redirect(http.StatusTemporaryRedirect, "/login")
- })
- e.GET("/login", serveLogin)
- g := e.Group("/admin")
- g.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
- return func(c echo.Context) error {
- sess, _ := session.Get("session", c)
- auth, ok := sess.Values["authorised"]
- if !ok || !auth.(bool) {
- fmt.Println("Not authorised")
- return c.Redirect(http.StatusTemporaryRedirect, "/login")
- }
- fmt.Println("Authorised")
- return next(c)
- }
- })
- g.GET("", serveIndex)
- g.POST("", serveIndex)
- g.POST("/user", func(c echo.Context) error {
- sess, _ := session.Get("session", c)
- name := strings.ToLower(c.FormValue("username"))
- matched, _ := regexp.MatchString(`\w`, name)
- if !matched {
- return c.String(http.StatusNotAcceptable, "Invalid username. Allowed symbols: a-z 0-9 _")
- }
- pass := c.FormValue("password")
- if len(name) == 0 {
- return c.String(http.StatusNotAcceptable, "No username")
- }
- admin, exist := config.Admins[name]
- if exist {
- if len(pass) > 0 {
- if sess.Values["username"] != name {
- return c.String(http.StatusNotAcceptable, "Can't change other user passwords")
- }
- err := admin.newPassword(pass)
- if err != nil {
- fmt.Printf("Failed hash password %s\n", err)
- return c.String(http.StatusNotAcceptable, "Failed to hash")
- }
- }
- } else {
- if len(pass) == 0 {
- return c.String(http.StatusNotAcceptable, "No password")
- }
- admin := configAdmin{name, nil}
- err := admin.newPassword(pass)
- if err != nil {
- fmt.Printf("Failed hash password %s\n", err)
- return c.String(http.StatusNotAcceptable, "Failed to hash")
- }
- config.Admins[name] = admin
- }
- saveConfig()
- return c.JSON(http.StatusOK, genConfig())
- })
- g.POST("/board", func(c echo.Context) error {
- id64, err := strconv.ParseUint(c.FormValue("id"), 10, 16)
- if err != nil {
- return c.String(http.StatusNotAcceptable, "Invalid ID")
- }
- id := uint16(id64)
- keysize, err := strconv.ParseUint(c.FormValue("keysize"), 10, 16)
- if err != nil || (keysize != 128 && keysize != 192 && keysize != 256) {
- return c.String(http.StatusNotAcceptable, "Invalid key size")
- }
- key, err := hex.DecodeString(c.FormValue("key"))
- if err != nil {
- return c.String(http.StatusNotAcceptable, "Key is not base 16")
- }
- if len(key) != int(keysize/8) && len(key) != 0 {
- return c.String(http.StatusNotAcceptable, "Key does not match key size")
- }
- if board, exist := config.Boards[id]; exist {
- // Update settings
- if len(key) > 0 {
- board.KEY = key
- board.KEY16 = hex.EncodeToString(key)
- }
- } else {
- // New board
- if len(key) == 0 {
- key = make([]byte, keysize/8)
- _, err = rand.Read(key)
- errCheck(err, "Failed generate random key")
- }
- config.Boards[id] = configBoard{
- id,
- key,
- hex.EncodeToString(key),
- time.Unix(0, 0),
- }
- }
- saveConfig()
- return c.JSON(http.StatusOK, genConfig())
- })
- g.DELETE("/user/:name", func(c echo.Context) error {
- sess, _ := session.Get("session", c)
- if sess.Values["username"] == c.Param("name") {
- return c.String(http.StatusNotAcceptable, "Can't delete yourself")
- }
- _, ok := config.Admins[c.Param("name")]
- if !ok {
- return c.String(http.StatusNotFound, "Not found")
- }
- delete(config.Admins, c.Param("name"))
- saveConfig()
- return c.JSON(http.StatusOK, genConfig())
- })
- g.DELETE("/board/:id", func(c echo.Context) error {
- id64, err := strconv.ParseUint(c.Param("id"), 10, 16)
- if err != nil {
- return c.String(http.StatusNotAcceptable, "Invalid ID")
- }
- id := uint16(id64)
- _, ok := config.Boards[id]
- if !ok {
- return c.String(http.StatusNotFound, "Not found")
- }
- delete(config.Boards, id)
- saveConfig()
- return c.JSON(http.StatusOK, genConfig())
- })
- e.POST("/login", func(c echo.Context) error {
- username := c.FormValue("username")
- password := c.FormValue("password")
- user, ok := config.Admins[username]
- if !ok || !user.checkPassword(password) {
- return c.File("server/templates/login.html")
- }
- sess, _ := session.Get("session", c)
- sess.Options = &sessions.Options{
- Path: "/",
- MaxAge: 86400 * 7,
- HttpOnly: true,
- }
- sess.Values["username"] = user.Username
- sess.Values["authorised"] = true
- err := sess.Save(c.Request(), c.Response())
- errCheck(err, "Failed to save session")
- return c.Redirect(http.StatusTemporaryRedirect, "/admin")
- })
- g.GET("/logout", func(c echo.Context) error {
- sess, _ := session.Get("session", c)
- sess.Values["authorised"] = false
- err := sess.Save(c.Request(), c.Response())
- errCheck(err, "Failed to save session")
- return c.Redirect(http.StatusTemporaryRedirect, "/login")
- })
- //g.Use(middleware.BasicAuth()
- g.GET("/config", func(c echo.Context) error {
- return c.JSON(http.StatusOK, genConfig())
- })
- e.Logger.Fatal(e.Start(address))
- }
|