2020-04-29 17:44:29 -07:00
|
|
|
package manage
|
|
|
|
|
|
|
|
import (
|
2022-01-07 14:44:42 -08:00
|
|
|
"bytes"
|
2022-07-22 14:56:14 -07:00
|
|
|
"fmt"
|
2020-04-29 17:44:29 -07:00
|
|
|
"net/http"
|
2022-01-16 13:30:33 -08:00
|
|
|
"strconv"
|
2020-04-29 17:44:29 -07:00
|
|
|
"time"
|
|
|
|
|
2021-03-26 11:10:05 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/config"
|
2020-04-29 17:44:29 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/gclog"
|
|
|
|
"github.com/gochan-org/gochan/pkg/gcsql"
|
2022-01-07 14:44:42 -08:00
|
|
|
"github.com/gochan-org/gochan/pkg/gctemplates"
|
2021-03-26 11:10:05 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/gcutil"
|
2020-04-29 17:44:29 -07:00
|
|
|
"github.com/gochan-org/gochan/pkg/serverutil"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-05-28 12:49:41 -07:00
|
|
|
sSuccess = iota
|
2020-04-29 17:44:29 -07:00
|
|
|
sInvalidPassword
|
|
|
|
sOtherError
|
|
|
|
)
|
|
|
|
|
2020-07-09 15:54:31 -07:00
|
|
|
func createSession(key, username, password string, request *http.Request, writer http.ResponseWriter) int {
|
2020-04-29 17:44:29 -07:00
|
|
|
//returns 0 for successful, 1 for password mismatch, and 2 for other
|
|
|
|
domain := request.Host
|
2020-06-06 09:28:45 -07:00
|
|
|
var err error
|
2020-04-29 17:44:29 -07:00
|
|
|
domain = chopPortNumRegex.Split(domain, -1)[0]
|
|
|
|
|
|
|
|
if !serverutil.ValidReferer(request) {
|
|
|
|
gclog.Print(gclog.LStaffLog, "Rejected login from possible spambot @ "+request.RemoteAddr)
|
2020-05-28 12:49:41 -07:00
|
|
|
return sOtherError
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
staff, err := gcsql.GetStaffByName(username)
|
|
|
|
if err != nil {
|
|
|
|
gclog.Print(gclog.LErrorLog, err.Error())
|
2020-05-28 12:49:41 -07:00
|
|
|
return sInvalidPassword
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
success := bcrypt.CompareHashAndPassword([]byte(staff.PasswordChecksum), []byte(password))
|
|
|
|
if success == bcrypt.ErrMismatchedHashAndPassword {
|
|
|
|
// password mismatch
|
|
|
|
gclog.Print(gclog.LStaffLog, "Failed login (password mismatch) from "+request.RemoteAddr+" at "+time.Now().Format(gcsql.MySQLDatetimeFormat))
|
2020-05-28 12:49:41 -07:00
|
|
|
return sInvalidPassword
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// successful login, add cookie that expires in one month
|
2021-07-11 11:51:29 -07:00
|
|
|
systemCritical := config.GetSystemCriticalConfig()
|
|
|
|
siteConfig := config.GetSiteConfig()
|
|
|
|
maxAge, err := gcutil.ParseDurationString(siteConfig.CookieMaxAge)
|
2021-03-26 11:10:05 -07:00
|
|
|
if err != nil {
|
|
|
|
maxAge = gcutil.DefaultMaxAge
|
|
|
|
}
|
2020-04-29 17:44:29 -07:00
|
|
|
http.SetCookie(writer, &http.Cookie{
|
|
|
|
Name: "sessiondata",
|
|
|
|
Value: key,
|
2021-07-11 11:51:29 -07:00
|
|
|
Path: systemCritical.WebRoot,
|
2020-04-29 17:44:29 -07:00
|
|
|
Domain: domain,
|
2021-03-26 11:10:05 -07:00
|
|
|
MaxAge: int(maxAge),
|
2020-04-29 17:44:29 -07:00
|
|
|
})
|
|
|
|
|
|
|
|
if err = gcsql.CreateSession(key, username); err != nil {
|
|
|
|
gclog.Print(gclog.LErrorLog, "Error creating new staff session: ", err.Error())
|
2020-05-28 12:49:41 -07:00
|
|
|
return sOtherError
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
2020-05-28 12:49:41 -07:00
|
|
|
return sSuccess
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
|
2020-06-06 09:28:45 -07:00
|
|
|
func getCurrentStaff(request *http.Request) (string, error) { //TODO after refactor, check if still used
|
2020-04-29 17:44:29 -07:00
|
|
|
sessionCookie, err := request.Cookie("sessiondata")
|
|
|
|
if err != nil {
|
2020-06-06 09:28:45 -07:00
|
|
|
return "", err
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
name, err := gcsql.GetStaffName(sessionCookie.Value)
|
|
|
|
if err == nil {
|
2020-06-06 09:28:45 -07:00
|
|
|
return "", err
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
return name, nil
|
|
|
|
}
|
|
|
|
|
2020-06-06 09:28:45 -07:00
|
|
|
func getCurrentFullStaff(request *http.Request) (*gcsql.Staff, error) {
|
2020-04-29 17:44:29 -07:00
|
|
|
sessionCookie, err := request.Cookie("sessiondata")
|
|
|
|
if err != nil {
|
2020-06-06 09:28:45 -07:00
|
|
|
return nil, err
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
return gcsql.GetStaffBySession(sessionCookie.Value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetStaffRank returns the rank number of the staff referenced in the request
|
|
|
|
func GetStaffRank(request *http.Request) int {
|
|
|
|
staff, err := getCurrentFullStaff(request)
|
|
|
|
if err != nil {
|
2020-10-10 16:17:36 -07:00
|
|
|
return NoPerms
|
2020-04-29 17:44:29 -07:00
|
|
|
}
|
|
|
|
return staff.Rank
|
|
|
|
}
|
2020-05-22 18:06:15 +02:00
|
|
|
|
2022-01-01 16:03:39 -08:00
|
|
|
// returns the action by its ID, or nil if it doesn't exist
|
|
|
|
func getAction(id string, rank int) *Action {
|
2022-01-16 13:30:33 -08:00
|
|
|
for a := range actions {
|
2022-01-01 16:03:39 -08:00
|
|
|
if rank == NoPerms && actions[a].Permissions > NoPerms {
|
|
|
|
id = "login"
|
|
|
|
}
|
|
|
|
if actions[a].ID == id {
|
|
|
|
return &actions[a]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-23 14:41:49 -08:00
|
|
|
func init() {
|
2022-01-07 14:44:42 -08:00
|
|
|
actions = append(actions,
|
|
|
|
Action{
|
|
|
|
ID: "actions",
|
|
|
|
Title: "Staff actions",
|
|
|
|
Permissions: JanitorPerms,
|
|
|
|
JSONoutput: AlwaysJSON,
|
|
|
|
Callback: getStaffActions,
|
|
|
|
},
|
|
|
|
Action{
|
|
|
|
ID: "dashboard",
|
|
|
|
Title: "Dashboard",
|
|
|
|
Permissions: JanitorPerms,
|
|
|
|
Callback: dashboardCallback,
|
|
|
|
})
|
2021-12-23 14:41:49 -08:00
|
|
|
}
|
|
|
|
|
2022-01-07 14:44:42 -08:00
|
|
|
func dashboardCallback(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (interface{}, error) {
|
|
|
|
dashBuffer := bytes.NewBufferString("")
|
|
|
|
announcements, err := gcsql.GetAllAccouncements()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-10-10 16:17:36 -07:00
|
|
|
rank := GetStaffRank(request)
|
2022-01-07 14:44:42 -08:00
|
|
|
availableActions := getAvailableActions(rank, true)
|
|
|
|
if err = serverutil.MinifyTemplate(gctemplates.ManageDashboard,
|
|
|
|
map[string]interface{}{
|
|
|
|
"actions": availableActions,
|
|
|
|
"rank": rank,
|
|
|
|
"announcements": announcements,
|
|
|
|
"boards": gcsql.AllBoards,
|
|
|
|
"webroot": config.GetSystemCriticalConfig().WebRoot,
|
|
|
|
}, dashBuffer, "text/html"); err != nil {
|
|
|
|
gclog.Printf(gclog.LErrorLog|gclog.LStaffLog,
|
|
|
|
"Error executing dashboard template: %q", err.Error())
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return dashBuffer.String(), nil
|
|
|
|
}
|
2021-12-23 14:41:49 -08:00
|
|
|
|
2022-01-07 14:44:42 -08:00
|
|
|
func getAvailableActions(rank int, noJSON bool) []Action {
|
|
|
|
available := []Action{}
|
2022-01-01 16:03:39 -08:00
|
|
|
for _, action := range actions {
|
2022-01-07 14:44:42 -08:00
|
|
|
if (rank < action.Permissions || action.Permissions == NoPerms) ||
|
|
|
|
(noJSON && action.JSONoutput == AlwaysJSON) {
|
2020-10-10 16:17:36 -07:00
|
|
|
continue
|
2020-05-22 18:06:15 +02:00
|
|
|
}
|
2022-01-07 14:44:42 -08:00
|
|
|
available = append(available, action)
|
2020-05-22 18:06:15 +02:00
|
|
|
}
|
2022-01-07 14:44:42 -08:00
|
|
|
return available
|
|
|
|
}
|
|
|
|
|
|
|
|
func getStaffActions(writer http.ResponseWriter, request *http.Request, wantsJSON bool) (interface{}, error) {
|
|
|
|
rank := GetStaffRank(request)
|
|
|
|
availableActions := getAvailableActions(rank, false)
|
|
|
|
return availableActions, nil
|
2020-05-22 18:06:15 +02:00
|
|
|
}
|
2022-01-16 13:30:33 -08:00
|
|
|
|
|
|
|
// bordsRequestType takes the request and returns "cancel", "create", "delete",
|
|
|
|
// "edit", or "modify" and the board's ID according to the request
|
|
|
|
func boardsRequestType(request *http.Request) (string, int, error) {
|
|
|
|
var requestType string
|
|
|
|
var boardID int
|
|
|
|
var err error
|
|
|
|
if request.FormValue("docancel") != "" {
|
|
|
|
requestType = "cancel"
|
|
|
|
} else if request.FormValue("docreate") != "" {
|
|
|
|
requestType = "create"
|
|
|
|
} else if request.FormValue("dodelete") != "" {
|
|
|
|
requestType = "delete"
|
|
|
|
} else if request.FormValue("doedit") != "" {
|
|
|
|
requestType = "edit"
|
|
|
|
} else if request.FormValue("domodify") != "" {
|
|
|
|
requestType = "modify"
|
|
|
|
}
|
|
|
|
boardIDstr := request.FormValue("board")
|
|
|
|
if boardIDstr != "" {
|
|
|
|
boardID, err = strconv.Atoi(boardIDstr)
|
|
|
|
}
|
|
|
|
return requestType, boardID, err
|
|
|
|
}
|
2022-07-22 14:56:14 -07:00
|
|
|
|
|
|
|
func invalidWordfilterID(id interface{}) error {
|
|
|
|
return fmt.Errorf("wordfilter with id %q does not exist", id)
|
|
|
|
}
|