summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndinus <andinus@nand.sh>2020-03-27 22:43:11 +0530
committerAndinus <andinus@nand.sh>2020-03-27 22:43:11 +0530
commitb0b83af1c45c2d5ee587dc96847e25c95a3d50b0 (patch)
tree09aeffb9ee5538a002d76457d2cfdc50257c67f2
parent79b376a659a1d58db01f60ad049110363fbf15fc (diff)
downloadperseus-b0b83af1c45c2d5ee587dc96847e25c95a3d50b0.tar.gz
Add login handler
-rw-r--r--auth/login.go6
-rw-r--r--auth/token/add.go4
-rw-r--r--cmd/perseus/main.go3
-rw-r--r--handler/web/login.go83
-rw-r--r--web/login.html52
-rw-r--r--web/register.html9
6 files changed, 145 insertions, 12 deletions
diff --git a/auth/login.go b/auth/login.go
index 66d1b21..99e74ba 100644
--- a/auth/login.go
+++ b/auth/login.go
@@ -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())
diff --git a/auth/token/add.go b/auth/token/add.go
index c7f632c..eadc6dc 100644
--- a/auth/token/add.go
+++ b/auth/token/add.go
@@ -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
 	}
diff --git a/cmd/perseus/main.go b/cmd/perseus/main.go
index b94793e..6abd3a4 100644
--- a/cmd/perseus/main.go
+++ b/cmd/perseus/main.go
@@ -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())
diff --git a/handler/web/login.go b/handler/web/login.go
new file mode 100644
index 0000000..0c70b56
--- /dev/null
+++ b/handler/web/login.go
@@ -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)
+	}
+
+}
diff --git a/web/login.html b/web/login.html
new file mode 100644
index 0000000..cd0d6a7
--- /dev/null
+++ b/web/login.html
@@ -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>
diff --git a/web/register.html b/web/register.html
index e71979e..c351ae1 100644
--- a/web/register.html
+++ b/web/register.html
@@ -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">