summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndinus <andinus@nand.sh>2020-03-26 23:29:48 +0530
committerAndinus <andinus@nand.sh>2020-03-26 23:29:48 +0530
commit7a3e2f9552a063ac99f87e47b38e3fd14919fdf0 (patch)
tree878f2714107bdfc5231a7ef7f06a1f02d4940838
parent288d04779e881cb4738ea469e4c93b841a5b42e2 (diff)
downloadperseus-7a3e2f9552a063ac99f87e47b38e3fd14919fdf0.tar.gz
Add auth and user package
-rw-r--r--auth/genid.go14
-rw-r--r--auth/hashpass.go13
-rw-r--r--auth/register.go81
-rw-r--r--go.mod5
-rw-r--r--go.sum7
-rw-r--r--storage/sqlite3/db.go13
-rw-r--r--storage/sqlite3/init.go8
-rw-r--r--user/user.go38
8 files changed, 170 insertions, 9 deletions
diff --git a/auth/genid.go b/auth/genid.go
new file mode 100644
index 0000000..fea7ac9
--- /dev/null
+++ b/auth/genid.go
@@ -0,0 +1,14 @@
+package auth
+
+import (
+	"crypto/rand"
+	"encoding/base64"
+)
+
+// genID generates a random id string of length n. Don't forget to
+// seed the random number generator otherwise it won't be random.
+func genID(n int) string {
+	b := make([]byte, n/2)
+	rand.Read(b)
+	return base64.StdEncoding.EncodeToString(b)
+}
diff --git a/auth/hashpass.go b/auth/hashpass.go
new file mode 100644
index 0000000..4e5041a
--- /dev/null
+++ b/auth/hashpass.go
@@ -0,0 +1,13 @@
+package auth
+
+import (
+	"golang.org/x/crypto/bcrypt"
+)
+
+// hashPass takes a string as input and returns the hash of the
+// password.
+func hashPass(password string) (string, error) {
+	// 10 is the default cost.
+	bytes, err := bcrypt.GenerateFromPassword([]byte(password), 10)
+	return string(bytes), err
+}
diff --git a/auth/register.go b/auth/register.go
new file mode 100644
index 0000000..c50f3f4
--- /dev/null
+++ b/auth/register.go
@@ -0,0 +1,81 @@
+package auth
+
+import (
+	"log"
+	"strings"
+	"time"
+
+	"tildegit.org/andinus/perseus/storage/sqlite3"
+	"tildegit.org/andinus/perseus/user"
+)
+
+// Register takes in registration details and returns an error. If
+// error doesn't equal nil then the registration was unsucessful.
+// regInfo should have username, password & ip.
+func Register(db *sqlite3.DB, regInfo map[string]string) error {
+	u := user.User{}
+	u.SetID(genID(64))
+	u.SetUsername(strings.ToLower(regInfo["username"]))
+
+	pass, err := hashPass(regInfo["password"])
+	if err != nil {
+		log.Printf("auth/register.go: %s\n",
+			"hashPass func failed")
+		return err
+	}
+	u.SetPassword(pass)
+
+	// Acquire write lock on the database.
+	db.Mu.Lock()
+	defer db.Mu.Unlock()
+
+	err = insertRecords(db, u, regInfo)
+	return err
+}
+
+func insertRecords(db *sqlite3.DB, u user.User, regInfo map[string]string) error {
+	// Start the transaction
+	tx, err := db.Conn.Begin()
+	if err != nil {
+		log.Printf("auth/register.go: %s\n",
+			"Failed to begin transaction")
+		return err
+	}
+
+	// Insert the record into registration table
+	regStmt, err := db.Conn.Prepare(`
+INSERT INTO registration(id, username, reg_time, reg_ip) values(?, ?, ?, ?)`)
+	if err != nil {
+		log.Printf("auth/register.go: %s\n",
+			"Failed to prepare statement")
+		return err
+	}
+	defer regStmt.Close()
+
+	_, err = regStmt.Exec(u.ID(), u.Username(), time.Now().UTC(), regInfo["ip"])
+	if err != nil {
+		log.Printf("auth/register.go: %s\n",
+			"Failed to execute statement")
+		return err
+	}
+
+	// Insert the record into users table
+	usrStmt, err := db.Conn.Prepare(`
+INSERT INTO users(id, username, password) values(?, ?, ?)`)
+	if err != nil {
+		log.Printf("auth/register.go: %s\n",
+			"Failed to prepare statement")
+		return err
+	}
+	defer usrStmt.Close()
+
+	_, err = usrStmt.Exec(u.ID(), u.Username(), u.Password())
+	if err != nil {
+		log.Printf("auth/register.go: %s\n",
+			"Failed to execute statement")
+		return err
+	}
+
+	tx.Commit()
+	return err
+}
diff --git a/go.mod b/go.mod
index 8472b8b..1d6a947 100644
--- a/go.mod
+++ b/go.mod
@@ -2,4 +2,7 @@ module tildegit.org/andinus/perseus
 
 go 1.13
 
-require github.com/mattn/go-sqlite3 v2.0.3+incompatible
+require (
+	github.com/mattn/go-sqlite3 v2.0.3+incompatible
+	golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59
+)
diff --git a/go.sum b/go.sum
index d674429..d243940 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,9 @@
 github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
+golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
diff --git a/storage/sqlite3/db.go b/storage/sqlite3/db.go
new file mode 100644
index 0000000..e949bba
--- /dev/null
+++ b/storage/sqlite3/db.go
@@ -0,0 +1,13 @@
+package sqlite3
+
+import (
+	"database/sql"
+	"sync"
+)
+
+// DB holds the database connection, mutex & path.
+type DB struct {
+	Path string
+	Mu   *sync.RWMutex
+	Conn *sql.DB
+}
diff --git a/storage/sqlite3/init.go b/storage/sqlite3/init.go
index cb573a2..01ffb9e 100644
--- a/storage/sqlite3/init.go
+++ b/storage/sqlite3/init.go
@@ -4,18 +4,10 @@ import (
 	"database/sql"
 	"log"
 	"os"
-	"sync"
 
 	_ "github.com/mattn/go-sqlite3"
 )
 
-// DB holds the database connection, mutex & path.
-type DB struct {
-	Path string
-	Mu   *sync.RWMutex
-	Conn *sql.DB
-}
-
 // initErr will log the error and close the database connection if
 // necessary.
 func initErr(db *DB, err error) {
diff --git a/user/user.go b/user/user.go
new file mode 100644
index 0000000..a15d625
--- /dev/null
+++ b/user/user.go
@@ -0,0 +1,38 @@
+package user
+
+// User holds information about the user.
+type User struct {
+	id       string
+	username string
+	password string
+}
+
+// SetUsername will set the username.
+func (u *User) SetUsername(username string) {
+	u.username = username
+}
+
+// Username returns the username.
+func (u *User) Username() string {
+	return u.username
+}
+
+// SetPassword will set the password.
+func (u *User) SetPassword(password string) {
+	u.password = password
+}
+
+// Password returns the password.
+func (u *User) Password() string {
+	return u.password
+}
+
+// SetID will set the id.
+func (u *User) SetID(id string) {
+	u.id = id
+}
+
+// ID returns the id.
+func (u *User) ID() string {
+	return u.id
+}