From 7a3e2f9552a063ac99f87e47b38e3fd14919fdf0 Mon Sep 17 00:00:00 2001 From: Andinus Date: Thu, 26 Mar 2020 23:29:48 +0530 Subject: Add auth and user package --- auth/genid.go | 14 +++++++++ auth/hashpass.go | 13 ++++++++ auth/register.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 5 ++- go.sum | 7 +++++ storage/sqlite3/db.go | 13 ++++++++ storage/sqlite3/init.go | 8 ----- user/user.go | 38 +++++++++++++++++++++++ 8 files changed, 170 insertions(+), 9 deletions(-) create mode 100644 auth/genid.go create mode 100644 auth/hashpass.go create mode 100644 auth/register.go create mode 100644 storage/sqlite3/db.go create mode 100644 user/user.go 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 +} -- cgit 1.4.1-2-gfad0