galched-bot/modules/web/server.go

160 lines
3.4 KiB
Go
Raw Permalink Normal View History

package web
import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"time"
"galched-bot/modules/settings"
"galched-bot/modules/youtube"
)
type (
WebServer struct {
server http.Server
r *youtube.Requester
users map[string]string
authed map[string]struct{}
}
)
func New(s *settings.Settings, r *youtube.Requester) *WebServer {
srv := http.Server{
Addr: s.QueueAddress,
}
webServer := &WebServer{
server: srv,
r: r,
users: s.LoginUsers,
authed: make(map[string]struct{}, 10),
}
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
if request.Method != http.MethodGet {
return
}
if webServer.IsAuthorized(request) {
http.ServeFile(writer, request, "web/index.html")
} else {
http.Redirect(writer, request, "/login", 301)
}
})
http.HandleFunc("/login", func(writer http.ResponseWriter, request *http.Request) {
if request.Method == http.MethodGet {
http.ServeFile(writer, request, "web/login.html")
return
} else if request.Method != http.MethodPost {
return
}
login := request.FormValue("login")
pwd := request.FormValue("password")
log.Print("web: trying to log in with user: ", login)
if webServer.IsRegistered(login, pwd) {
webServer.Authorize(writer)
} else {
log.Print("web: incorrect password attempt")
}
http.Redirect(writer, request, "/", http.StatusSeeOther)
})
http.HandleFunc("/scripts.js", func(writer http.ResponseWriter, request *http.Request) {
if request.Method != http.MethodGet {
return
}
http.ServeFile(writer, request, "web/scripts.js")
})
http.HandleFunc("/style.css", func(writer http.ResponseWriter, request *http.Request) {
if request.Method != http.MethodGet {
return
}
http.ServeFile(writer, request, "web/style.css")
})
http.HandleFunc("/queue", func(writer http.ResponseWriter, request *http.Request) {
if !webServer.IsAuthorized(request) {
http.Error(writer, "not authorized", http.StatusUnauthorized)
return
}
switch request.Method {
case http.MethodGet:
case http.MethodPost:
body, err := ioutil.ReadAll(request.Body)
if err != nil {
log.Print("web: cannot read body msg, %v", err)
return
}
id := string(body)
if len(id) != youtube.YoutubeIDLength && len(id) > 0 {
log.Printf("web: incorrect data in body, <%s>", id)
return
}
r.Remove(id)
default:
return
}
writer.Header().Set("Content-Type", "application/json")
writer.Header().Set("Access-Control-Allow-Origin", "*")
json.NewEncoder(writer).Encode(webServer.r.List())
})
return webServer
}
func (s WebServer) Start() error {
go func() {
s.server.ListenAndServe()
}()
return nil
}
func (s WebServer) Stop(ctx context.Context) error {
return s.server.Shutdown(ctx)
}
func (s WebServer) IsAuthorized(request *http.Request) bool {
if cookie, err := request.Cookie("session"); err == nil {
if _, ok := s.authed[cookie.Value]; ok {
return true
}
}
return false
}
func (s WebServer) IsRegistered(login, pwd string) bool {
return s.users[login] == pwd
}
func (s WebServer) Authorize(response http.ResponseWriter) {
var byteKey = make([]byte, 16)
rand.Read(byteKey[:])
stringKey := hex.EncodeToString(byteKey)
s.authed[stringKey] = struct{}{}
log.Print("web: authenticated new user")
expires := time.Now().AddDate(0, 1, 0)
http.SetCookie(response, &http.Cookie{
Name: "session",
Value: stringKey,
Path: "/",
Expires: expires,
})
}