mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-07 01:56:24 -07:00
172 lines
5.2 KiB
Go
172 lines
5.2 KiB
Go
package gcsql
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gochan-org/gochan/pkg/gcutil"
|
|
)
|
|
|
|
var (
|
|
ErrUnrecognizedUsername = errors.New("invalid username")
|
|
)
|
|
|
|
// createDefaultAdminIfNoStaff creates a new default admin account if no accounts exist
|
|
func createDefaultAdminIfNoStaff() error {
|
|
const sql = `SELECT COUNT(id) FROM DBPREFIXstaff`
|
|
var count int
|
|
QueryRowSQL(sql, interfaceSlice(), interfaceSlice(&count))
|
|
if count > 0 {
|
|
return nil
|
|
}
|
|
_, err := NewStaff("admin", "password", 3)
|
|
return err
|
|
}
|
|
|
|
func NewStaff(username string, password string, rank int) (*Staff, error) {
|
|
const sqlINSERT = `INSERT INTO DBPREFIXstaff
|
|
(username, password_checksum, global_rank)
|
|
VALUES(?,?,?)`
|
|
passwordChecksum := gcutil.BcryptSum(password)
|
|
_, err := ExecSQL(sqlINSERT, username, passwordChecksum, rank)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Staff{
|
|
Username: username,
|
|
PasswordChecksum: passwordChecksum,
|
|
Rank: rank,
|
|
AddedOn: time.Now(),
|
|
IsActive: true,
|
|
}, nil
|
|
}
|
|
|
|
// SetActive changes the active status of the staff member. If `active` is false, the login sessions are cleared
|
|
func (s *Staff) SetActive(active bool) error {
|
|
const updateActive = `UPDATE DBPREFIXstaff SET is_active = FALSE WHERE username = ?`
|
|
_, err := ExecSQL(updateActive, s.Username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if active {
|
|
return nil
|
|
}
|
|
return s.ClearSessions()
|
|
}
|
|
|
|
// ClearSessions clears all login sessions for the user, requiring them to login again
|
|
func (s *Staff) ClearSessions() error {
|
|
const query = `SELECT id FROM DBPREFIXstaff WHERE username = ?`
|
|
const deleteSessions = `DELETE FROM DBPREFIXsessions WHERE staff_id = ?`
|
|
var err error
|
|
if s.ID == 0 {
|
|
// ID field not set, get it from the DB
|
|
if err = QueryRowSQL(query, interfaceSlice(s.Username), interfaceSlice(&s.ID)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
_, err = ExecSQL(deleteSessions, s.ID)
|
|
return err
|
|
}
|
|
|
|
func (s *Staff) RankTitle() string {
|
|
if s.Rank == 3 {
|
|
return "Administrator"
|
|
} else if s.Rank == 2 {
|
|
return "Moderator"
|
|
} else if s.Rank == 1 {
|
|
return "Janitor"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// EndStaffSession deletes any session rows associated with the requests session cookie and then
|
|
// makes the cookie expire, essentially deleting it
|
|
func EndStaffSession(writer http.ResponseWriter, request *http.Request) error {
|
|
session, err := request.Cookie("sessiondata")
|
|
if err != nil {
|
|
// No staff session cookie, presumably not logged in so nothing to do
|
|
return nil
|
|
}
|
|
// make it so that the next time the page is loaded, the browser will delete it
|
|
sessionVal := session.Value
|
|
session.MaxAge = -1
|
|
http.SetCookie(writer, session)
|
|
|
|
staffID := 0
|
|
if err = QueryRowSQL(`SELECT staff_id FROM DBPREFIXsessions WHERE data = ?`,
|
|
[]interface{}{session.Value}, []interface{}{&staffID}); err != nil && err != sql.ErrNoRows {
|
|
// something went wrong with the query and it's not caused by no rows being returned
|
|
return errors.New("failed getting staff ID: " + err.Error())
|
|
}
|
|
|
|
_, err = ExecSQL(`DELETE FROM DBPREFIXsessions WHERE data = ?`, sessionVal)
|
|
if err != nil && err != sql.ErrNoRows {
|
|
return fmt.Errorf("failed clearing session for staff with id %d", staffID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func DeactivateStaff(username string) error {
|
|
s := Staff{Username: username}
|
|
return s.SetActive(false)
|
|
}
|
|
|
|
func GetStaffUsernameFromID(id int) (string, error) {
|
|
const query = `SELECT username FROM DBPREFIXstaff WHERE id = ?`
|
|
var username string
|
|
err := QueryRowSQL(query, interfaceSlice(id), interfaceSlice(&username))
|
|
return username, err
|
|
}
|
|
|
|
// GetStaffBySession gets the staff that is logged in in the given session
|
|
func GetStaffBySession(session string) (*Staff, error) {
|
|
const query = `SELECT
|
|
staff.id,
|
|
staff.username,
|
|
staff.password_checksum,
|
|
staff.global_rank,
|
|
staff.added_on,
|
|
staff.last_login
|
|
FROM DBPREFIXstaff as staff
|
|
JOIN DBPREFIXsessions as sessions
|
|
ON sessions.staff_id = staff.id
|
|
WHERE sessions.data = ?`
|
|
staff := new(Staff)
|
|
err := QueryRowSQL(query, interfaceSlice(session), interfaceSlice(
|
|
&staff.ID, &staff.Username, &staff.PasswordChecksum, &staff.Rank, &staff.AddedOn, &staff.LastLogin))
|
|
return staff, err
|
|
}
|
|
|
|
func GetStaffByUsername(username string, onlyActive bool) (*Staff, error) {
|
|
query := `SELECT
|
|
id, username, password_checksum, global_rank, added_on, last_login, is_active
|
|
FROM DBPREFIXstaff WHERE username = ?`
|
|
if onlyActive {
|
|
query += ` AND is_active = TRUE`
|
|
}
|
|
staff := new(Staff)
|
|
err := QueryRowSQL(query, interfaceSlice(username), interfaceSlice(
|
|
&staff.ID, &staff.Username, &staff.PasswordChecksum, &staff.Rank, &staff.AddedOn,
|
|
&staff.LastLogin, &staff.IsActive,
|
|
))
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, ErrUnrecognizedUsername
|
|
}
|
|
return staff, err
|
|
}
|
|
|
|
// CreateLoginSession inserts a session for a given key and username into the database
|
|
func (staff *Staff) CreateLoginSession(key string) error {
|
|
const insertSQL = `INSERT INTO DBPREFIXsessions (staff_id,data,expires) VALUES(?,?,?)`
|
|
const updateSQL = `UPDATE DBPREFIXstaff SET last_login = CURRENT_TIMESTAMP WHERE id = ?`
|
|
_, err := ExecSQL(insertSQL, staff.ID, key, time.Now().Add(time.Duration(time.Hour*730))) //TODO move amount of time to config file
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = ExecSQL(updateSQL, staff.ID)
|
|
return err
|
|
}
|