2021-05-09 10:42:12 +00:00
|
|
|
|
package web
|
2020-11-14 13:03:06 +00:00
|
|
|
|
|
|
|
|
|
import (
|
2021-07-14 19:51:55 +00:00
|
|
|
|
"errors"
|
2021-07-01 08:45:03 +00:00
|
|
|
|
"fmt"
|
2022-04-01 19:51:15 +00:00
|
|
|
|
"github.com/bouncepaw/mycorrhiza/viewutil"
|
2021-04-12 17:40:43 +00:00
|
|
|
|
"io"
|
2020-11-14 13:03:06 +00:00
|
|
|
|
"log"
|
2021-07-01 08:45:03 +00:00
|
|
|
|
"mime"
|
2020-11-14 13:03:06 +00:00
|
|
|
|
"net/http"
|
2021-07-14 19:51:55 +00:00
|
|
|
|
"strings"
|
2020-11-14 13:03:06 +00:00
|
|
|
|
|
2021-07-15 17:46:35 +00:00
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
|
|
2021-07-01 08:45:03 +00:00
|
|
|
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
2021-09-06 17:46:34 +00:00
|
|
|
|
"github.com/bouncepaw/mycorrhiza/l18n"
|
2020-11-14 13:03:06 +00:00
|
|
|
|
"github.com/bouncepaw/mycorrhiza/user"
|
2021-02-17 18:41:35 +00:00
|
|
|
|
"github.com/bouncepaw/mycorrhiza/util"
|
2021-02-23 14:25:07 +00:00
|
|
|
|
"github.com/bouncepaw/mycorrhiza/views"
|
2020-11-14 13:03:06 +00:00
|
|
|
|
)
|
|
|
|
|
|
2021-07-15 17:46:35 +00:00
|
|
|
|
func initAuth(r *mux.Router) {
|
|
|
|
|
r.HandleFunc("/lock", handlerLock)
|
2021-12-30 21:07:39 +00:00
|
|
|
|
// The check below saves a lot of extra checks and lines of codes in other places in this file.
|
2021-07-02 08:20:03 +00:00
|
|
|
|
if !cfg.UseAuth {
|
2021-05-09 11:09:27 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
2021-07-02 08:20:03 +00:00
|
|
|
|
if cfg.AllowRegistration {
|
2021-07-15 17:46:35 +00:00
|
|
|
|
r.HandleFunc("/register", handlerRegister)
|
2021-05-09 11:09:27 +00:00
|
|
|
|
}
|
2021-07-14 19:51:55 +00:00
|
|
|
|
if cfg.TelegramEnabled {
|
2021-07-15 17:46:35 +00:00
|
|
|
|
r.HandleFunc("/telegram-login", handlerTelegramLogin)
|
2021-07-14 19:51:55 +00:00
|
|
|
|
}
|
2021-07-15 17:46:35 +00:00
|
|
|
|
r.HandleFunc("/login", handlerLogin)
|
|
|
|
|
r.HandleFunc("/logout", handlerLogout)
|
2020-11-14 13:03:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 11:47:50 +00:00
|
|
|
|
func handlerLock(w http.ResponseWriter, rq *http.Request) {
|
2022-03-20 21:24:40 +00:00
|
|
|
|
_, _ = io.WriteString(w, views.Lock(l18n.FromRequest(rq)))
|
2021-07-09 11:47:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 21:07:39 +00:00
|
|
|
|
// handlerRegister displays the register form (GET) or registers the user (POST).
|
2021-04-12 17:40:43 +00:00
|
|
|
|
func handlerRegister(w http.ResponseWriter, rq *http.Request) {
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc := l18n.FromRequest(rq)
|
2021-05-09 10:42:12 +00:00
|
|
|
|
util.PrepareRq(rq)
|
2021-04-12 17:40:43 +00:00
|
|
|
|
if rq.Method == http.MethodGet {
|
2021-12-30 21:07:39 +00:00
|
|
|
|
_, _ = io.WriteString(
|
2021-04-12 17:40:43 +00:00
|
|
|
|
w,
|
2022-03-20 21:24:40 +00:00
|
|
|
|
views.Base(
|
2022-04-01 19:51:15 +00:00
|
|
|
|
viewutil.MetaFrom(w, rq),
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc.Get("auth.register_title"),
|
2022-03-20 21:24:40 +00:00
|
|
|
|
views.Register(rq),
|
2021-04-12 17:40:43 +00:00
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
} else if rq.Method == http.MethodPost {
|
2021-04-19 16:39:25 +00:00
|
|
|
|
var (
|
|
|
|
|
username = rq.PostFormValue("username")
|
|
|
|
|
password = rq.PostFormValue("password")
|
2021-07-14 21:00:35 +00:00
|
|
|
|
err = user.Register(username, password, "editor", "local", false)
|
2021-04-19 16:39:25 +00:00
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
2021-08-12 12:12:53 +00:00
|
|
|
|
log.Printf("Failed to register ‘%s’: %s", username, err.Error())
|
2021-07-01 08:45:03 +00:00
|
|
|
|
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2021-12-30 21:07:39 +00:00
|
|
|
|
_, _ = io.WriteString(
|
2021-07-01 08:45:03 +00:00
|
|
|
|
w,
|
2022-03-20 21:24:40 +00:00
|
|
|
|
views.Base(
|
2022-04-01 19:51:15 +00:00
|
|
|
|
viewutil.MetaFrom(w, rq),
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc.Get("auth.register_title"),
|
2021-07-01 08:45:03 +00:00
|
|
|
|
fmt.Sprintf(
|
2021-09-06 17:46:34 +00:00
|
|
|
|
`<main class="main-width"><p>%s</p><p><a href="/register">%s<a></p></main>`,
|
2021-07-01 08:45:03 +00:00
|
|
|
|
err.Error(),
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc.Get("auth.try_again"),
|
2021-07-01 08:45:03 +00:00
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)
|
2021-04-19 16:39:25 +00:00
|
|
|
|
} else {
|
2021-08-12 12:12:53 +00:00
|
|
|
|
log.Printf("Successfully registered ‘%s’", username)
|
2021-04-19 16:39:25 +00:00
|
|
|
|
user.LoginDataHTTP(w, rq, username, password)
|
|
|
|
|
http.Redirect(w, rq, "/"+rq.URL.RawQuery, http.StatusSeeOther)
|
|
|
|
|
}
|
2021-04-12 17:40:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 21:07:39 +00:00
|
|
|
|
// handlerLogout shows the logout form (GET) or logs the user out (POST).
|
2020-11-14 13:03:06 +00:00
|
|
|
|
func handlerLogout(w http.ResponseWriter, rq *http.Request) {
|
2021-12-30 21:07:39 +00:00
|
|
|
|
if rq.Method == http.MethodGet {
|
|
|
|
|
var (
|
|
|
|
|
u = user.FromRequest(rq)
|
|
|
|
|
can = u != nil
|
|
|
|
|
lc = l18n.FromRequest(rq)
|
|
|
|
|
)
|
|
|
|
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
|
|
|
|
if can {
|
|
|
|
|
log.Println("User", u.Name, "tries to log out")
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
} else {
|
|
|
|
|
log.Println("Unknown user tries to log out")
|
|
|
|
|
w.WriteHeader(http.StatusForbidden)
|
|
|
|
|
}
|
|
|
|
|
_, _ = io.WriteString(
|
|
|
|
|
w,
|
2022-04-01 19:51:15 +00:00
|
|
|
|
views.Base(viewutil.MetaFrom(w, rq), lc.Get("auth.logout_title"), views.Logout(can, lc)),
|
2021-12-30 21:07:39 +00:00
|
|
|
|
)
|
|
|
|
|
} else if rq.Method == http.MethodPost {
|
|
|
|
|
user.LogoutFromRequest(w, rq)
|
|
|
|
|
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
2020-11-14 13:03:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 21:07:39 +00:00
|
|
|
|
// handlerLogin shows the login form (GET) or logs the user in (POST).
|
2021-05-09 11:09:27 +00:00
|
|
|
|
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
|
2021-12-30 21:07:39 +00:00
|
|
|
|
lc := l18n.FromRequest(rq)
|
|
|
|
|
if rq.Method == http.MethodGet {
|
|
|
|
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
2021-05-09 11:09:27 +00:00
|
|
|
|
w.WriteHeader(http.StatusOK)
|
2021-12-30 21:07:39 +00:00
|
|
|
|
_, _ = io.WriteString(
|
|
|
|
|
w,
|
2022-03-20 21:24:40 +00:00
|
|
|
|
views.Base(
|
2022-04-01 19:51:15 +00:00
|
|
|
|
viewutil.MetaFrom(w, rq),
|
2021-12-30 21:07:39 +00:00
|
|
|
|
lc.Get("auth.login_title"),
|
2022-03-20 21:24:40 +00:00
|
|
|
|
views.Login(lc),
|
2021-12-30 21:07:39 +00:00
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
} else if rq.Method == http.MethodPost {
|
|
|
|
|
var (
|
|
|
|
|
username = util.CanonicalName(rq.PostFormValue("username"))
|
|
|
|
|
password = rq.PostFormValue("password")
|
|
|
|
|
err = user.LoginDataHTTP(w, rq, username, password)
|
|
|
|
|
)
|
|
|
|
|
if err != "" {
|
|
|
|
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2022-04-01 19:51:15 +00:00
|
|
|
|
_, _ = io.WriteString(w, views.Base(viewutil.MetaFrom(w, rq), err, views.LoginError(err, lc)))
|
2021-12-30 21:07:39 +00:00
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
2021-05-09 11:09:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-14 19:51:55 +00:00
|
|
|
|
func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
|
|
|
|
|
// Note there is no lock here.
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc := l18n.FromRequest(rq)
|
2021-07-14 20:04:52 +00:00
|
|
|
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
2021-07-14 19:51:55 +00:00
|
|
|
|
rq.ParseForm()
|
|
|
|
|
var (
|
2021-07-15 17:46:35 +00:00
|
|
|
|
values = rq.URL.Query()
|
|
|
|
|
username = strings.ToLower(values.Get("username"))
|
2021-07-14 19:51:55 +00:00
|
|
|
|
seemsValid = user.TelegramAuthParamsAreValid(values)
|
2021-07-15 17:46:35 +00:00
|
|
|
|
err = user.Register(
|
2021-07-14 19:51:55 +00:00
|
|
|
|
username,
|
|
|
|
|
"", // Password matters not
|
2021-07-14 21:00:35 +00:00
|
|
|
|
"editor",
|
2021-07-14 19:51:55 +00:00
|
|
|
|
"telegram",
|
|
|
|
|
false,
|
|
|
|
|
)
|
|
|
|
|
)
|
2021-10-01 17:12:16 +00:00
|
|
|
|
if user.HasUsername(username) && user.ByName(username).Source == "telegram" {
|
2021-07-14 19:51:55 +00:00
|
|
|
|
// Problems is something we put blankets on.
|
|
|
|
|
err = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !seemsValid {
|
|
|
|
|
err = errors.New("Wrong parameters")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Printf("Failed to register ‘%s’ using Telegram: %s", username, err.Error())
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2021-12-30 21:07:39 +00:00
|
|
|
|
_, _ = io.WriteString(
|
2021-07-14 19:51:55 +00:00
|
|
|
|
w,
|
2022-03-20 21:24:40 +00:00
|
|
|
|
views.Base(
|
2022-04-01 19:51:15 +00:00
|
|
|
|
viewutil.MetaFrom(w, rq),
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc.Get("ui.error"),
|
2021-07-14 19:51:55 +00:00
|
|
|
|
fmt.Sprintf(
|
2021-09-06 17:46:34 +00:00
|
|
|
|
`<main class="main-width"><p>%s</p><p>%s</p><p><a href="/login">%s<a></p></main>`,
|
|
|
|
|
lc.Get("auth.error_telegram"),
|
2021-07-14 19:51:55 +00:00
|
|
|
|
err.Error(),
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc.Get("auth.go_login"),
|
2021-07-14 19:51:55 +00:00
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errmsg := user.LoginDataHTTP(w, rq, username, "")
|
|
|
|
|
if errmsg != "" {
|
|
|
|
|
log.Printf("Failed to login ‘%s’ using Telegram: %s", username, err.Error())
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2021-12-30 21:07:39 +00:00
|
|
|
|
_, _ = io.WriteString(
|
2021-07-14 19:51:55 +00:00
|
|
|
|
w,
|
2022-03-20 21:24:40 +00:00
|
|
|
|
views.Base(
|
2022-04-01 19:51:15 +00:00
|
|
|
|
viewutil.MetaFrom(w, rq),
|
2021-07-14 19:51:55 +00:00
|
|
|
|
"Error",
|
|
|
|
|
fmt.Sprintf(
|
2021-09-06 17:46:34 +00:00
|
|
|
|
`<main class="main-width"><p>%s</p><p>%s</p><p><a href="/login">%s<a></p></main>`,
|
|
|
|
|
lc.Get("auth.error_telegram"),
|
2021-07-14 19:51:55 +00:00
|
|
|
|
err.Error(),
|
2021-09-06 17:46:34 +00:00
|
|
|
|
lc.Get("auth.go_login"),
|
2021-07-14 19:51:55 +00:00
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
log.Printf("Authorize ‘%s’ from Telegram", username)
|
|
|
|
|
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
|
|
|
|
}
|