alexvanin
f0f31a8415
This commits adds new feature for galchedbot: video requests in the twitch chat via highlighted chat messages. This messages parsed by the bot and added to the video queue, that can be accessed by the dedicated web server. Video queue requires authorization based on random token added to the cookies.
159 lines
3.4 KiB
Go
159 lines
3.4 KiB
Go
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,
|
|
})
|
|
}
|