1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-12 05:20:26 +00:00

Implement logging out

This commit is contained in:
bouncepaw 2020-11-14 18:03:06 +05:00
parent a0d1099b75
commit f4ba0f5498
6 changed files with 330 additions and 190 deletions

62
http_auth.go Normal file
View File

@ -0,0 +1,62 @@
package main
import (
"log"
"net/http"
"github.com/bouncepaw/mycorrhiza/templates"
"github.com/bouncepaw/mycorrhiza/user"
)
func init() {
http.HandleFunc("/login", handlerLogin)
http.HandleFunc("/login-data", handlerLoginData)
http.HandleFunc("/logout", handlerLogout)
http.HandleFunc("/logout-confirm", handlerLogoutConfirm)
}
func handlerLogout(w http.ResponseWriter, rq *http.Request) {
var (
u = user.FromRequest(rq)
can = u != nil
)
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)
}
w.Write([]byte(base("Logout?", templates.LogoutHTML(can))))
}
func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) {
user.LogoutFromRequest(w, rq)
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
log.Println(rq.URL)
var (
username = CanonicalName(rq.PostFormValue("username"))
password = rq.PostFormValue("password")
err = user.LoginDataHTTP(w, rq, username, password)
)
if err != "" {
w.Write([]byte(base(err, templates.LoginErrorHTML(err))))
} else {
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
}
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
log.Println(rq.URL)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
if user.AuthUsed {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusForbidden)
}
w.Write([]byte(base("Login", templates.LoginHTML())))
}

29
main.go
View File

@ -15,7 +15,6 @@ import (
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/templates"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
)
@ -110,31 +109,6 @@ func handlerStyle(w http.ResponseWriter, rq *http.Request) {
}
}
func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
log.Println(rq.URL)
var (
username = CanonicalName(rq.PostFormValue("username"))
password = rq.PostFormValue("password")
err = user.LoginDataHTTP(w, rq, username, password)
)
if err != "" {
w.Write([]byte(base(err, templates.LoginErrorHTML(err))))
} else {
http.Redirect(w, rq, "/", http.StatusSeeOther)
}
}
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
log.Println(rq.URL)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
if user.AuthUsed {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusForbidden)
}
w.Write([]byte(base("Login", templates.LoginHTML())))
}
func main() {
log.Println("Running MycorrhizaWiki β")
parseCliArgs()
@ -151,6 +125,7 @@ func main() {
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(WikiDir+"/static"))))
// See http_readers.go for /page/, /text/, /binary/, /history/.
// See http_mutators.go for /upload-binary/, /upload-text/, /edit/, /delete-ask/, /delete-confirm/, /rename-ask/, /rename-confirm/.
// See http_auth.go for /login, /login-data, /logout, /logout-confirm
http.HandleFunc("/list", handlerList)
http.HandleFunc("/reindex", handlerReindex)
http.HandleFunc("/random", handlerRandom)
@ -159,8 +134,6 @@ func main() {
http.ServeFile(w, rq, WikiDir+"/static/favicon.ico")
})
http.HandleFunc("/static/common.css", handlerStyle)
http.HandleFunc("/login", handlerLogin)
http.HandleFunc("/login-data", handlerLoginData)
http.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) {
http.Redirect(w, rq, "/page/"+util.HomePage, http.StatusSeeOther)
})

View File

@ -43,3 +43,18 @@
</main>
{% endfunc %}
{% func LogoutHTML(can bool) %}
<main>
<section>
{% if can %}
<h1>Log out?</h1>
<p><a href="/logout-confirm"><strong>Confirm</strong></a></p>
<p><a href="/">Cancel</a></p>
{% else %}
<p>You cannot log out because you are not logged in.</p>
<p><a href="/login">Login</a></p>
<p><a href="/login">← Home</a></p>
{% endif %}
</section>
</main>
{% endfunc %}

218
templates/auth.qtpl.go Normal file
View File

@ -0,0 +1,218 @@
// Code generated by qtc from "auth.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
//line templates/auth.qtpl:1
package templates
//line templates/auth.qtpl:1
import "github.com/bouncepaw/mycorrhiza/user"
//line templates/auth.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line templates/auth.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line templates/auth.qtpl:3
func StreamLoginHTML(qw422016 *qt422016.Writer) {
//line templates/auth.qtpl:3
qw422016.N().S(`
<main>
<section>
`)
//line templates/auth.qtpl:6
if user.AuthUsed {
//line templates/auth.qtpl:6
qw422016.N().S(`
<h1>Login</h1>
<form method="post" action="/login-data" id="login-form" enctype="multipart/form-data">
<p>Use the data you were given by the administrator.</p>
<fieldset>
<legend>Username</legend>
<input type="text" required autofocus name="username" autocomplete="on">
</fieldset>
<fieldset>
<legend>Password</legend>
<input type="password" required name="password" autocomplete="on">
</fieldset>
<p>By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you.</p>
<input type="submit">
<a href="/">Cancel</a>
</form>
`)
//line templates/auth.qtpl:22
} else {
//line templates/auth.qtpl:22
qw422016.N().S(`
<p>Administrator of this wiki have not configured any authorization method. You can make edits anonymously.</p>
<p><a href="/"> Go home</a></p>
`)
//line templates/auth.qtpl:25
}
//line templates/auth.qtpl:25
qw422016.N().S(`
</section>
</main>
`)
//line templates/auth.qtpl:28
}
//line templates/auth.qtpl:28
func WriteLoginHTML(qq422016 qtio422016.Writer) {
//line templates/auth.qtpl:28
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/auth.qtpl:28
StreamLoginHTML(qw422016)
//line templates/auth.qtpl:28
qt422016.ReleaseWriter(qw422016)
//line templates/auth.qtpl:28
}
//line templates/auth.qtpl:28
func LoginHTML() string {
//line templates/auth.qtpl:28
qb422016 := qt422016.AcquireByteBuffer()
//line templates/auth.qtpl:28
WriteLoginHTML(qb422016)
//line templates/auth.qtpl:28
qs422016 := string(qb422016.B)
//line templates/auth.qtpl:28
qt422016.ReleaseByteBuffer(qb422016)
//line templates/auth.qtpl:28
return qs422016
//line templates/auth.qtpl:28
}
//line templates/auth.qtpl:30
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) {
//line templates/auth.qtpl:30
qw422016.N().S(`
<main>
<section>
`)
//line templates/auth.qtpl:33
switch err {
//line templates/auth.qtpl:34
case "unknown username":
//line templates/auth.qtpl:34
qw422016.N().S(`
<p class="error">Unknown username.</p>
`)
//line templates/auth.qtpl:36
case "wrong password":
//line templates/auth.qtpl:36
qw422016.N().S(`
<p class="error">Wrong password.</p>
`)
//line templates/auth.qtpl:38
default:
//line templates/auth.qtpl:38
qw422016.N().S(`
<p class="error">`)
//line templates/auth.qtpl:39
qw422016.E().S(err)
//line templates/auth.qtpl:39
qw422016.N().S(`</p>
`)
//line templates/auth.qtpl:40
}
//line templates/auth.qtpl:40
qw422016.N().S(`
<p><a href="/login"> Try again</a></p>
</section>
</main>
`)
//line templates/auth.qtpl:44
}
//line templates/auth.qtpl:44
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) {
//line templates/auth.qtpl:44
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/auth.qtpl:44
StreamLoginErrorHTML(qw422016, err)
//line templates/auth.qtpl:44
qt422016.ReleaseWriter(qw422016)
//line templates/auth.qtpl:44
}
//line templates/auth.qtpl:44
func LoginErrorHTML(err string) string {
//line templates/auth.qtpl:44
qb422016 := qt422016.AcquireByteBuffer()
//line templates/auth.qtpl:44
WriteLoginErrorHTML(qb422016, err)
//line templates/auth.qtpl:44
qs422016 := string(qb422016.B)
//line templates/auth.qtpl:44
qt422016.ReleaseByteBuffer(qb422016)
//line templates/auth.qtpl:44
return qs422016
//line templates/auth.qtpl:44
}
//line templates/auth.qtpl:46
func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) {
//line templates/auth.qtpl:46
qw422016.N().S(`
<main>
<section>
`)
//line templates/auth.qtpl:49
if can {
//line templates/auth.qtpl:49
qw422016.N().S(`
<h1>Log out?</h1>
<p><a href="/logout-confirm"><strong>Confirm</strong></a></p>
<p><a href="/">Cancel</a></p>
`)
//line templates/auth.qtpl:53
} else {
//line templates/auth.qtpl:53
qw422016.N().S(`
<p>You cannot log out because you are not logged in.</p>
<p><a href="/login">Login</a></p>
<p><a href="/login"> Home</a></p>
`)
//line templates/auth.qtpl:57
}
//line templates/auth.qtpl:57
qw422016.N().S(`
</section>
</main>
`)
//line templates/auth.qtpl:60
}
//line templates/auth.qtpl:60
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) {
//line templates/auth.qtpl:60
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/auth.qtpl:60
StreamLogoutHTML(qw422016, can)
//line templates/auth.qtpl:60
qt422016.ReleaseWriter(qw422016)
//line templates/auth.qtpl:60
}
//line templates/auth.qtpl:60
func LogoutHTML(can bool) string {
//line templates/auth.qtpl:60
qb422016 := qt422016.AcquireByteBuffer()
//line templates/auth.qtpl:60
WriteLogoutHTML(qb422016, can)
//line templates/auth.qtpl:60
qs422016 := string(qb422016.B)
//line templates/auth.qtpl:60
qt422016.ReleaseByteBuffer(qb422016)
//line templates/auth.qtpl:60
return qs422016
//line templates/auth.qtpl:60
}

View File

@ -1,159 +0,0 @@
// Code generated by qtc from "login.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
//line templates/login.qtpl:1
package templates
//line templates/login.qtpl:1
import "github.com/bouncepaw/mycorrhiza/user"
//line templates/login.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line templates/login.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line templates/login.qtpl:3
func StreamLoginHTML(qw422016 *qt422016.Writer) {
//line templates/login.qtpl:3
qw422016.N().S(`
<main>
<section>
`)
//line templates/login.qtpl:6
if user.AuthUsed {
//line templates/login.qtpl:6
qw422016.N().S(`
<h1>Login</h1>
<form method="post" action="/login-data" id="login-form" enctype="multipart/form-data">
<p>Use the data you were given by the administrator.</p>
<fieldset>
<legend>Username</legend>
<input type="text" required autofocus name="username" autocomplete="on">
</fieldset>
<fieldset>
<legend>Password</legend>
<input type="password" required name="password" autocomplete="on">
</fieldset>
<p>By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you.</p>
<input type="submit">
<a href="/">Cancel</a>
</form>
`)
//line templates/login.qtpl:22
} else {
//line templates/login.qtpl:22
qw422016.N().S(`
<p>Administrator of this wiki have not configured any authorization method. You can make edits anonymously.</p>
<p><a href="/"> Go home</a></p>
`)
//line templates/login.qtpl:25
}
//line templates/login.qtpl:25
qw422016.N().S(`
</section>
</main>
`)
//line templates/login.qtpl:28
}
//line templates/login.qtpl:28
func WriteLoginHTML(qq422016 qtio422016.Writer) {
//line templates/login.qtpl:28
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/login.qtpl:28
StreamLoginHTML(qw422016)
//line templates/login.qtpl:28
qt422016.ReleaseWriter(qw422016)
//line templates/login.qtpl:28
}
//line templates/login.qtpl:28
func LoginHTML() string {
//line templates/login.qtpl:28
qb422016 := qt422016.AcquireByteBuffer()
//line templates/login.qtpl:28
WriteLoginHTML(qb422016)
//line templates/login.qtpl:28
qs422016 := string(qb422016.B)
//line templates/login.qtpl:28
qt422016.ReleaseByteBuffer(qb422016)
//line templates/login.qtpl:28
return qs422016
//line templates/login.qtpl:28
}
//line templates/login.qtpl:30
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) {
//line templates/login.qtpl:30
qw422016.N().S(`
<main>
<section>
`)
//line templates/login.qtpl:33
switch err {
//line templates/login.qtpl:34
case "unknown username":
//line templates/login.qtpl:34
qw422016.N().S(`
<p class="error">Unknown username.</p>
`)
//line templates/login.qtpl:36
case "wrong password":
//line templates/login.qtpl:36
qw422016.N().S(`
<p class="error">Wrong password.</p>
`)
//line templates/login.qtpl:38
default:
//line templates/login.qtpl:38
qw422016.N().S(`
<p class="error">`)
//line templates/login.qtpl:39
qw422016.E().S(err)
//line templates/login.qtpl:39
qw422016.N().S(`</p>
`)
//line templates/login.qtpl:40
}
//line templates/login.qtpl:40
qw422016.N().S(`
<p><a href="/login"> Try again</a></p>
</section>
</main>
`)
//line templates/login.qtpl:44
}
//line templates/login.qtpl:44
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) {
//line templates/login.qtpl:44
qw422016 := qt422016.AcquireWriter(qq422016)
//line templates/login.qtpl:44
StreamLoginErrorHTML(qw422016, err)
//line templates/login.qtpl:44
qt422016.ReleaseWriter(qw422016)
//line templates/login.qtpl:44
}
//line templates/login.qtpl:44
func LoginErrorHTML(err string) string {
//line templates/login.qtpl:44
qb422016 := qt422016.AcquireByteBuffer()
//line templates/login.qtpl:44
WriteLoginErrorHTML(qb422016, err)
//line templates/login.qtpl:44
qs422016 := string(qb422016.B)
//line templates/login.qtpl:44
qt422016.ReleaseByteBuffer(qb422016)
//line templates/login.qtpl:44
return qs422016
//line templates/login.qtpl:44
}

View File

@ -10,6 +10,29 @@ import (
"github.com/bouncepaw/mycorrhiza/util"
)
func LogoutFromRequest(w http.ResponseWriter, rq *http.Request) {
cookieFromUser, err := rq.Cookie("mycorrhiza_token")
if err == nil {
http.SetCookie(w, cookie("token", "", time.Unix(0, 0)))
terminateSession(cookieFromUser.Value)
}
}
func (us *FixedUserStorage) userByToken(token string) *User {
if user, ok := us.Tokens[token]; ok {
return user
}
return nil
}
func FromRequest(rq *http.Request) *User {
cookie, err := rq.Cookie("mycorrhiza_token")
if err != nil {
return nil
}
return UserStorage.userByToken(cookie.Value)
}
func LoginDataHTTP(w http.ResponseWriter, rq *http.Request, username, password string) string {
w.Header().Set("Content-Type", "text/html;charset=utf-8")
if !HasUsername(username) {
@ -36,12 +59,20 @@ func LoginDataHTTP(w http.ResponseWriter, rq *http.Request, username, password s
func AddSession(username string) (string, error) {
token, err := util.RandomString(16)
if err == nil {
UserStorage.Tokens[token] = username
for _, user := range UserStorage.Users {
if user.Name == username {
UserStorage.Tokens[token] = user
}
}
log.Println("New token for", username, "is", token)
}
return token, err
}
func terminateSession(token string) {
delete(UserStorage.Tokens, token)
}
func HasUsername(username string) bool {
for _, user := range UserStorage.Users {
if user.Name == username {
@ -62,10 +93,10 @@ func CredentialsOK(username, password string) bool {
type FixedUserStorage struct {
Users []*User
Tokens map[string]string
Tokens map[string]*User
}
var UserStorage = FixedUserStorage{Tokens: make(map[string]string)}
var UserStorage = FixedUserStorage{Tokens: make(map[string]*User)}
func PopulateFixedUserStorage() {
contents, err := ioutil.ReadFile(util.FixedCredentialsPath)