diff options
Diffstat (limited to 'account')
-rw-r--r-- | account/addtoken.go | 56 | ||||
-rw-r--r-- | account/adduser.go | 43 | ||||
-rw-r--r-- | account/getid.go | 33 | ||||
-rw-r--r-- | account/login.go | 50 | ||||
-rw-r--r-- | account/register.go | 49 | ||||
-rw-r--r-- | account/user.go | 10 |
6 files changed, 241 insertions, 0 deletions
diff --git a/account/addtoken.go b/account/addtoken.go new file mode 100644 index 0000000..1c36ad8 --- /dev/null +++ b/account/addtoken.go @@ -0,0 +1,56 @@ +package account + +import ( + "log" + "time" + + "tildegit.org/andinus/perseus/password" + "tildegit.org/andinus/perseus/storage" +) + +// addToken will generate a random token, add it to database and +// return the token. +func (u *User) addToken(db *storage.DB) error { + u.Token = password.RandStr(64) + + // Set user id from username. + err := u.GetID(db) + if err != nil { + log.Printf("account/addtoken.go: %s\n", + "failed to get id from username") + return err + } + + // Acquire write lock on the database. + db.Mu.Lock() + defer db.Mu.Unlock() + + // Start the transaction + tx, err := db.Conn.Begin() + defer tx.Rollback() + if err != nil { + log.Printf("account/addtoken.go: %s\n", + "failed to begin transaction") + return err + } + + stmt, err := db.Conn.Prepare(` +INSERT INTO access(id, token, genTime) values(?, ?, ?)`) + if err != nil { + log.Printf("account/addtoken.go: %s\n", + "failed to prepare statement") + return err + } + defer stmt.Close() + + _, err = stmt.Exec(u.ID, u.Token, time.Now().UTC()) + if err != nil { + log.Printf("account/addtoken.go: %s\n", + "failed to execute statement") + return err + } + + tx.Commit() + return err + +} diff --git a/account/adduser.go b/account/adduser.go new file mode 100644 index 0000000..8a8734f --- /dev/null +++ b/account/adduser.go @@ -0,0 +1,43 @@ +package account + +import ( + "log" + "time" + + "tildegit.org/andinus/perseus/storage" +) + +// addUser adds the user to record. +func (u *User) addUser(db *storage.DB) error { + // Acquire write lock on the database. + db.Mu.Lock() + defer db.Mu.Unlock() + + // Start the transaction + tx, err := db.Conn.Begin() + defer tx.Rollback() + if err != nil { + log.Printf("account/adduser.go: %s\n", + "failed to begin transaction") + return err + } + + stmt, err := db.Conn.Prepare(` +INSERT INTO accounts(id, username, hash, regTime) values(?, ?, ?, ?)`) + if err != nil { + log.Printf("account/adduser.go: %s\n", + "failed to prepare statement") + return err + } + defer stmt.Close() + + _, err = stmt.Exec(u.ID, u.Username, u.Hash, time.Now().UTC()) + if err != nil { + log.Printf("account/adduser.go: %s\n", + "failed to execute statement") + return err + } + + tx.Commit() + return err +} diff --git a/account/getid.go b/account/getid.go new file mode 100644 index 0000000..4f6da69 --- /dev/null +++ b/account/getid.go @@ -0,0 +1,33 @@ +package account + +import ( + "log" + + "tildegit.org/andinus/perseus/storage" +) + +// GetID returns id from username. +func (u *User) GetID(db *storage.DB) error { + // Acquire read lock on database. + db.Mu.RLock() + defer db.Mu.RUnlock() + + // Get password for this user from the database. + stmt, err := db.Conn.Prepare("SELECT id FROM accounts WHERE username = ?") + if err != nil { + log.Printf("account/getid.go: %s\n", + "failed to prepare statement") + return err + } + defer stmt.Close() + + var id string + err = stmt.QueryRow(u.Username).Scan(&id) + if err != nil { + log.Printf("account/getid.go: %s\n", + "query failed") + } + u.ID = id + + return err +} diff --git a/account/login.go b/account/login.go new file mode 100644 index 0000000..c81fcbd --- /dev/null +++ b/account/login.go @@ -0,0 +1,50 @@ +package account + +import ( + "log" + + "tildegit.org/andinus/perseus/password" + "tildegit.org/andinus/perseus/storage" +) + +// Login takes in login details and returns an error. If error doesn't +// equal nil then consider login failed. It will also set the u.Token +// field. +func (u *User) Login(db *storage.DB) error { + // Acquire read lock on the database. + db.Mu.RLock() + + // Get password for this user from the database. + stmt, err := db.Conn.Prepare("SELECT hash FROM accounts WHERE username = ?") + if err != nil { + log.Printf("account/login.go: %s\n", + "failed to prepare statement") + return err + } + defer stmt.Close() + + var hash string + err = stmt.QueryRow(u.Username).Scan(&hash) + if err != nil { + log.Printf("account/login.go: %s\n", + "query failed") + return err + } + u.Hash = hash + + // Check user's password. + err = password.Check(u.Password, u.Hash) + if err != nil { + log.Printf("account/login.go: %s%s\n", + "user login failed, username: ", u.Username) + return err + } + db.Mu.RUnlock() + + err = u.addToken(db) + if err != nil { + log.Printf("account/login.go: %s\n", + "addtoken failed") + } + return err +} diff --git a/account/register.go b/account/register.go new file mode 100644 index 0000000..e008370 --- /dev/null +++ b/account/register.go @@ -0,0 +1,49 @@ +package account + +import ( + "errors" + "log" + "regexp" + "strings" + + "tildegit.org/andinus/perseus/password" + "tildegit.org/andinus/perseus/storage" +) + +// Register takes in registration details and returns an error. If +// error doesn't equal nil then the registration was unsuccessful. +func (u User) Register(db *storage.DB) error { + var err error + u.ID = password.RandStr(64) + u.Username = strings.ToLower(u.Username) + + // Validate username. It must be alphanumeric and less than + // 128 characters. + re := regexp.MustCompile("^[a-zA-Z0-9]*$") + if !re.MatchString(u.Username) { + return errors.New("account/register.go: invalid username") + } + if len(u.Username) > 128 { + return errors.New("account/register.go: username too long") + } + + // Validate password + if len(u.Password) < 8 { + return errors.New("account/register.go: password too short") + } + + u.Hash, err = password.Hash(u.Password) + if err != nil { + log.Printf("account/register.go: %s\n", + "password.Hash func failed") + return err + } + + err = u.addUser(db) + if err != nil { + log.Printf("account/register.go: %s\n", + "addUser func failed") + } + return err + +} diff --git a/account/user.go b/account/user.go new file mode 100644 index 0000000..769e8fc --- /dev/null +++ b/account/user.go @@ -0,0 +1,10 @@ +package account + +// User holds information about the user. +type User struct { + ID string + Username string + Password string + Hash string + Token string +} |