1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-01-07 18:30:26 +00:00

Auth: Refactor login and logout

GET /login and POST /login-data are merged into /login.

GET /logout and POST /logout-confirm are merged into /logout.

The logout form now looks more consistent with other forms.

Used io.WriteString instead of Fprint where it wasn't like that for some reason.
This commit is contained in:
Timur Ismagilov 2021-12-31 02:07:39 +05:00
parent d75f96d5ce
commit 51f5ebf46d
3 changed files with 124 additions and 124 deletions

View File

@ -45,7 +45,7 @@
<main class="main-width"> <main class="main-width">
<section> <section>
{% if cfg.UseAuth %} {% if cfg.UseAuth %}
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on"> <form class="modal" method="post" action="/login" id="login-form" enctype="multipart/form-data" autocomplete="on">
<fieldset class="modal__fieldset"> <fieldset class="modal__fieldset">
<legend class="modal__title">{%s lc.Get("auth.login_header", &l18n.Replacements{"name": cfg.WikiName}) %}</legend> <legend class="modal__title">{%s lc.Get("auth.login_header", &l18n.Replacements{"name": cfg.WikiName}) %}</legend>
<label for="login-form__username">{%s lc.Get("auth.username") %}</label> <label for="login-form__username">{%s lc.Get("auth.username") %}</label>
@ -102,8 +102,10 @@ Telegram auth widget was requested by Yogurt. As you can see, we don't offer use
<section> <section>
{% if can %} {% if can %}
<h1>{%s lc.Get("auth.logout_header") %}</h1> <h1>{%s lc.Get("auth.logout_header") %}</h1>
<p><a href="/logout-confirm"><strong>{%s lc.Get("auth.logout_button") %}</strong></a></p> <form method="POST" action="/logout">
<p><a href="/">{%s lc.Get("ui.cancel") %}</a></p> <input class="btn btn_accent" type="submit" value="{%s lc.Get("auth.logout_button") %}"/>
<a class="btn btn_weak" href="/">{%s lc.Get("auth.go_home") %}</a>
</form>
{% else %} {% else %}
<p>{%s lc.Get("auth.logout_anon") %}</p> <p>{%s lc.Get("auth.logout_anon") %}</p>
<p><a href="/login">{%s lc.Get("auth.login_title") %}</a></p> <p><a href="/login">{%s lc.Get("auth.login_title") %}</a></p>
@ -129,7 +131,7 @@ Telegram auth widget was requested by Yogurt. As you can see, we don't offer use
<section class="locked-notice__message"> <section class="locked-notice__message">
<p class="locked-notice__lock">🔒</p> <p class="locked-notice__lock">🔒</p>
<h1 class="locked-notice__title">{%s lc.Get("auth.lock_title") %}</h1> <h1 class="locked-notice__title">{%s lc.Get("auth.lock_title") %}</h1>
<form class="locked-notice__login-form" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on"> <form class="locked-notice__login-form" method="post" action="/login" id="login-form" enctype="multipart/form-data" autocomplete="on">
<label for="login-form__username">{%s lc.Get("auth.username") %}</label> <label for="login-form__username">{%s lc.Get("auth.username") %}</label>
<br> <br>
<input type="text" required autofocus id="login-form__username" name="username" autocomplete="username"> <input type="text" required autofocus id="login-form__username" name="username" autocomplete="username">

View File

@ -190,7 +190,7 @@ func StreamLoginHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
if cfg.UseAuth { if cfg.UseAuth {
//line views/auth.qtpl:47 //line views/auth.qtpl:47
qw422016.N().S(` qw422016.N().S(`
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on"> <form class="modal" method="post" action="/login" id="login-form" enctype="multipart/form-data" autocomplete="on">
<fieldset class="modal__fieldset"> <fieldset class="modal__fieldset">
<legend class="modal__title">`) <legend class="modal__title">`)
//line views/auth.qtpl:50 //line views/auth.qtpl:50
@ -446,77 +446,79 @@ func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool, lc *l18n.Localizer) {
qw422016.E().S(lc.Get("auth.logout_header")) qw422016.E().S(lc.Get("auth.logout_header"))
//line views/auth.qtpl:104 //line views/auth.qtpl:104
qw422016.N().S(`</h1> qw422016.N().S(`</h1>
<p><a href="/logout-confirm"><strong>`) <form method="POST" action="/logout">
//line views/auth.qtpl:105 <input class="btn btn_accent" type="submit" value="`)
//line views/auth.qtpl:106
qw422016.E().S(lc.Get("auth.logout_button")) qw422016.E().S(lc.Get("auth.logout_button"))
//line views/auth.qtpl:105
qw422016.N().S(`</strong></a></p>
<p><a href="/">`)
//line views/auth.qtpl:106 //line views/auth.qtpl:106
qw422016.E().S(lc.Get("ui.cancel")) qw422016.N().S(`"/>
//line views/auth.qtpl:106 <a class="btn btn_weak" href="/">`)
qw422016.N().S(`</a></p> //line views/auth.qtpl:107
qw422016.E().S(lc.Get("auth.go_home"))
//line views/auth.qtpl:107
qw422016.N().S(`</a>
</form>
`) `)
//line views/auth.qtpl:107 //line views/auth.qtpl:109
} else { } else {
//line views/auth.qtpl:107 //line views/auth.qtpl:109
qw422016.N().S(` qw422016.N().S(`
<p>`) <p>`)
//line views/auth.qtpl:108 //line views/auth.qtpl:110
qw422016.E().S(lc.Get("auth.logout_anon")) qw422016.E().S(lc.Get("auth.logout_anon"))
//line views/auth.qtpl:108 //line views/auth.qtpl:110
qw422016.N().S(`</p> qw422016.N().S(`</p>
<p><a href="/login">`) <p><a href="/login">`)
//line views/auth.qtpl:109 //line views/auth.qtpl:111
qw422016.E().S(lc.Get("auth.login_title")) qw422016.E().S(lc.Get("auth.login_title"))
//line views/auth.qtpl:109 //line views/auth.qtpl:111
qw422016.N().S(`</a></p> qw422016.N().S(`</a></p>
<p><a href="/"> `) <p><a href="/"> `)
//line views/auth.qtpl:110 //line views/auth.qtpl:112
qw422016.E().S(lc.Get("auth.go_home")) qw422016.E().S(lc.Get("auth.go_home"))
//line views/auth.qtpl:110 //line views/auth.qtpl:112
qw422016.N().S(`</a></p> qw422016.N().S(`</a></p>
`) `)
//line views/auth.qtpl:111 //line views/auth.qtpl:113
} }
//line views/auth.qtpl:111 //line views/auth.qtpl:113
qw422016.N().S(` qw422016.N().S(`
</section> </section>
</main> </main>
</div> </div>
`) `)
//line views/auth.qtpl:115 //line views/auth.qtpl:117
} }
//line views/auth.qtpl:115 //line views/auth.qtpl:117
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool, lc *l18n.Localizer) { func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool, lc *l18n.Localizer) {
//line views/auth.qtpl:115 //line views/auth.qtpl:117
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:115 //line views/auth.qtpl:117
StreamLogoutHTML(qw422016, can, lc) StreamLogoutHTML(qw422016, can, lc)
//line views/auth.qtpl:115 //line views/auth.qtpl:117
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:115 //line views/auth.qtpl:117
} }
//line views/auth.qtpl:115 //line views/auth.qtpl:117
func LogoutHTML(can bool, lc *l18n.Localizer) string { func LogoutHTML(can bool, lc *l18n.Localizer) string {
//line views/auth.qtpl:115 //line views/auth.qtpl:117
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:115 //line views/auth.qtpl:117
WriteLogoutHTML(qb422016, can, lc) WriteLogoutHTML(qb422016, can, lc)
//line views/auth.qtpl:115 //line views/auth.qtpl:117
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/auth.qtpl:115 //line views/auth.qtpl:117
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:115 //line views/auth.qtpl:117
return qs422016 return qs422016
//line views/auth.qtpl:115 //line views/auth.qtpl:117
} }
//line views/auth.qtpl:117 //line views/auth.qtpl:119
func StreamLockHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) { func StreamLockHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:117 //line views/auth.qtpl:119
qw422016.N().S(` qw422016.N().S(`
<!doctype html> <!doctype html>
<html> <html>
@ -524,9 +526,9 @@ func StreamLockHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>🔒 `) <title>🔒 `)
//line views/auth.qtpl:123 //line views/auth.qtpl:125
qw422016.E().S(lc.Get("auth.lock_title")) qw422016.E().S(lc.Get("auth.lock_title"))
//line views/auth.qtpl:123 //line views/auth.qtpl:125
qw422016.N().S(`</title> qw422016.N().S(`</title>
<link rel="shortcut icon" href="/static/favicon.ico"> <link rel="shortcut icon" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/style.css"> <link rel="stylesheet" href="/static/style.css">
@ -536,68 +538,68 @@ func StreamLockHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
<section class="locked-notice__message"> <section class="locked-notice__message">
<p class="locked-notice__lock">🔒</p> <p class="locked-notice__lock">🔒</p>
<h1 class="locked-notice__title">`) <h1 class="locked-notice__title">`)
//line views/auth.qtpl:131 //line views/auth.qtpl:133
qw422016.E().S(lc.Get("auth.lock_title")) qw422016.E().S(lc.Get("auth.lock_title"))
//line views/auth.qtpl:131 //line views/auth.qtpl:133
qw422016.N().S(`</h1> qw422016.N().S(`</h1>
<form class="locked-notice__login-form" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on"> <form class="locked-notice__login-form" method="post" action="/login" id="login-form" enctype="multipart/form-data" autocomplete="on">
<label for="login-form__username">`) <label for="login-form__username">`)
//line views/auth.qtpl:133 //line views/auth.qtpl:135
qw422016.E().S(lc.Get("auth.username")) qw422016.E().S(lc.Get("auth.username"))
//line views/auth.qtpl:133 //line views/auth.qtpl:135
qw422016.N().S(`</label> qw422016.N().S(`</label>
<br> <br>
<input type="text" required autofocus id="login-form__username" name="username" autocomplete="username"> <input type="text" required autofocus id="login-form__username" name="username" autocomplete="username">
<br> <br>
<label for="login-form__password">`) <label for="login-form__password">`)
//line views/auth.qtpl:137 //line views/auth.qtpl:139
qw422016.E().S(lc.Get("auth.password")) qw422016.E().S(lc.Get("auth.password"))
//line views/auth.qtpl:137 //line views/auth.qtpl:139
qw422016.N().S(`</label> qw422016.N().S(`</label>
<br> <br>
<input type="password" required name="password" autocomplete="current-password"> <input type="password" required name="password" autocomplete="current-password">
<br> <br>
<button class="btn" type="submit" value="Log in">`) <button class="btn" type="submit" value="Log in">`)
//line views/auth.qtpl:141 //line views/auth.qtpl:143
qw422016.E().S(lc.Get("auth.login_button")) qw422016.E().S(lc.Get("auth.login_button"))
//line views/auth.qtpl:141 //line views/auth.qtpl:143
qw422016.N().S(`</button> qw422016.N().S(`</button>
</form> </form>
`) `)
//line views/auth.qtpl:143 //line views/auth.qtpl:145
streamtelegramWidgetHTML(qw422016, lc) streamtelegramWidgetHTML(qw422016, lc)
//line views/auth.qtpl:143 //line views/auth.qtpl:145
qw422016.N().S(` qw422016.N().S(`
</section> </section>
</main> </main>
</body> </body>
</html> </html>
`) `)
//line views/auth.qtpl:148 //line views/auth.qtpl:150
} }
//line views/auth.qtpl:148 //line views/auth.qtpl:150
func WriteLockHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) { func WriteLockHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:148 //line views/auth.qtpl:150
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:148 //line views/auth.qtpl:150
StreamLockHTML(qw422016, lc) StreamLockHTML(qw422016, lc)
//line views/auth.qtpl:148 //line views/auth.qtpl:150
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:148 //line views/auth.qtpl:150
} }
//line views/auth.qtpl:148 //line views/auth.qtpl:150
func LockHTML(lc *l18n.Localizer) string { func LockHTML(lc *l18n.Localizer) string {
//line views/auth.qtpl:148 //line views/auth.qtpl:150
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:148 //line views/auth.qtpl:150
WriteLockHTML(qb422016, lc) WriteLockHTML(qb422016, lc)
//line views/auth.qtpl:148 //line views/auth.qtpl:150
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/auth.qtpl:148 //line views/auth.qtpl:150
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:148 //line views/auth.qtpl:150
return qs422016 return qs422016
//line views/auth.qtpl:148 //line views/auth.qtpl:150
} }

View File

@ -20,6 +20,7 @@ import (
func initAuth(r *mux.Router) { func initAuth(r *mux.Router) {
r.HandleFunc("/lock", handlerLock) r.HandleFunc("/lock", handlerLock)
// The check below saves a lot of extra checks and lines of codes in other places in this file.
if !cfg.UseAuth { if !cfg.UseAuth {
return return
} }
@ -30,24 +31,19 @@ func initAuth(r *mux.Router) {
r.HandleFunc("/telegram-login", handlerTelegramLogin) r.HandleFunc("/telegram-login", handlerTelegramLogin)
} }
r.HandleFunc("/login", handlerLogin) r.HandleFunc("/login", handlerLogin)
r.HandleFunc("/login-data", handlerLoginData)
r.HandleFunc("/logout", handlerLogout) r.HandleFunc("/logout", handlerLogout)
r.HandleFunc("/logout-confirm", handlerLogoutConfirm)
} }
func handlerLock(w http.ResponseWriter, rq *http.Request) { func handlerLock(w http.ResponseWriter, rq *http.Request) {
io.WriteString(w, views.LockHTML(l18n.FromRequest(rq))) _, _ = io.WriteString(w, views.LockHTML(l18n.FromRequest(rq)))
} }
// handlerRegister both displays the register form (GET) and registers users (POST). // handlerRegister displays the register form (GET) or registers the user (POST).
func handlerRegister(w http.ResponseWriter, rq *http.Request) { func handlerRegister(w http.ResponseWriter, rq *http.Request) {
lc := l18n.FromRequest(rq) lc := l18n.FromRequest(rq)
util.PrepareRq(rq) util.PrepareRq(rq)
if !cfg.AllowRegistration {
w.WriteHeader(http.StatusForbidden)
}
if rq.Method == http.MethodGet { if rq.Method == http.MethodGet {
io.WriteString( _, _ = io.WriteString(
w, w,
views.BaseHTML( views.BaseHTML(
lc.Get("auth.register_title"), lc.Get("auth.register_title"),
@ -66,7 +62,7 @@ func handlerRegister(w http.ResponseWriter, rq *http.Request) {
log.Printf("Failed to register %s: %s", username, err.Error()) log.Printf("Failed to register %s: %s", username, err.Error())
w.Header().Set("Content-Type", mime.TypeByExtension(".html")) w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
fmt.Fprint( _, _ = io.WriteString(
w, w,
views.BaseHTML( views.BaseHTML(
lc.Get("auth.register_title"), lc.Get("auth.register_title"),
@ -87,43 +83,61 @@ func handlerRegister(w http.ResponseWriter, rq *http.Request) {
} }
} }
// handlerLogout shows the logout form. // handlerLogout shows the logout form (GET) or logs the user out (POST).
func handlerLogout(w http.ResponseWriter, rq *http.Request) { func handlerLogout(w http.ResponseWriter, rq *http.Request) {
var ( if rq.Method == http.MethodGet {
u = user.FromRequest(rq) var (
can = u != nil u = user.FromRequest(rq)
lc = l18n.FromRequest(rq) can = u != nil
) lc = l18n.FromRequest(rq)
w.Header().Set("Content-Type", "text/html;charset=utf-8") )
if can { w.Header().Set("Content-Type", "text/html;charset=utf-8")
log.Println("User", u.Name, "tries to log out") if can {
w.WriteHeader(http.StatusOK) log.Println("User", u.Name, "tries to log out")
} else { w.WriteHeader(http.StatusOK)
log.Println("Unknown user tries to log out") } else {
w.WriteHeader(http.StatusForbidden) log.Println("Unknown user tries to log out")
w.WriteHeader(http.StatusForbidden)
}
_, _ = io.WriteString(
w,
views.BaseHTML(lc.Get("auth.logout_title"), views.LogoutHTML(can, lc), lc, u),
)
} else if rq.Method == http.MethodPost {
user.LogoutFromRequest(w, rq)
http.Redirect(w, rq, "/", http.StatusSeeOther)
} }
w.Write([]byte(views.BaseHTML(lc.Get("auth.logout_title"), views.LogoutHTML(can, lc), lc, u)))
} }
// handlerLogoutConfirm logs the user out. // handlerLogin shows the login form (GET) or logs the user in (POST).
//
// TODO: merge into handlerLogout as POST method.
func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) {
user.LogoutFromRequest(w, rq)
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
// handlerLogin shows the login form.
func handlerLogin(w http.ResponseWriter, rq *http.Request) { func handlerLogin(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
if cfg.UseAuth {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusForbidden)
}
lc := l18n.FromRequest(rq) lc := l18n.FromRequest(rq)
w.Write([]byte(views.BaseHTML(lc.Get("auth.login_title"), views.LoginHTML(lc), lc, user.EmptyUser()))) if rq.Method == http.MethodGet {
w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = io.WriteString(
w,
views.BaseHTML(
lc.Get("auth.login_title"),
views.LoginHTML(lc),
lc,
user.EmptyUser(),
),
)
} 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)
_, _ = io.WriteString(w, views.BaseHTML(err, views.LoginErrorHTML(err, lc), lc, user.EmptyUser()))
return
}
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
} }
func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) { func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
@ -155,7 +169,7 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
if err != nil { if err != nil {
log.Printf("Failed to register %s using Telegram: %s", username, err.Error()) log.Printf("Failed to register %s using Telegram: %s", username, err.Error())
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
fmt.Fprint( _, _ = io.WriteString(
w, w,
views.BaseHTML( views.BaseHTML(
lc.Get("ui.error"), lc.Get("ui.error"),
@ -176,7 +190,7 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
if errmsg != "" { if errmsg != "" {
log.Printf("Failed to login %s using Telegram: %s", username, err.Error()) log.Printf("Failed to login %s using Telegram: %s", username, err.Error())
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
fmt.Fprint( _, _ = io.WriteString(
w, w,
views.BaseHTML( views.BaseHTML(
"Error", "Error",
@ -195,21 +209,3 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
log.Printf("Authorize %s from Telegram", username) log.Printf("Authorize %s from Telegram", username)
http.Redirect(w, rq, "/", http.StatusSeeOther) http.Redirect(w, rq, "/", http.StatusSeeOther)
} }
// handlerLoginData logs the user in.
//
// TODO: merge into handlerLogin as POST method.
func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
lc := l18n.FromRequest(rq)
util.PrepareRq(rq)
var (
username = util.CanonicalName(rq.PostFormValue("username"))
password = rq.PostFormValue("password")
err = user.LoginDataHTTP(w, rq, username, password)
)
if err != "" {
w.Write([]byte(views.BaseHTML(err, views.LoginErrorHTML(err, lc), lc, user.EmptyUser())))
} else {
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
}