mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2025-01-06 10:00:26 +00:00
Make the lock work
There is a new config field: Authorization.Locked.
I am a little bit sorry for how actually the lock is implemented. I've added the check on almost every handler there is. Good luck maintaining that ❤️
This commit is contained in:
parent
d8f4f40f52
commit
5d45ae67d4
@ -23,13 +23,13 @@ var (
|
||||
UserHypha string
|
||||
HeaderLinksHypha string
|
||||
|
||||
ListenAddr string
|
||||
URL string
|
||||
GeminiCertificatePath string
|
||||
ListenAddr string
|
||||
URL string
|
||||
|
||||
UseAuth bool
|
||||
AllowRegistration bool
|
||||
RegistrationLimit uint64
|
||||
Locked bool
|
||||
|
||||
CommonScripts []string
|
||||
ViewScripts []string
|
||||
@ -82,6 +82,7 @@ type Authorization struct {
|
||||
UseAuth bool
|
||||
AllowRegistration bool
|
||||
RegistrationLimit uint64 `comment:"This field controls the maximum amount of allowed registrations."`
|
||||
Locked bool `comment:"Set if users have to authorize to see anything on the wiki."`
|
||||
}
|
||||
|
||||
// ReadConfigFile reads a config on the given path and stores the
|
||||
@ -103,6 +104,7 @@ func ReadConfigFile(path string) error {
|
||||
UseAuth: false,
|
||||
AllowRegistration: false,
|
||||
RegistrationLimit: 0,
|
||||
Locked: false,
|
||||
},
|
||||
CustomScripts: CustomScripts{
|
||||
CommonScripts: []string{},
|
||||
@ -135,7 +137,9 @@ func ReadConfigFile(path string) error {
|
||||
|
||||
// Map the config file to the config struct. It'll do nothing if the file
|
||||
// doesn't exist or is empty.
|
||||
f.MapTo(cfg)
|
||||
if err := f.MapTo(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Map the struct to the global variables
|
||||
WikiName = cfg.WikiName
|
||||
@ -150,6 +154,7 @@ func ReadConfigFile(path string) error {
|
||||
UseAuth = cfg.UseAuth
|
||||
AllowRegistration = cfg.AllowRegistration
|
||||
RegistrationLimit = cfg.RegistrationLimit
|
||||
Locked = cfg.Locked && cfg.UseAuth // Makes no sense to have the lock but no auth
|
||||
CommonScripts = cfg.CommonScripts
|
||||
ViewScripts = cfg.ViewScripts
|
||||
EditScripts = cfg.EditScripts
|
||||
|
10
user/user.go
10
user/user.go
@ -1,6 +1,7 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@ -96,3 +97,12 @@ func (user *User) isCorrectPassword(password string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
57
web/admin.go
57
web/admin.go
@ -30,6 +30,9 @@ func initAdmin() {
|
||||
// handlerAdmin provides the admin panel.
|
||||
func handlerAdmin(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if user.CanProceed(rq, "admin") {
|
||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
@ -43,6 +46,9 @@ func handlerAdmin(w http.ResponseWriter, rq *http.Request) {
|
||||
// handlerAdminShutdown kills the wiki.
|
||||
func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if user.CanProceed(rq, "admin/shutdown") && rq.Method == "POST" {
|
||||
log.Fatal("An admin commanded the wiki to shutdown")
|
||||
}
|
||||
@ -51,6 +57,9 @@ func handlerAdminShutdown(w http.ResponseWriter, rq *http.Request) {
|
||||
// handlerAdminReindexUsers reinitialises the user system.
|
||||
func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if user.CanProceed(rq, "admin") && rq.Method == "POST" {
|
||||
user.ReadUsersFromFilesystem()
|
||||
redirectTo := rq.Referer()
|
||||
@ -61,10 +70,13 @@ func handlerAdminReindexUsers(w http.ResponseWriter, rq *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func handlerAdminUsers(w http.ResponseWriter, r *http.Request) {
|
||||
util.PrepareRq(r)
|
||||
if user.CanProceed(r, "admin") {
|
||||
path := strings.TrimPrefix(r.URL.Path, "/admin/users")
|
||||
func handlerAdminUsers(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if user.CanProceed(rq, "admin") {
|
||||
path := strings.TrimPrefix(rq.URL.Path, "/admin/users")
|
||||
parts := strings.Split(path, "/")[1:]
|
||||
|
||||
// Users dashboard
|
||||
@ -81,7 +93,7 @@ func handlerAdminUsers(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
|
||||
html := views.AdminUsersPanelHTML(userList)
|
||||
html = views.BaseHTML("Manage users", html, user.FromRequest(r))
|
||||
html = views.BaseHTML("Manage users", html, user.FromRequest(rq))
|
||||
|
||||
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
||||
if _, err := io.WriteString(w, html); err != nil {
|
||||
@ -103,9 +115,9 @@ func handlerAdminUsers(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
switch parts[1] {
|
||||
case "edit":
|
||||
f := util.FormDataFromRequest(r, []string{"group"})
|
||||
f := util.FormDataFromRequest(rq, []string{"group"})
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
if rq.Method == http.MethodPost {
|
||||
oldGroup := u.Group
|
||||
newGroup := f.Get("group")
|
||||
|
||||
@ -116,7 +128,7 @@ func handlerAdminUsers(w http.ResponseWriter, r *http.Request) {
|
||||
log.Println(err)
|
||||
f = f.WithError(err)
|
||||
} else {
|
||||
http.Redirect(w, r, "/admin/users/", http.StatusSeeOther)
|
||||
http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@ -127,7 +139,7 @@ func handlerAdminUsers(w http.ResponseWriter, r *http.Request) {
|
||||
f.Put("group", u.Group)
|
||||
|
||||
html := views.AdminUserEditHTML(u, f)
|
||||
html = views.BaseHTML(fmt.Sprintf("User %s", u.Name), html, user.FromRequest(r))
|
||||
html = views.BaseHTML(fmt.Sprintf("User %s", u.Name), html, user.FromRequest(rq))
|
||||
|
||||
if f.HasError() {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
@ -138,17 +150,17 @@ func handlerAdminUsers(w http.ResponseWriter, r *http.Request) {
|
||||
case "delete":
|
||||
f := util.NewFormData()
|
||||
|
||||
if r.Method == http.MethodPost {
|
||||
if rq.Method == http.MethodPost {
|
||||
f = f.WithError(user.DeleteUser(u.Name))
|
||||
if !f.HasError() {
|
||||
http.Redirect(w, r, "/admin/users/", http.StatusSeeOther)
|
||||
http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther)
|
||||
} else {
|
||||
log.Println(f.Error())
|
||||
}
|
||||
}
|
||||
|
||||
html := views.AdminUserDeleteHTML(u, util.NewFormData())
|
||||
html = views.BaseHTML(fmt.Sprintf("User %s", u.Name), html, user.FromRequest(r))
|
||||
html = views.BaseHTML(fmt.Sprintf("User %s", u.Name), html, user.FromRequest(rq))
|
||||
|
||||
if f.HasError() {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
@ -162,32 +174,35 @@ func handlerAdminUsers(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func handlerAdminUserNew(w http.ResponseWriter, r *http.Request) {
|
||||
util.PrepareRq(r)
|
||||
if user.CanProceed(r, "admin") {
|
||||
if r.Method == http.MethodGet {
|
||||
func handlerAdminUserNew(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if user.CanProceed(rq, "admin") {
|
||||
if rq.Method == http.MethodGet {
|
||||
// New user form
|
||||
html := views.AdminUserNewHTML(util.NewFormData())
|
||||
html = views.BaseHTML("New user", html, user.FromRequest(r))
|
||||
html = views.BaseHTML("New user", html, user.FromRequest(rq))
|
||||
|
||||
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
||||
io.WriteString(w, html)
|
||||
return
|
||||
} else if r.Method == http.MethodPost {
|
||||
} else if rq.Method == http.MethodPost {
|
||||
// Create a user
|
||||
f := util.FormDataFromRequest(r, []string{"name", "password", "group"})
|
||||
f := util.FormDataFromRequest(rq, []string{"name", "password", "group"})
|
||||
|
||||
err := user.Register(f.Get("name"), f.Get("password"), f.Get("group"), true)
|
||||
|
||||
if err != nil {
|
||||
html := views.AdminUserNewHTML(f.WithError(err))
|
||||
html = views.BaseHTML("New user", html, user.FromRequest(r))
|
||||
html = views.BaseHTML("New user", html, user.FromRequest(rq))
|
||||
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
||||
io.WriteString(w, html)
|
||||
} else {
|
||||
http.Redirect(w, r, "/admin/users/", http.StatusSeeOther)
|
||||
http.Redirect(w, rq, "/admin/users/", http.StatusSeeOther)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -33,6 +33,9 @@ func handlerLock(w http.ResponseWriter, rq *http.Request) {
|
||||
|
||||
// handlerRegister both displays the register form (GET) and registers users (POST).
|
||||
func handlerRegister(w http.ResponseWriter, rq *http.Request) {
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
util.PrepareRq(rq)
|
||||
if !cfg.AllowRegistration {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
@ -102,6 +105,9 @@ func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) {
|
||||
|
||||
// handlerLogin shows the login form.
|
||||
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
util.PrepareRq(rq)
|
||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||
if cfg.UseAuth {
|
||||
|
@ -24,6 +24,9 @@ func initHistory() {
|
||||
// handlerHistory lists all revisions of a hypha.
|
||||
func handlerHistory(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
hyphaName := util.HyphaNameFromRq(rq, "history")
|
||||
var list string
|
||||
|
||||
@ -41,6 +44,9 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) {
|
||||
// handlerRecentChanges displays the /recent-changes/ page.
|
||||
func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
var (
|
||||
noPrefix = strings.TrimPrefix(rq.URL.String(), "/recent-changes/")
|
||||
n, err = strconv.Atoi(noPrefix)
|
||||
@ -55,6 +61,9 @@ func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
|
||||
// genericHandlerOfFeeds is a helper function for the web feed handlers.
|
||||
func genericHandlerOfFeeds(w http.ResponseWriter, rq *http.Request, f func() (string, error), name string) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if content, err := f(); err != nil {
|
||||
w.Header().Set("Content-Type", "text/plain;charset=utf-8")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@ -42,6 +42,9 @@ func factoryHandlerAsker(
|
||||
h = hyphae.ByName(hyphaName)
|
||||
u = user.FromRequest(rq)
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if err, errtitle := asker(u, h); err != nil {
|
||||
httpErr(
|
||||
w,
|
||||
@ -92,6 +95,9 @@ func factoryHandlerConfirmer(
|
||||
h = hyphae.ByName(hyphaName)
|
||||
u = user.FromRequest(rq)
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if hop, errtitle := confirmer(h, u, rq); hop.HasErrors() {
|
||||
httpErr(w, http.StatusInternalServerError, hyphaName,
|
||||
errtitle,
|
||||
@ -139,6 +145,9 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
|
||||
err error
|
||||
u = user.FromRequest(rq)
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if err, errtitle := shroom.CanEdit(u, h); err != nil {
|
||||
httpErr(w, http.StatusInternalServerError, hyphaName,
|
||||
errtitle,
|
||||
@ -178,6 +187,9 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
|
||||
hop *history.HistoryOp
|
||||
errtitle string
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
|
||||
if action != "Preview" {
|
||||
hop, errtitle = shroom.UploadText(h, []byte(textData), message, u)
|
||||
@ -219,6 +231,9 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
|
||||
u = user.FromRequest(rq)
|
||||
file, handler, err = rq.FormFile("binary")
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
httpErr(w, http.StatusInternalServerError, hyphaName,
|
||||
"Error",
|
||||
|
@ -37,6 +37,9 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) {
|
||||
h = hyphae.ByName(hyphaName)
|
||||
u = user.FromRequest(rq)
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
util.HTTP200Page(w,
|
||||
views.BaseHTML(
|
||||
fmt.Sprintf("Attachment of %s", util.BeautifulName(hyphaName)),
|
||||
@ -54,6 +57,9 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
|
||||
h = hyphae.ByName(hyphaName)
|
||||
u = user.FromRequest(rq)
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
util.HTTP200Page(w,
|
||||
views.BaseHTML(
|
||||
fmt.Sprintf("Diff of %s at %s", hyphaName, revHash),
|
||||
@ -74,6 +80,9 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
|
||||
textContents, err = history.FileAtRevision(h.TextPath, revHash)
|
||||
u = user.FromRequest(rq)
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if err == nil {
|
||||
ctx, _ := mycocontext.ContextFromStringInput(hyphaName, textContents)
|
||||
contents = mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx))
|
||||
@ -92,6 +101,9 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
|
||||
// handlerText serves raw source text of the hypha.
|
||||
func handlerText(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
hyphaName := util.HyphaNameFromRq(rq, "text")
|
||||
if h := hyphae.ByName(hyphaName); h.Exists {
|
||||
log.Println("Serving", h.TextPath)
|
||||
@ -103,6 +115,9 @@ func handlerText(w http.ResponseWriter, rq *http.Request) {
|
||||
// handlerBinary serves binary part of the hypha.
|
||||
func handlerBinary(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
hyphaName := util.HyphaNameFromRq(rq, "binary")
|
||||
if h := hyphae.ByName(hyphaName); h.Exists {
|
||||
log.Println("Serving", h.BinaryPath)
|
||||
@ -121,6 +136,9 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
|
||||
openGraph string
|
||||
u = user.FromRequest(rq)
|
||||
)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if h.Exists {
|
||||
fileContentsT, errT := os.ReadFile(h.TextPath)
|
||||
_, errB := os.Stat(h.BinaryPath)
|
||||
|
18
web/stuff.go
18
web/stuff.go
@ -30,13 +30,20 @@ func initStuff() {
|
||||
|
||||
// handlerList shows a list of all hyphae in the wiki in random order.
|
||||
func handlerList(w http.ResponseWriter, rq *http.Request) {
|
||||
u := user.FromRequest(rq)
|
||||
if shown := u.ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
util.PrepareRq(rq)
|
||||
util.HTTP200Page(w, views.BaseHTML("List of pages", views.HyphaListHTML(), user.FromRequest(rq)))
|
||||
util.HTTP200Page(w, views.BaseHTML("List of pages", views.HyphaListHTML(), u))
|
||||
}
|
||||
|
||||
// handlerReindex reindexes all hyphae by checking the wiki storage directory anew.
|
||||
func handlerReindex(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if ok := user.CanProceed(rq, "reindex"); !ok {
|
||||
httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be an admin to reindex hyphae.")
|
||||
log.Println("Rejected", rq.URL)
|
||||
@ -54,6 +61,9 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) {
|
||||
// See https://mycorrhiza.wiki/hypha/configuration/header
|
||||
func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
if ok := user.CanProceed(rq, "update-header-links"); !ok {
|
||||
httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be a moderator to update header links.")
|
||||
log.Println("Rejected", rq.URL)
|
||||
@ -66,6 +76,9 @@ func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
|
||||
// handlerRandom redirects to a random hypha.
|
||||
func handlerRandom(w http.ResponseWriter, rq *http.Request) {
|
||||
util.PrepareRq(rq)
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
var (
|
||||
randomHyphaName string
|
||||
amountOfHyphae = hyphae.Count()
|
||||
@ -87,6 +100,9 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) {
|
||||
|
||||
// handlerAbout shows a summary of wiki's software.
|
||||
func handlerAbout(w http.ResponseWriter, rq *http.Request) {
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html;charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, err := io.WriteString(w, views.BaseHTML("About "+cfg.WikiName, views.AboutHTML(), user.FromRequest(rq)))
|
||||
|
@ -54,6 +54,9 @@ func handlerStyle(w http.ResponseWriter, rq *http.Request) {
|
||||
}
|
||||
|
||||
func handlerUserList(w http.ResponseWriter, rq *http.Request) {
|
||||
if shown := user.FromRequest(rq).ShowLockMaybe(w, rq); shown {
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(views.BaseHTML("User list", views.UserListHTML(), user.FromRequest(rq))))
|
||||
|
Loading…
Reference in New Issue
Block a user