1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-12-12 05:20:26 +00:00
mycorrhiza/user/user.go

151 lines
3.5 KiB
Go
Raw Normal View History

package user
import (
"net/http"
"regexp"
"strings"
"sync"
2021-06-29 10:34:36 +00:00
"time"
"github.com/bouncepaw/mycorrhiza/cfg"
"golang.org/x/crypto/bcrypt"
)
var usernamePattern = regexp.MustCompile(`[^?!:#@><*|"'&%{}/]+`)
// User contains information about a given user required for identification.
type User struct {
// Name is a username. It must follow hypha naming rules.
Name string `json:"name"`
Group string `json:"group"`
Password string `json:"hashed_password"`
RegisteredAt time.Time `json:"registered_on"`
2021-11-10 07:21:11 +00:00
// Source is where the user from. Valid values: local, telegram.
Source string `json:"source"`
sync.RWMutex
// A note about why HashedPassword is string and not []byte. The reason is
// simple: golang's json marshals []byte as slice of numbers, which is not
// acceptable.
2020-11-14 13:03:06 +00:00
}
// Route — Right (more is more right)
var minimalRights = map[string]int{
2021-01-23 19:00:58 +00:00
"edit": 1,
"upload-binary": 1,
"upload-text": 1,
"rename-ask": 2,
"rename-confirm": 2,
"unattach-ask": 2,
"unattach-confirm": 2,
"update-header-links": 3,
"delete-ask": 3,
"delete-confirm": 3,
"reindex": 4,
"admin": 4,
2021-02-18 14:50:37 +00:00
"admin/shutdown": 4,
2020-11-14 14:46:04 +00:00
}
var groups = []string{
"anon",
"editor",
"trusted",
"moderator",
"admin",
}
2021-07-14 21:00:35 +00:00
// Group — Right level
var groupRight = map[string]int{
"anon": 0,
"editor": 1,
"trusted": 2,
"moderator": 3,
"admin": 4,
2020-11-14 13:03:06 +00:00
}
// ValidGroup checks whether provided user group name exists.
func ValidGroup(group string) bool {
for _, grp := range groups {
if grp == group {
return true
}
}
return false
}
// ValidSource checks whether provided user source name exists.
2021-07-14 21:00:35 +00:00
func ValidSource(source string) bool {
return source == "local" || source == "telegram"
}
// EmptyUser constructs an anonymous user.
2021-01-24 07:30:14 +00:00
func EmptyUser() *User {
return &User{
Name: "anon",
Group: "anon",
Password: "",
Source: "local",
2020-11-14 10:39:18 +00:00
}
}
// WikimindUser constructs the wikimind user, which is to be used for automated wiki edits and has admin privileges.
func WikimindUser() *User {
return &User{
Name: "wikimind",
Group: "admin",
Password: "",
Source: "local",
}
}
// CanProceed checks whether user has rights to visit the provided path (and perform an action).
func (user *User) CanProceed(route string) bool {
if !cfg.UseAuth {
return true
2020-11-14 10:39:18 +00:00
}
2020-11-14 13:03:06 +00:00
user.RLock()
defer user.RUnlock()
2020-11-14 10:39:18 +00:00
2021-10-29 08:59:30 +00:00
right := groupRight[user.Group]
minimalRight := minimalRights[route]
return right >= minimalRight
2020-11-14 10:39:18 +00:00
}
func (user *User) isCorrectPassword(password string) bool {
user.RLock()
defer user.RUnlock()
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
return err == nil
2020-11-14 10:39:18 +00:00
}
// ShowLockMaybe redirects to the lock page if the user is anon and the wiki has been configured to use the lock. It returns true if the user was redirected.
func (user *User) ShowLockMaybe(w http.ResponseWriter, rq *http.Request) bool {
if cfg.Locked && user.Group == "anon" {
http.Redirect(w, rq, "/lock", http.StatusSeeOther)
return true
}
return false
}
// IsValidUsername checks if the given username is valid.
func IsValidUsername(username string) bool {
return username != "anon" && username != "wikimind" &&
usernamePattern.MatchString(strings.TrimSpace(username)) &&
usernameIsWhiteListed(username)
}
func usernameIsWhiteListed(username string) bool {
if !cfg.UseWhiteList {
return true
}
for _, allowedUsername := range cfg.WhiteList {
if allowedUsername == username {
return true
}
}
return false
}