mirror of
https://github.com/ditatompel/xmr-remote-nodes.git
synced 2024-12-23 20:19:28 +00:00
169 lines
4 KiB
Go
169 lines
4 KiB
Go
package repo
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/ditatompel/xmr-nodes/internal/database"
|
|
|
|
"github.com/alexedwards/argon2id"
|
|
)
|
|
|
|
type Admin struct {
|
|
Id int `db:"id"`
|
|
Username string `db:"username"`
|
|
Password string `db:"password"`
|
|
LastactiveTs int64 `db:"lastactive_ts"`
|
|
CreatedTs int64 `db:"created_ts"`
|
|
}
|
|
|
|
type AdminRepo struct {
|
|
db *database.DB
|
|
}
|
|
|
|
type AdminRepository interface {
|
|
CreateAdmin(*Admin) (*Admin, error)
|
|
Login(username string, password string) (*Admin, error)
|
|
}
|
|
|
|
func NewAdminRepo(db *database.DB) AdminRepository {
|
|
return &AdminRepo{db}
|
|
}
|
|
|
|
func (repo *AdminRepo) CreateAdmin(admin *Admin) (*Admin, error) {
|
|
if !validUsername(admin.Username) {
|
|
return nil, errors.New("username is not valid, must be at least 4 characters long and contain only lowercase letters and numbers")
|
|
}
|
|
if !strongPassword(admin.Password) {
|
|
return nil, errors.New("password is not strong enough, must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number and one special character")
|
|
}
|
|
hash, err := setPassword(admin.Password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
admin.Password = hash
|
|
|
|
admin.CreatedTs = time.Now().Unix()
|
|
|
|
if repo.isUsernameExists(admin.Username) {
|
|
return nil, errors.New("username already exists")
|
|
}
|
|
|
|
query := `INSERT INTO tbl_admin (username, password, created_ts) VALUES (?, ?, ?)`
|
|
_, err = repo.db.Exec(query, admin.Username, admin.Password, admin.CreatedTs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return admin, nil
|
|
}
|
|
|
|
func (repo *AdminRepo) Login(username, password string) (*Admin, error) {
|
|
query := `SELECT id, username, password FROM tbl_admin WHERE username = ? LIMIT 1`
|
|
row, err := repo.db.Query(query, username)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return nil, err
|
|
}
|
|
defer row.Close()
|
|
|
|
admin := Admin{}
|
|
if row.Next() {
|
|
err = row.Scan(&admin.Id, &admin.Username, &admin.Password)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return nil, err
|
|
}
|
|
} else {
|
|
return nil, errors.New("Invalid username or password")
|
|
}
|
|
|
|
match, err := checkPassword(admin.Password, password)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return nil, err
|
|
}
|
|
if !match {
|
|
return nil, errors.New("Invalid username or password")
|
|
}
|
|
|
|
update := `UPDATE tbl_admin SET lastactive_ts = ? WHERE id = ?`
|
|
_, err = repo.db.Exec(update, time.Now().Unix(), admin.Id)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return nil, err
|
|
}
|
|
|
|
return &admin, nil
|
|
}
|
|
|
|
func (repo *AdminRepo) isUsernameExists(username string) bool {
|
|
query := `SELECT id FROM tbl_admin WHERE username = ? LIMIT 1`
|
|
row, err := repo.db.Query(query, username)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
defer row.Close()
|
|
return row.Next()
|
|
}
|
|
|
|
func setPassword(password string) (string, error) {
|
|
hash, err := argon2id.CreateHash(password, argon2id.DefaultParams)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return hash, nil
|
|
}
|
|
|
|
func checkPassword(hash, password string) (bool, error) {
|
|
match, err := argon2id.ComparePasswordAndHash(password, hash)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return match, nil
|
|
}
|
|
|
|
func strongPassword(password string) bool {
|
|
if len(password) < 8 {
|
|
return false
|
|
}
|
|
if !strings.ContainsAny(password, "0123456789") {
|
|
return false
|
|
}
|
|
if !strings.ContainsAny(password, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
|
|
return false
|
|
}
|
|
if !strings.ContainsAny(password, "abcdefghijklmnopqrstuvwxyz") {
|
|
return false
|
|
}
|
|
if !strings.ContainsAny(password, "!@#$%^&*()_+|~-=`{}[]:;<>?,./") {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// No special character and unicode for username
|
|
func validUsername(username string) bool {
|
|
if len(username) < 5 || len(username) > 20 {
|
|
return false
|
|
}
|
|
|
|
// reject witespace, tabs, newlines, and other special characters
|
|
if strings.ContainsAny(username, " \t\n") {
|
|
return false
|
|
}
|
|
// reject unicode
|
|
if strings.ContainsAny(username, "^\x00-\x7F") {
|
|
return false
|
|
}
|
|
// reject special characters
|
|
if strings.ContainsAny(username, "!@#$%^&*()_+|~-=`{}[]:;<>?,./ ") { // note last blank space
|
|
return false
|
|
}
|
|
|
|
if !strings.ContainsAny(username, "abcdefghijklmnopqrstuvwxyz0123456789") {
|
|
return false
|
|
}
|
|
return true
|
|
}
|