updates
This commit is contained in:
parent
4db3ca30a9
commit
d6eca5086f
|
@ -1,13 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"gitto.work/shortcut/scsusers"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"flag"
|
||||
"os"
|
||||
"fmt"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.teamworkapps.com/shortcut/scsusers"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var email string
|
||||
|
@ -27,14 +28,9 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
schema:=`CREATE TABLE test_auth (
|
||||
username text NOT NULL ,
|
||||
password text NOT NULL,
|
||||
email text NOT NULL unique,
|
||||
recovery text NOT NULL DEFAULT '',
|
||||
recoverytime timestamp null,
|
||||
registration_date timestamp not null,
|
||||
registration_ip text not null,
|
||||
lastseen timestamp );`
|
||||
id int primary key autoincrement,
|
||||
username text NOT NULL unique key
|
||||
password text NOT NULL);`
|
||||
_ ,err=db.Exec(schema)
|
||||
if err != nil {
|
||||
fmt.Println("Schema creation failed: " + err.Error())
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
module git.teamworkapps.com/shortcut/scsusers
|
||||
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/mattn/go-sqlite3 v1.14.17
|
||||
golang.org/x/crypto v0.12.0
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
122
main.go
122
main.go
|
@ -29,17 +29,27 @@ type config struct {
|
|||
Templates templates
|
||||
SMTPServer string
|
||||
db *sqlx.DB
|
||||
testing bool
|
||||
TablePrefix string
|
||||
}
|
||||
|
||||
type UserData struct {
|
||||
Username string `json:"username"`
|
||||
UserPerms map[string]string `json:"perms"`
|
||||
UserSettings map[string]string `json:"settings"`
|
||||
UserID int64 `db:"id"`
|
||||
Username string `db:"username"`
|
||||
Password string `db:"password"`
|
||||
|
||||
Meta map[string]metadata
|
||||
}
|
||||
|
||||
type metadata struct {
|
||||
Key string `db:"meta_key"`
|
||||
Value string `db:"meta_value"`
|
||||
ID int64 `db:"id"`
|
||||
}
|
||||
|
||||
var c config
|
||||
|
||||
|
||||
func Init(dbin *sqlx.DB, tp, sitename, fromaddr, smtpserver string) {
|
||||
c.db = dbin
|
||||
c.TablePrefix = tp
|
||||
|
@ -85,18 +95,20 @@ func Register(username, email, ip string) bool {
|
|||
log.Printf("scsusers.Register: Bcrypt GenerateFromPassword failed? Pass is %s and error is %s\n", pass, err.Error())
|
||||
return false
|
||||
}
|
||||
q := fmt.Sprintf("insert into %s_auth (username, displayname, email, password, registration_date, registration_ip) values ($1, $2, $3, $4, CURRENT_TIMESTAMP, $5)", c.TablePrefix)
|
||||
_, err = c.db.Exec(q, username, username, email, crypt, ip)
|
||||
_, err = c.db.Query(fmt.Sprintf("insert into %s_auth (username, password) VALUES ($1, $2)", c.TablePrefix), username, crypt)
|
||||
if err != nil {
|
||||
log.Printf("scsusers.Register: insert failed: %s\n", err.Error())
|
||||
return false
|
||||
}
|
||||
if c.testing {
|
||||
return true
|
||||
}
|
||||
if SendRegistrationEmail(email, username, string(pass)) {
|
||||
log.Printf("scsusers.Register: New user registration: %s from %s\n", username, ip)
|
||||
return true
|
||||
}
|
||||
log.Printf("scsusers.Register: Failed to send registration email, deleting user %s\n", username)
|
||||
q = fmt.Sprintf("delete from %s_auth where username = $1 AND password=$2", c.TablePrefix)
|
||||
q := fmt.Sprintf("delete from %s_auth where username = $1 AND password=$2", c.TablePrefix)
|
||||
_, err = c.db.Exec(q, username, string(crypt))
|
||||
if err != nil {
|
||||
log.Printf("scsusers.Register: Failed to delete new user %s: %s\n", username, err.Error())
|
||||
|
@ -104,17 +116,38 @@ func Register(username, email, ip string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func Login(username, password string) bool {
|
||||
username = strings.ToLower(username)
|
||||
func NewUser() *UserData {
|
||||
var u UserData
|
||||
u.Meta = make(map[string]metadata)
|
||||
return &u
|
||||
}
|
||||
|
||||
q := fmt.Sprintf("select password from %s_auth where username = $1 AND status='active'", c.TablePrefix)
|
||||
var crypt string
|
||||
err := c.db.Get(&crypt, q, username)
|
||||
func Get(username string) (*UserData, bool) {
|
||||
|
||||
u := NewUser()
|
||||
q := fmt.Sprintf("select username, password, id from %s_auth where username=$1", c.TablePrefix)
|
||||
err := c.db.Get(&u, q, username)
|
||||
if err != nil {
|
||||
log.Printf("scsusers.Login: Failed login attempt for unknown username: %s\n", username)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, false
|
||||
}
|
||||
log.Printf("scsusers.Get: %s", err.Error())
|
||||
return nil, false
|
||||
}
|
||||
q = fmt.Sprintf("select key, value, id from %s_meta where user=%d", c.TablePrefix, u.UserID)
|
||||
err = c.db.Select(&u.Meta, q)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
log.Printf("scsuser.Get: select: %s", err.Error())
|
||||
}
|
||||
return u, true
|
||||
}
|
||||
|
||||
func Login(username, password string) bool {
|
||||
u, ok := Get(username)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword([]byte(crypt), []byte(password)) != nil {
|
||||
if bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) != nil {
|
||||
log.Printf("scsusers.Login: Failed password for " + username)
|
||||
return false
|
||||
}
|
||||
|
@ -122,25 +155,20 @@ func Login(username, password string) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func ChangePassword(username, oldpass, newpass string) bool {
|
||||
username = strings.ToLower(username)
|
||||
|
||||
q := fmt.Sprintf("select password from %s_auth where username = $1 AND status='active'", c.TablePrefix)
|
||||
var crypt string
|
||||
err := c.db.Get(&crypt, q, username)
|
||||
if err != nil {
|
||||
log.Println("scsusers.ChangePassword: Failed change attempt for unknown username: " + username)
|
||||
return false
|
||||
}
|
||||
if bcrypt.CompareHashAndPassword([]byte(crypt), []byte(oldpass)) != nil {
|
||||
log.Printf("scsusers.ChangePassword: Failed password for %s\n", username)
|
||||
func (u *UserData) ChangePassword(oldpass, newpass string) bool {
|
||||
if bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(oldpass)) != nil {
|
||||
log.Printf("scsusers.ChangePassword: Failed password for %s\n", u.Username)
|
||||
return false
|
||||
}
|
||||
newcrypt, err := bcrypt.GenerateFromPassword([]byte(newpass), 10)
|
||||
q = fmt.Sprintf("update %s_auth set password=$2 where username = $1", c.TablePrefix)
|
||||
_, err = c.db.Exec(q, username, newcrypt)
|
||||
if err != nil {
|
||||
log.Printf("scsusers.ChangePassword: update failed for %s: %s\n", username, err.Error())
|
||||
log.Printf("scsusers.ChangePassword: generate: %s", err.Error())
|
||||
return false
|
||||
}
|
||||
q := fmt.Sprintf("update %s_auth set password=$2 where userid=$1", c.TablePrefix)
|
||||
_, err = c.db.Exec(q, u.UserID, newcrypt)
|
||||
if err != nil {
|
||||
log.Printf("scsusers.ChangePassword: update failed for %s: %s\n", u.Username, err.Error())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@ -159,22 +187,34 @@ func GetUserid(username string) int64 {
|
|||
}
|
||||
return i
|
||||
}
|
||||
func LoadUser(username string) (UserData, error) {
|
||||
var tmp UserData
|
||||
username = strings.ToLower(username)
|
||||
|
||||
q := fmt.Sprintf("select data from %s_userdata where username = $1", c.TablePrefix)
|
||||
var d string
|
||||
err := c.db.Get(d, q, username)
|
||||
if err != nil {
|
||||
log.Printf("scsusers.LoadUser: Error loading user: %s : %s\n", username, err.Error())
|
||||
return tmp, err
|
||||
func (u *UserData) Get(key string) (string, bool) {
|
||||
tmp, ok := u.Meta[key]
|
||||
return tmp.Value, ok
|
||||
}
|
||||
|
||||
func (u *UserData) Set(key, value string) error {
|
||||
tmp, ok := u.Meta[key]
|
||||
if ok {
|
||||
_, err := c.db.Query(fmt.Sprintf("delete from %s_meta where id=$1", c.TablePrefix), tmp.ID)
|
||||
if err != nil {
|
||||
log.Printf("scsauth: set: delete: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = json.Unmarshal([]byte(d), &tmp)
|
||||
var insertid int64
|
||||
err := c.db.Get(&insertid, fmt.Sprintf("insert into %s_meta (userid, meta_key, meta_value) VALUES ($1, $2, $3) returning id", c.TablePrefix), u.UserID, key, value)
|
||||
if err != nil {
|
||||
log.Printf("scsusers.LoadUser: Error decoding json on user %s. Unmarshal returned %s\n", username, err.Error())
|
||||
log.Printf("scsauth: set: insert: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
return tmp, err
|
||||
var m metadata
|
||||
m.Key = key
|
||||
m.Value = value
|
||||
m.ID = insertid
|
||||
u.Meta[key] = m
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func SaveUser(username string, d UserData) bool {
|
||||
|
@ -191,10 +231,10 @@ func SaveUser(username string, d UserData) bool {
|
|||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
func Bump(username string, ip string) {
|
||||
|
||||
username = strings.ToLower(username)
|
||||
q := fmt.Sprintf("update %s_auth set lastseen=CURRENT_TIMESTAMP, lastseenip=$2 where username = $1 limit 1", c.TablePrefix)
|
||||
_, err := c.db.Exec(q, username, ip)
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package scsusers
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func TestUsers(t *testing.T) {
|
||||
var email string
|
||||
c.testing=true
|
||||
flag.StringVar(&email, "email", "", "Email address to use for registration test")
|
||||
flag.Parse()
|
||||
|
||||
db, err := sqlx.Open("sqlite3", ":memory:")
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't open sqlite3 in-memory db:" + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't ping sqlite3 in-memory db:" + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
schema := `CREATE TABLE test_auth (
|
||||
id integer primary key autoincrement,
|
||||
username text NOT NULL unique,
|
||||
password text NOT NULL);`
|
||||
_, err = db.Exec(schema)
|
||||
if err != nil {
|
||||
fmt.Println("Schema creation failed: " + err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
Init(db, "test", "Example Test", "nobody@nowhere.com", "localhost:25")
|
||||
a := UsernameAvailable("testuser")
|
||||
fmt.Printf("Initial test of username available: %v\n", a)
|
||||
a = Register("testuser", email, "127.0.0.1")
|
||||
fmt.Printf("Register returned %v\n", a)
|
||||
fmt.Printf("Attempt to log in with invalid username returned %v\n", Login("baduser", "badpass"))
|
||||
fmt.Printf("Enter code from email:")
|
||||
var code string
|
||||
fmt.Scan(&code)
|
||||
a = Login("testuser", code)
|
||||
fmt.Printf("Login returned %v\n", a)
|
||||
|
||||
}
|
Loading…
Reference in New Issue