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 } }