package scsusers import ( "database/sql" "fmt" "html/template" "log" "strings" "github.com/jmoiron/sqlx" "golang.org/x/crypto/bcrypt" ) type templates struct { Registration *template.Template Alert *template.Template Recovery *template.Template TwoFA *template.Template } type config struct { SiteName string FromEmail string Templates templates SMTPServer string db *sqlx.DB Testing bool TablePrefix string } type UserData struct { 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, testing bool) { c.db = dbin c.TablePrefix = tp c.SiteName = sitename c.FromEmail = fromaddr c.SMTPServer = smtpserver c.Testing = testing SetRegistrationTemplate("") SetAlertTemplate("") SetRecoveryTemplate("") Set2faTemplate("") } func UsernameAvailable(username string) bool { if len(username) == 0 { return false } var tmp string username = strings.ToLower(username) q := fmt.Sprintf("select username from %s_users where username = ?", c.TablePrefix) err := c.db.Get(&tmp, q, username) if err == sql.ErrNoRows { return true } if err != nil { log.Printf("UsernameAvailable returned error: " + err.Error() + " Query was " + q) return false } return false } /* Check for username availability, add to database, send email */ func Register(username, email, ip string) error { if !UsernameAvailable(username) { return fmt.Errorf("Username %s is not available", username) } username = strings.ToLower(username) pass := generatePassword(16) crypt, err := bcrypt.GenerateFromPassword(pass, 10) if err != nil { log.Printf("scsusers.Register: Bcrypt GenerateFromPassword failed? Pass is %s and error is %s\n", pass, err.Error()) return fmt.Errorf("Failed to generate password") } _, err = c.db.Query(fmt.Sprintf("insert into %s_users (username, password) VALUES (?,?)", c.TablePrefix), username, crypt) if err != nil { log.Printf("scsusers.Register: insert failed: %s\n", err.Error()) return fmt.Errorf("failed to insert user") } if SendRegistrationEmail(email, username, string(pass)) { log.Printf("scsusers.Register: New user registration: %s from %s\n", username, ip) return nil } log.Printf("scsusers.Register: Failed to send registration email, deleting user %s\n", username) q := fmt.Sprintf("delete from %s_users where username = ? AND password=?", 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()) } return fmt.Errorf("failed to send registration email") } func NewUser() *UserData { var u UserData u.Meta = make(map[string]metadata) return &u } func Get(username string) (*UserData, bool) { u := NewUser() q := fmt.Sprintf("select username, password, id from %s_users where username=?", c.TablePrefix) err := c.db.Get(u, q, username) if err != nil { if err == sql.ErrNoRows { return nil, false } log.Printf("scsusers.Get: %s", err.Error()) return nil, false } ok := u.LoadMeta() return u, ok } func GetById(id int64) (*UserData, bool) { u := NewUser() q := fmt.Sprintf("select username, password, id from %s_users where id=?", c.TablePrefix) err := c.db.Get(u, q, id) if err != nil { if err == sql.ErrNoRows { return nil, false } log.Printf("scsusers.GetById: %s", err.Error()) return nil, false } ok := u.LoadMeta() return u, ok } func GetUsersByMeta(key string, value string) []string { var u []string var userids []int64 q := fmt.Sprintf("select user from %s_meta where meta_key=? AND meta_value=?", c.TablePrefix) err := c.db.Select(&userids, q, key, value) if err != nil && err != sql.ErrNoRows { log.Printf("scsusers.getusersByMeta: %s", err) return nil } if len(userids) == 0 { return nil } q = fmt.Sprintf("select username from %s_users where id IN (?)", c.TablePrefix) query, args, err := sqlx.In(q, userids) if err != nil { log.Printf("scsusers.getusersbymeta: %s", err.Error()) return nil } query = c.db.Rebind(query) err = c.db.Select(&u, query, args...) if err != nil { log.Printf("scsusers.getusersbymeta: %s", err.Error()) return nil } return u } func GetUserid(username string) int64 { var i int64 username = strings.ToLower(username) q := fmt.Sprintf("select userid from %s_users where username = ?", c.TablePrefix) err := c.db.Get(&i, q, username) if err != nil { log.Printf("scsusers.getUserId: Error loading user: %s : %s\n", username, err.Error()) return 0 } return i }