mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2025-01-08 10:51:09 +00:00
Auth: Do not let users with weird characters in name register
This commit is contained in:
parent
2a1e6409c8
commit
c1ac0bbd16
14
user/net.go
14
user/net.go
@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -41,6 +42,9 @@ func LogoutFromRequest(w http.ResponseWriter, rq *http.Request) {
|
|||||||
|
|
||||||
// Register registers the given user. If it fails, a non-nil error is returned.
|
// Register registers the given user. If it fails, a non-nil error is returned.
|
||||||
func Register(username, password, group, source string, force bool) error {
|
func Register(username, password, group, source string, force bool) error {
|
||||||
|
if !IsValidUsername(username) {
|
||||||
|
return fmt.Errorf("illegal username ‘%s’", username)
|
||||||
|
}
|
||||||
username = util.CanonicalName(username)
|
username = util.CanonicalName(username)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
@ -75,26 +79,26 @@ func Register(username, password, group, source string, force bool) error {
|
|||||||
// LoginDataHTTP logs such user in and returns string representation of an error if there is any.
|
// LoginDataHTTP logs such user in and returns string representation of an error if there is any.
|
||||||
//
|
//
|
||||||
// The HTTP parameters are used for setting header status (bad request, if it is bad) and saving a cookie.
|
// The HTTP parameters are used for setting header status (bad request, if it is bad) and saving a cookie.
|
||||||
func LoginDataHTTP(w http.ResponseWriter, rq *http.Request, username, password string) string {
|
func LoginDataHTTP(w http.ResponseWriter, username, password string) error {
|
||||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||||
if !HasUsername(username) {
|
if !HasUsername(username) {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
log.Println("Unknown username", username, "was entered")
|
log.Println("Unknown username", username, "was entered")
|
||||||
return "unknown username"
|
return errors.New("unknown username")
|
||||||
}
|
}
|
||||||
if !CredentialsOK(username, password) {
|
if !CredentialsOK(username, password) {
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
log.Println("A wrong password was entered for username", username)
|
log.Println("A wrong password was entered for username", username)
|
||||||
return "wrong password"
|
return errors.New("wrong password")
|
||||||
}
|
}
|
||||||
token, err := AddSession(username)
|
token, err := AddSession(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
return err.Error()
|
return err
|
||||||
}
|
}
|
||||||
http.SetCookie(w, cookie("token", token, time.Now().Add(365*24*time.Hour)))
|
http.SetCookie(w, cookie("token", token, time.Now().Add(365*24*time.Hour)))
|
||||||
return ""
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSession saves a session for `username` and returns a token to use.
|
// AddSession saves a session for `username` and returns a token to use.
|
||||||
|
14
user/user.go
14
user/user.go
@ -1,8 +1,8 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -11,8 +11,6 @@ import (
|
|||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var usernamePattern = regexp.MustCompile(`[^?!:#@><*|"'&%{}/]+`)
|
|
||||||
|
|
||||||
// User contains information about a given user required for identification.
|
// User contains information about a given user required for identification.
|
||||||
type User struct {
|
type User struct {
|
||||||
// Name is a username. It must follow hypha naming rules.
|
// Name is a username. It must follow hypha naming rules.
|
||||||
@ -138,8 +136,14 @@ func (user *User) ShowLockMaybe(w http.ResponseWriter, rq *http.Request) bool {
|
|||||||
|
|
||||||
// IsValidUsername checks if the given username is valid.
|
// IsValidUsername checks if the given username is valid.
|
||||||
func IsValidUsername(username string) bool {
|
func IsValidUsername(username string) bool {
|
||||||
return username != "anon" && username != "wikimind" &&
|
fmt.Println("Is", username, "ok")
|
||||||
usernamePattern.MatchString(strings.TrimSpace(username)) &&
|
for _, r := range username {
|
||||||
|
if strings.ContainsRune("?!:#@><*|\"'&%{}/", r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return username != "anon" &&
|
||||||
|
username != "wikimind" &&
|
||||||
usernameIsWhiteListed(username)
|
usernameIsWhiteListed(username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
70
web/auth.go
70
web/auth.go
@ -27,7 +27,7 @@ func initAuth(r *mux.Router) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if cfg.AllowRegistration {
|
if cfg.AllowRegistration {
|
||||||
r.HandleFunc("/register", handlerRegister)
|
r.HandleFunc("/register", handlerRegister).Methods(http.MethodPost, http.MethodGet)
|
||||||
}
|
}
|
||||||
if cfg.TelegramEnabled {
|
if cfg.TelegramEnabled {
|
||||||
r.HandleFunc("/telegram-login", handlerTelegramLogin)
|
r.HandleFunc("/telegram-login", handlerTelegramLogin)
|
||||||
@ -60,34 +60,38 @@ func handlerRegister(w http.ResponseWriter, rq *http.Request) {
|
|||||||
views.Register(rq),
|
views.Register(rq),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
} else if rq.Method == http.MethodPost {
|
return
|
||||||
var (
|
|
||||||
username = rq.PostFormValue("username")
|
|
||||||
password = rq.PostFormValue("password")
|
|
||||||
err = user.Register(username, password, "editor", "local", false)
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to register ‘%s’: %s", username, err.Error())
|
|
||||||
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = io.WriteString(
|
|
||||||
w,
|
|
||||||
views.Base(
|
|
||||||
viewutil.MetaFrom(w, rq),
|
|
||||||
lc.Get("auth.register_title"),
|
|
||||||
fmt.Sprintf(
|
|
||||||
`<main class="main-width"><p>%s</p><p><a href="/register">%s<a></p></main>`,
|
|
||||||
err.Error(),
|
|
||||||
lc.Get("auth.try_again"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
log.Printf("Successfully registered ‘%s’", username)
|
|
||||||
user.LoginDataHTTP(w, rq, username, password)
|
|
||||||
http.Redirect(w, rq, "/"+rq.URL.RawQuery, http.StatusSeeOther)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
username = rq.PostFormValue("username")
|
||||||
|
password = rq.PostFormValue("password")
|
||||||
|
err = user.Register(username, password, "editor", "local", false)
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to register ‘%s’: %s", username, err.Error())
|
||||||
|
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
_, _ = io.WriteString(
|
||||||
|
w,
|
||||||
|
views.Base(
|
||||||
|
viewutil.MetaFrom(w, rq),
|
||||||
|
lc.Get("auth.register_title"),
|
||||||
|
fmt.Sprintf(
|
||||||
|
`<main class="main-width"><p>%s</p><p><a href="/register">%s<a></p></main>`,
|
||||||
|
err.Error(),
|
||||||
|
lc.Get("auth.try_again"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Successfully registered ‘%s’", username)
|
||||||
|
if err := user.LoginDataHTTP(w, username, password); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Redirect(w, rq, "/"+rq.URL.RawQuery, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
// handlerLogout shows the logout form (GET) or logs the user out (POST).
|
// handlerLogout shows the logout form (GET) or logs the user out (POST).
|
||||||
@ -134,12 +138,12 @@ func handlerLogin(w http.ResponseWriter, rq *http.Request) {
|
|||||||
var (
|
var (
|
||||||
username = util.CanonicalName(rq.PostFormValue("username"))
|
username = util.CanonicalName(rq.PostFormValue("username"))
|
||||||
password = rq.PostFormValue("password")
|
password = rq.PostFormValue("password")
|
||||||
err = user.LoginDataHTTP(w, rq, username, password)
|
err = user.LoginDataHTTP(w, username, password)
|
||||||
)
|
)
|
||||||
if err != "" {
|
if err != nil {
|
||||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
_, _ = io.WriteString(w, views.Base(viewutil.MetaFrom(w, rq), err, views.LoginError(err, lc)))
|
_, _ = io.WriteString(w, views.Base(viewutil.MetaFrom(w, rq), err.Error(), views.LoginError(err.Error(), lc)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
http.Redirect(w, rq, "/", http.StatusSeeOther)
|
||||||
@ -191,8 +195,8 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errmsg := user.LoginDataHTTP(w, rq, username, "")
|
errmsg := user.LoginDataHTTP(w, username, "")
|
||||||
if errmsg != "" {
|
if errmsg != nil {
|
||||||
log.Printf("Failed to login ‘%s’ using Telegram: %s", username, err.Error())
|
log.Printf("Failed to login ‘%s’ using Telegram: %s", username, err.Error())
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, _ = io.WriteString(
|
_, _ = io.WriteString(
|
||||||
|
Loading…
Reference in New Issue
Block a user