190 lines
4.5 KiB
Go
190 lines
4.5 KiB
Go
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) bool {
|
|
if !UsernameAvailable(username) {
|
|
return false
|
|
}
|
|
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 false
|
|
}
|
|
_, 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 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_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 false
|
|
}
|
|
|
|
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
|
|
}
|