easybridge/web.go

172 lines
3.6 KiB
Go

package main
import (
"crypto/rand"
"html/template"
"log"
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
)
const SESSION_NAME = "easybridge_session"
var sessionsStore sessions.Store = nil
func StartWeb() {
session_key := make([]byte, 32)
n, err := rand.Read(session_key)
if err != nil || n != 32 {
log.Fatal(err)
}
sessionsStore = sessions.NewCookieStore(session_key)
r := mux.NewRouter()
r.HandleFunc("/", handleHome)
r.HandleFunc("/logout", handleLogout)
staticfiles := http.FileServer(http.Dir("static"))
r.Handle("/static/{file:.*}", http.StripPrefix("/static/", staticfiles))
log.Printf("Starting web UI HTTP server on %s", config.WebBindAddr)
go func() {
err = http.ListenAndServe(config.WebBindAddr, logRequest(r))
if err != nil {
log.Fatal("Cannot start http server: ", err)
}
}()
}
func logRequest(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL)
handler.ServeHTTP(w, r)
})
}
// ----
type LoginInfo struct {
MxId string
}
func checkLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
var login_info *LoginInfo
session, err := sessionsStore.Get(r, SESSION_NAME)
if err == nil {
mxid, ok := session.Values["login_mxid"]
if ok {
login_info = &LoginInfo{
MxId: mxid.(string),
}
}
}
if login_info == nil {
login_info = handleLogin(w, r)
}
return login_info
}
// ----
type HomeData struct {
Login *LoginInfo
Accounts map[string]*Account
}
func handleHome(w http.ResponseWriter, r *http.Request) {
templateHome := template.Must(template.ParseFiles("templates/layout.html", "templates/home.html"))
login := checkLogin(w, r)
if login == nil {
return
}
accountsLock.Lock()
defer accountsLock.Unlock()
templateHome.Execute(w, &HomeData{
Login: login,
Accounts: registeredAccounts[login.MxId],
})
}
func handleLogout(w http.ResponseWriter, r *http.Request) {
session, err := sessionsStore.Get(r, SESSION_NAME)
if err != nil {
session, _ = sessionsStore.New(r, SESSION_NAME)
}
delete(session.Values, "login_mxid")
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/", http.StatusFound)
}
type LoginFormData struct {
Username string
WrongPass bool
ErrorMessage string
MatrixDomain string
}
func handleLogin(w http.ResponseWriter, r *http.Request) *LoginInfo {
templateLogin := template.Must(template.ParseFiles("templates/layout.html", "templates/login.html"))
data := &LoginFormData{
MatrixDomain: config.MatrixDomain,
}
if r.Method == "GET" {
templateLogin.Execute(w, data)
return nil
} else if r.Method == "POST" {
r.ParseForm()
username := strings.Join(r.Form["username"], "")
password := strings.Join(r.Form["password"], "")
cli := mxlib.NewClient(config.Server, "")
mxid, err := cli.PasswordLogin(username, password, "EZBRIDGE", "Easybridge")
if err != nil {
data.Username = username
data.ErrorMessage = err.Error()
templateLogin.Execute(w, data)
return nil
}
// Successfully logged in, save it to session
session, err := sessionsStore.Get(r, SESSION_NAME)
if err != nil {
session, _ = sessionsStore.New(r, SESSION_NAME)
}
session.Values["login_mxid"] = mxid
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return nil
}
return &LoginInfo{
MxId: mxid,
}
} else {
http.Error(w, "Unsupported method", http.StatusBadRequest)
return nil
}
}