gosora/auth.go
Azareal 5a43432b80 Replaced most of the uses of fmt with log.
Replaced the io.Writers with http.ResponseWriters.
Refactored the compiled template calls.
Redirect port 443 to port 80.
Catch more errors from templates.
Fixed a few mutexes which are never unlocked.
Eliminated an unnecessary parameter in InternalError()
Temporarily commented out users_penalties so that the installer will succeed.
A couple more template types can be remapped now.
Tweaked the theme.
2017-08-13 12:22:34 +01:00

160 lines
4.3 KiB
Go

/* Work in progress */
package main
import "log"
import "errors"
import "strconv"
import "net/http"
import "database/sql"
import "./query_gen/lib"
import "golang.org/x/crypto/bcrypt"
var auth Auth
var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword
var ErrPasswordTooLong = errors.New("The password you selected is too long") // Silly, but we don't want bcrypt to bork on us
type Auth interface
{
Authenticate(username string, password string) (uid int, err error)
Logout(w http.ResponseWriter, uid int)
ForceLogout(uid int) error
SetCookies(w http.ResponseWriter, uid int, session string)
GetCookies(r *http.Request) (uid int, session string, err error)
SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool)
CreateSession(uid int) (session string, err error)
}
type DefaultAuth struct
{
login *sql.Stmt
logout *sql.Stmt
}
func NewDefaultAuth() *DefaultAuth {
login_stmt, err := qgen.Builder.SimpleSelect("users","uid, password, salt","name = ?","","")
if err != nil {
log.Fatal(err)
}
logout_stmt, err := qgen.Builder.SimpleUpdate("users","session = ''","uid = ?")
if err != nil {
log.Fatal(err)
}
return &DefaultAuth{
login: login_stmt,
logout: logout_stmt,
}
}
func (auth *DefaultAuth) Authenticate(username string, password string) (uid int, err error) {
var real_password, salt string
err = auth.login.QueryRow(username).Scan(&uid, &real_password, &salt)
if err == ErrNoRows {
return 0, errors.New("We couldn't find an account with that username.")
} else if err != nil {
LogError(err)
return 0, errors.New("There was a glitch in the system. Please contact the system administrator.")
}
if salt == "" {
// Send an email to admin for this?
LogError(errors.New("Missing salt for user #" + strconv.Itoa(uid) + ". Potential security breach."))
return 0, errors.New("There was a glitch in the system. Please contact the system administrator.")
}
err = CheckPassword(real_password,password,salt)
if err == ErrMismatchedHashAndPassword {
return 0, errors.New("That's not the correct password.")
} else if err != nil {
LogError(err)
return 0, errors.New("There was a glitch in the system. Please contact the system administrator.")
}
return uid, nil
}
func (auth *DefaultAuth) ForceLogout(uid int) error {
_, err := auth.logout.Exec(uid)
if err != nil {
LogError(err)
return errors.New("There was a glitch in the system. Please contact the system administrator.")
}
// Flush the user out of the cache and reload
err = users.Load(uid)
if err != nil {
return errors.New("Your account no longer exists!")
}
return nil
}
func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int) {
cookie := http.Cookie{Name:"uid",Value:"",Path:"/",MaxAge: year}
http.SetCookie(w,&cookie)
cookie = http.Cookie{Name:"session",Value:"",Path:"/",MaxAge: year}
http.SetCookie(w,&cookie)
}
func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session string) {
cookie := http.Cookie{Name: "uid",Value: strconv.Itoa(uid),Path: "/",MaxAge: year}
http.SetCookie(w,&cookie)
cookie = http.Cookie{Name: "session",Value: session,Path: "/",MaxAge: year}
http.SetCookie(w,&cookie)
}
func (auth *DefaultAuth) GetCookies(r *http.Request) (uid int, session string, err error) {
// Are there any session cookies..?
cookie, err := r.Cookie("uid")
if err != nil {
return 0, "", err
}
uid, err = strconv.Atoi(cookie.Value)
if err != nil {
return 0, "", err
}
cookie, err = r.Cookie("session")
if err != nil {
return 0, "", err
}
return uid, cookie.Value, err
}
func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool) {
uid, session, err := auth.GetCookies(r)
if err != nil {
return &guest_user, false
}
// Is this session valid..?
user, err = users.CascadeGet(uid)
if err == ErrNoRows {
return &guest_user, false
} else if err != nil {
InternalError(err,w)
return &guest_user, true
}
if user.Session == "" || session != user.Session {
return &guest_user, false
}
return user, false
}
func(auth *DefaultAuth) CreateSession(uid int) (session string, err error) {
session, err = GenerateSafeString(sessionLength)
if err != nil {
return "", err
}
_, err = update_session_stmt.Exec(session, uid)
if err != nil {
return "", err
}
// Reload the user data
_ = users.Load(uid)
return session, nil
}