Author: Adam <git@apiote.tk>
log out
db/db.go | 19 ++++++++++++++++ front/capnproto.go | 5 ++++ front/html.go | 5 ++++ front/renderer.go | 1 libamuse/account.go | 26 +++++++++++++++++++++++ libamuse/login.go | 21 ++++++++++++++++++ router.go | 47 ++++++++++++++++++++++++++++++++++++++++++ templates/loggedout.html | 29 +++++++++++++++++++++++++
diff --git a/db/db.go b/db/db.go index 22a9ec1f6e0304f4a810ec57844f4097b4bad525..56174347af8520d35560cd2937cb5534ee90c5b1 100644 --- a/db/db.go +++ b/db/db.go @@ -241,6 +241,25 @@ return nil } +func RemoveSession(username, token string) error { + db, err := sql.Open("sqlite3", utils.DataHome+"/amuse.db") + if err != nil { + fmt.Fprintf(os.Stderr, "DB open err\n") + return err + } + defer db.Close() + + rows, err := db.Exec(`delete from sessions where id = ? and username = ?`, token, username) + affected, _ := rows.RowsAffected() + if affected == 0 { + return EmptyError{ + message: "No session " + token + " for user " + username, + } + } + + return err +} + func GetItemExperiences(username, itemId string, itemType datastructure.ItemType) (map[string][]time.Time, error) { times := map[string][]time.Time{} user, err := GetUser(username) diff --git a/front/capnproto.go b/front/capnproto.go index 415ecbf730ac465a0c72e7c14d82a450eb7bc80e..d722f33eac2fc1462da7af45894dc824575f6699 100644 --- a/front/capnproto.go +++ b/front/capnproto.go @@ -56,6 +56,11 @@ // todo throw Wrong Accept return TODO("implement CapnprotoRenderer.RenderLogin").(string) } +func (CapnprotoRenderer) RenderLoggedOut(languages []language.Tag) string { + // todo throw Wrong Accept + return TODO("implement CapnprotoRenderer.RenderLogin").(string) +} + func (CapnprotoRenderer) RenderSignup(languages []language.Tag, err error, otp *otp.Key, sfaEnabled bool, username, qr string) string { // todo throw Wrong Accept return TODO("implement CapnprotoRenderer.RenderSignup").(string) diff --git a/front/html.go b/front/html.go index 4b7cf47308ddc67eacd01e9929435272c3bd04a5..6a97673d243210f588454ba3391f2ee228c738bc 100644 --- a/front/html.go +++ b/front/html.go @@ -140,6 +140,11 @@ data.State.Error = authError return render(languages, data, "login") } +func (HtmlRenderer) RenderLoggedOut(languages []language.Tag) string { + data := RenderData{} + return render(languages, data, "loggedout") +} + func (HtmlRenderer) RenderSignup(languages []language.Tag, authError error, key *otp.Key, sfaEnabled bool, username, qr string) string { secret := struct { Secret string diff --git a/front/renderer.go b/front/renderer.go index 92917be7e499e9a6b7326f3ad6063c76b8377491..df1c27130a500d7744ebdd5daa4a9b1161b7c02a 100644 --- a/front/renderer.go +++ b/front/renderer.go @@ -30,6 +30,7 @@ RenderBookSerie(wikidata.BookSerie, []language.Tag) string RenderAbout([]language.Tag) string RenderErrorPage(int, []language.Tag) string RenderLogin([]language.Tag, error, string) string + RenderLoggedOut([]language.Tag) string RenderSignup([]language.Tag, error, *otp.Key, bool, string, string) string RenderSignedup([]language.Tag, []string) string RenderWatchlist(datastructure.Watchlist, []language.Tag) string diff --git a/libamuse/account.go b/libamuse/account.go index 03f52cefa49814df616661913dceacd14757fc7e..bca7dc747063ebecbb74cb9d08878a2262e7ad44 100644 --- a/libamuse/account.go +++ b/libamuse/account.go @@ -210,3 +210,29 @@ } return err } + +func removeSession(args ...interface{}) (interface{}, error) { + data := args[0].(*RequestData) + var token string + if data.id == "0" { + token = data.auth.Token + } else { + token = data.id + } + username := data.username + err := db.RemoveSession(username, token) + return gott.Tuple(args), err +} + +func SessionDelete(username string, auth accounts.Authentication, session, languages, mimetype string) error { + auth.Necessary = true + _, err := gott. + NewResult(gott.Tuple{&RequestData{id: session, language: languages, mimetype: mimetype, auth: auth, username: username}, &Result{}}). + Bind(parseLanguage). + Bind(verifyToken). + Bind(verifyUser). + Bind(removeSession). + Finish() + + return err +} diff --git a/libamuse/login.go b/libamuse/login.go index 222242f4441c45a587e6ce0b3abab81ab993bda6..b91dbee3f273376b5cb48319c4685a5654ce6019 100644 --- a/libamuse/login.go +++ b/libamuse/login.go @@ -35,3 +35,24 @@ func DoLogin(username, password, sfa string, remember bool) (string, error) { return accounts.Login(username, password, sfa, remember) } + +func renderLoggedOut(args ...interface{}) interface{} { + result := args[1].(*Result) + result.page = result.renderer.RenderLoggedOut(result.languages) + return gott.Tuple(args) +} + +func ShowLoggedOut(languages, mimetype string) (string, error) { + r, err := gott. + NewResult(gott.Tuple{&RequestData{language: languages, mimetype: mimetype}, &Result{}}). + Bind(parseLanguage). + Bind(createRenderer). + Map(renderLoggedOut). + Finish() + + if err != nil { + return "", err + } else { + return r.(gott.Tuple)[1].(*Result).page, nil + } +} diff --git a/router.go b/router.go index 29955d0204f2aadcb6af8e609fd151e5f61ce8b9..6c68a99f2635d2b11fde5c0cc3289e980c17d26e 100644 --- a/router.go +++ b/router.go @@ -2,6 +2,7 @@ package main import ( "notabug.org/apiote/amuse/accounts" + "notabug.org/apiote/amuse/db" "notabug.org/apiote/amuse/front" "notabug.org/apiote/amuse/libamuse" "notabug.org/apiote/amuse/network" @@ -431,6 +432,36 @@ } } } +func sessionDelete(w http.ResponseWriter, r *http.Request, username string, auth accounts.Authentication, session, acceptLanguages, mimetype string) { + err := libamuse.SessionDelete(username, auth, session, acceptLanguages, mimetype) + if err != nil { + render("", err, w, acceptLanguages, mimetype) + } else { + w.Header().Add("Location", "/loggedout") + w.WriteHeader(303) + } +} + +func userSessions(w http.ResponseWriter, r *http.Request, username string, auth accounts.Authentication, acceptLanguages, mimetype string) { + path := strings.Split(r.URL.Path[1:], "/") + if len(path) == 3 { + // todo show sessions + renderError(404, w, nil, acceptLanguages, mimetype) + } else if len(path) == 4 { + if r.Method == "POST" { + r.ParseForm() + method := r.PostForm.Get("method") + session := path[3] + if method == "DELETE" { + sessionDelete(w, r, username, auth, session, acceptLanguages, mimetype) + } + } else if r.Method == "DELETE" { + session := path[3] + sessionDelete(w, r, username, auth, session, acceptLanguages, mimetype) + } + } +} + func userRouter(w http.ResponseWriter, r *http.Request) { path := strings.Split(r.URL.Path[1:], "/") acceptLanguages := r.Header.Get("Accept-Language") @@ -456,12 +487,25 @@ case "tvqueue": userTvQueue(w, r, username, auth, acceptLanguages, mimetype) case "experiences": userExperiences(w, r, username, auth, acceptLanguages, mimetype) + case "sessions": + userSessions(w, r, username, auth, acceptLanguages, mimetype) default: renderError(404, w, nil, acceptLanguages, mimetype) } } } +func loggedout(w http.ResponseWriter, r *http.Request) { + acceptLanguages := r.Header.Get("Accept-Language") + mimetype := strings.Split(r.Header.Get("Accept"), ",")[0] + + defer recovery(acceptLanguages, mimetype, w) + + loggedout, err := libamuse.ShowLoggedOut(acceptLanguages, mimetype) + setAuthCookie(false, "", w) + render(loggedout, err, w, acceptLanguages, mimetype) +} + func route(port int) { portStr := fmt.Sprintf(":%d", port) @@ -479,6 +523,7 @@ http.HandleFunc("/login", login) http.HandleFunc("/signup", signup) http.HandleFunc("/signedup", signedup) + http.HandleFunc("/loggedout", loggedout) fmt.Printf("running on %s\n", portStr) e := http.ListenAndServe(portStr, nil) if e != nil { @@ -537,6 +582,8 @@ if _, ok := e.(front.NoSuchRendererError); ok { renderError(406, w, e, languages, mimetype) } else if httpError, ok := e.(network.HttpError); ok { renderError(httpError.Status, w, httpError, languages, mimetype) + } else if _, ok := e.(db.EmptyError); ok { + renderError(410, w, e, languages, mimetype) } else if authError, ok := e.(accounts.AuthError); ok { if authError.Err.Error() == "401" { w.Header().Add("WWW-Authenticate", "Bearer") diff --git a/templates/loggedout.html b/templates/loggedout.html new file mode 100644 index 0000000000000000000000000000000000000000..082441b48a14ef9354e917d1c15d57f9cd4b1456 --- /dev/null +++ b/templates/loggedout.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>a·muse</title> + <link rel="stylesheet" href="/static/style/style.css" /> + <link rel="icon" type="image/svg+xml" href="/static/img/logo.svg"> + <link rel="apple-touch-icon" type="image/svg+xml" href="/static/img/logo.svg"> + </head> + <body class="flex flex-column height-all"> + <header class="w12 padding-bottom-_25 flex flex-row flex-justify-space flex-align-centre flex-content"> + <a href="/" class="decoration-none"> + <h1 class="inline valign-mid text sans margin-lr-1">a·muse</h1> + </a> + </header> + <main class="margin-lr-1 flex-fill"> + <div class="flex flex-column height-fill flex-centre"> + <div class="w12 flex flex-centre border-box left"> + <div> + <div class="sans italic centre">„Mischief managed”</div> + <hr/> + <p class="sans">See You next time…</p> + </div> + </div> + </div> + </main> + </body> +</html>