Add login handler
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Andinus 2020-03-27 22:43:11 +05:30
parent 79b376a659
commit b0b83af1c4
Signed by: andinus
GPG Key ID: B67D55D482A799FD
6 changed files with 145 additions and 12 deletions

View File

@ -9,13 +9,13 @@ import (
// Login takes in login details and returns an error. If error doesn't
// equal nil then consider login failed.
func Login(db *sqlite3.DB, loginInfo map[string]string) error {
func Login(db *sqlite3.DB, uInfo map[string]string) error {
// Acquire read lock on the database.
db.Mu.RLock()
defer db.Mu.RUnlock()
u := user.User{}
u.SetUsername(loginInfo["username"])
u.SetUsername(uInfo["username"])
// Get password for this user from the database.
stmt, err := db.Conn.Prepare("SELECT password FROM users WHERE username = ?")
@ -36,7 +36,7 @@ func Login(db *sqlite3.DB, loginInfo map[string]string) error {
u.SetPassword(pass)
// Check user's password.
err = checkPass(loginInfo["password"], u.Password())
err = checkPass(uInfo["password"], u.Password())
if err != nil {
log.Printf("auth/login.go: %s%s\n",
"user login failed, username: ", u.Username())

View File

@ -37,9 +37,9 @@ func AddToken(db *sqlite3.DB, uInfo map[string]string) (token string, err error)
}
stmt, err := db.Conn.Prepare(`
INSERT INTO access(id, username, genTime) values(?, ?, ?)`)
INSERT INTO access(id, token, genTime) values(?, ?, ?)`)
if err != nil {
log.Printf("auth/tokenr.go: %s\n",
log.Printf("auth/token.go: %s\n",
"failed to prepare statement")
return
}

View File

@ -30,6 +30,9 @@ func main() {
http.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) {
web.HandleRegister(w, r, db)
})
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
web.HandleLogin(w, r, db)
})
log.Printf("main/main.go: listening on port %s...", envPort)
log.Fatal(srv.ListenAndServe())

83
handler/web/login.go Normal file
View File

@ -0,0 +1,83 @@
package web
import (
"fmt"
"html/template"
"log"
"net/http"
"time"
"tildegit.org/andinus/perseus/auth"
"tildegit.org/andinus/perseus/auth/token"
"tildegit.org/andinus/perseus/core"
"tildegit.org/andinus/perseus/storage/sqlite3"
)
// HandleLogin handles /login pages.
func HandleLogin(w http.ResponseWriter, r *http.Request, db *sqlite3.DB) {
p := Page{Version: core.Version()}
error := []string{}
success := []string{}
switch r.Method {
case http.MethodGet:
t, _ := template.ParseFiles("web/login.html")
t.Execute(w, p)
case http.MethodPost:
if err := r.ParseForm(); err != nil {
log.Printf("web/login.go: 400 Bad Request :: %s", err.Error())
http.Error(w, "400 Bad Request", http.StatusBadRequest)
return
}
// Get form values
uInfo := make(map[string]string)
uInfo["username"] = r.FormValue("username")
uInfo["password"] = r.FormValue("password")
// Perform authentication
err := auth.Login(db, uInfo)
if err != nil {
log.Printf("web/login.go: %s :: %s :: %s",
"login failed",
uInfo["username"],
err.Error())
error = append(error,
fmt.Sprintf("Login failed"))
p.Error = error
} else {
success = append(success,
fmt.Sprintf("Login successful"))
p.Success = success
// Set token if login was successful.
token, err := token.AddToken(db, uInfo)
if err != nil {
log.Printf("web/login.go: %s :: %s :: %s",
"token generation failed",
uInfo["username"],
err.Error())
error = append(error,
fmt.Sprintf("Token generation failed"))
}
// If token was generated then ask browser to
// set it as cookie.
expiration := time.Now().Add(1 * 24 * time.Hour)
cookie := http.Cookie{Name: "token", Value: token, Expires: expiration}
http.SetCookie(w, &cookie)
}
t, _ := template.ParseFiles("web/login.html")
t.Execute(w, p)
default:
w.WriteHeader(http.StatusMethodNotAllowed)
log.Printf("web/login.go: %v not allowed on %v", r.Method, r.URL)
}
}

52
web/login.html Normal file
View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Login &middot; Perseus</title>
<link rel="stylesheet" href="https://andinus.nand.sh/static/style.css">
<link rel="stylesheet" href="https://andinus.nand.sh/static/perseus/style.css">
<link rel="icon" href="https://andinus.nand.sh/static/perseus/favicon.png" type="image/png">
</head>
<body>
<div id="content">
<h1 class="title">Perseus</h1>{{ if .SafeList }}
<ul>{{ range .SafeList }}
<li>{{ . }}</li>{{ end }}
</ul>{{end}} {{ if .List }}
<ul>{{ range .List }}
<li>{{ . }}</li>{{ end }}
</ul>{{end}} {{ if .Error }}
<ul class="error">{{ range .Error }}
<li>{{ . }}</li>{{ end }}
</ul>{{end}} {{ if .Success }}
<ul class="success">{{ range .Success }}
<li>{{ . }}</li>{{ end }}
</ul>{{end}} {{ if .Notice }}
<ul class="notice">{{ range .Notice }}
<li>{{ . }}</li>{{ end }}
</ul>{{end}}
<form action="./login" method="post">
<h4>Username</h4>
<input type="text" name="username" required>
<h4>Password</h4>
<input type="password" name="password" required>
<input type="submit" name="submit" value="Login!">
</form>
</div>
<div id="postamble" class="status">
<p class="postamble">
<a href="https://andinus.nand.sh/">Andinus</a>
&nbsp;/&nbsp;
<a href="https://andinus.nand.sh/perseus">Perseus</a>
<span style="float:right">
Perseus {{ .Version }}
&nbsp;/&nbsp;
<a href="https://tildegit.org/andinus/perseus">
Source Code
</a>
</span>
</p>
</div>
</body>
</html>

View File

@ -10,12 +10,7 @@
</head>
<body>
<div id="content">
<h1 class="title">Perseus</h1>
<p>
Perseus is a simple link aggregation and discussion program.
It is written in Go &amp; uses sqlite3 for storage.
</p>
<hr>{{ if .SafeList }}
<h1 class="title">Perseus</h1>{{ if .SafeList }}
<ul>{{ range .SafeList }}
<li>{{ . }}</li>{{ end }}
</ul>{{end}} {{ if .List }}
@ -36,7 +31,7 @@
<input type="text" name="username" required>
<h4>Password</h4>
<input type="password" name="password" required>
<input type="submit" name="submit" value="Go!">
<input type="submit" name="submit" value="Register!">
</form>
</div>
<div id="postamble" class="status">