2021-05-09 11:09:27 +00:00
|
|
|
// Package web contains web handlers and initialization stuff.
|
2021-05-09 10:42:12 +00:00
|
|
|
package web
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2021-06-12 13:51:28 +00:00
|
|
|
"mime"
|
2021-05-09 10:42:12 +00:00
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
|
2021-07-15 17:46:35 +00:00
|
|
|
"github.com/gorilla/mux"
|
|
|
|
|
2021-05-11 10:14:00 +00:00
|
|
|
"github.com/bouncepaw/mycorrhiza/cfg"
|
2021-09-06 17:46:34 +00:00
|
|
|
"github.com/bouncepaw/mycorrhiza/l18n"
|
2021-06-12 13:51:28 +00:00
|
|
|
"github.com/bouncepaw/mycorrhiza/static"
|
2021-05-09 10:42:12 +00:00
|
|
|
"github.com/bouncepaw/mycorrhiza/user"
|
2021-05-11 10:14:00 +00:00
|
|
|
"github.com/bouncepaw/mycorrhiza/util"
|
2021-05-09 10:42:12 +00:00
|
|
|
"github.com/bouncepaw/mycorrhiza/views"
|
|
|
|
)
|
|
|
|
|
2021-06-12 13:51:28 +00:00
|
|
|
var stylesheets = []string{"default.css", "custom.css"}
|
|
|
|
|
2021-05-09 11:09:27 +00:00
|
|
|
// httpErr is used by many handlers to signal errors in a compact way.
|
2022-02-19 16:42:32 +00:00
|
|
|
func httpErr(w http.ResponseWriter, lc *l18n.Localizer, status int, name, errMsg string) {
|
2021-06-23 15:44:27 +00:00
|
|
|
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
2021-05-09 10:42:12 +00:00
|
|
|
w.WriteHeader(status)
|
|
|
|
fmt.Fprint(
|
|
|
|
w,
|
|
|
|
views.BaseHTML(
|
2022-02-19 16:42:32 +00:00
|
|
|
"Error",
|
2021-05-09 10:42:12 +00:00
|
|
|
fmt.Sprintf(
|
2021-09-06 17:46:34 +00:00
|
|
|
`<main class="main-width"><p>%s. <a href="/hypha/%s">%s<a></p></main>`,
|
2021-05-09 10:42:12 +00:00
|
|
|
errMsg,
|
|
|
|
name,
|
2021-09-06 17:46:34 +00:00
|
|
|
lc.Get("ui.error_go_back"),
|
2021-05-09 10:42:12 +00:00
|
|
|
),
|
2021-09-29 14:56:17 +00:00
|
|
|
lc,
|
2021-05-09 10:42:12 +00:00
|
|
|
user.EmptyUser(),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func handlerStyle(w http.ResponseWriter, rq *http.Request) {
|
2021-06-23 15:35:33 +00:00
|
|
|
w.Header().Set("Content-Type", mime.TypeByExtension(".css"))
|
2021-06-12 13:51:28 +00:00
|
|
|
for _, name := range stylesheets {
|
|
|
|
file, err := static.FS.Open(name)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
2021-05-09 10:42:12 +00:00
|
|
|
}
|
2021-06-12 13:51:28 +00:00
|
|
|
io.Copy(w, file)
|
|
|
|
file.Close()
|
2021-05-09 10:42:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func handlerUserList(w http.ResponseWriter, rq *http.Request) {
|
2021-09-06 17:46:34 +00:00
|
|
|
lc := l18n.FromRequest(rq)
|
2021-06-23 15:44:27 +00:00
|
|
|
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
|
2021-05-09 10:42:12 +00:00
|
|
|
w.WriteHeader(http.StatusOK)
|
2021-09-06 17:46:34 +00:00
|
|
|
w.Write([]byte(views.BaseHTML(lc.Get("ui.users_title"), views.UserListHTML(lc), lc, user.FromRequest(rq))))
|
2021-05-09 10:42:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func handlerRobotsTxt(w http.ResponseWriter, rq *http.Request) {
|
2021-06-23 15:44:27 +00:00
|
|
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
|
|
|
|
|
|
|
file, err := static.FS.Open("robots.txt")
|
2021-07-25 13:16:34 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
2021-06-23 15:44:27 +00:00
|
|
|
}
|
|
|
|
io.Copy(w, file)
|
|
|
|
file.Close()
|
2021-05-09 10:42:12 +00:00
|
|
|
}
|
|
|
|
|
2021-10-01 17:34:56 +00:00
|
|
|
// Handler initializes and returns the HTTP router based on the configuration.
|
2021-07-15 17:46:35 +00:00
|
|
|
func Handler() http.Handler {
|
2021-07-15 18:14:05 +00:00
|
|
|
router := mux.NewRouter()
|
|
|
|
router.Use(func(next http.Handler) http.Handler {
|
2021-07-15 18:58:27 +00:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, rq *http.Request) {
|
|
|
|
util.PrepareRq(rq)
|
2022-02-18 08:57:15 +00:00
|
|
|
w.Header().Add("Content-Security-Policy",
|
|
|
|
"default-src 'self' telegram.org *.telegram.org; "+
|
|
|
|
"img-src * data:; media-src *; style-src *; font-src * data:")
|
2021-07-15 18:58:27 +00:00
|
|
|
next.ServeHTTP(w, rq)
|
2021-07-15 17:46:35 +00:00
|
|
|
})
|
|
|
|
})
|
2021-07-15 18:58:27 +00:00
|
|
|
router.StrictSlash(true)
|
2021-07-15 17:46:35 +00:00
|
|
|
|
2021-07-15 18:58:27 +00:00
|
|
|
// Public routes. They're always accessible regardless of the user status.
|
2021-07-15 18:14:05 +00:00
|
|
|
initAuth(router)
|
|
|
|
router.HandleFunc("/robots.txt", handlerRobotsTxt)
|
|
|
|
router.HandleFunc("/static/style.css", handlerStyle)
|
|
|
|
router.PathPrefix("/static/").
|
|
|
|
Handler(http.StripPrefix("/static/", http.FileServer(http.FS(static.FS))))
|
|
|
|
|
2021-07-15 18:58:27 +00:00
|
|
|
// Wiki routes. They may be locked or restricted.
|
2021-07-15 18:14:05 +00:00
|
|
|
wikiRouter := router.PathPrefix("").Subrouter()
|
|
|
|
wikiRouter.Use(func(next http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, rq *http.Request) {
|
|
|
|
user := user.FromRequest(rq)
|
|
|
|
if !user.ShowLockMaybe(w, rq) {
|
|
|
|
next.ServeHTTP(w, rq)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2021-07-15 17:46:35 +00:00
|
|
|
|
2021-07-15 18:14:05 +00:00
|
|
|
initReaders(wikiRouter)
|
|
|
|
initMutators(wikiRouter)
|
|
|
|
initHistory(wikiRouter)
|
|
|
|
initStuff(wikiRouter)
|
|
|
|
initSearch(wikiRouter)
|
2021-08-31 17:27:52 +00:00
|
|
|
initBacklinks(wikiRouter)
|
2022-03-20 08:21:59 +00:00
|
|
|
initCategories(wikiRouter)
|
2021-05-09 11:09:27 +00:00
|
|
|
|
2021-07-15 18:58:27 +00:00
|
|
|
// Admin routes.
|
|
|
|
if cfg.UseAuth {
|
|
|
|
adminRouter := wikiRouter.PathPrefix("/admin").Subrouter()
|
|
|
|
adminRouter.Use(groupMiddleware("admin"))
|
|
|
|
initAdmin(adminRouter)
|
|
|
|
}
|
|
|
|
|
2021-06-12 13:51:28 +00:00
|
|
|
// Miscellaneous
|
2021-07-15 18:14:05 +00:00
|
|
|
wikiRouter.HandleFunc("/user-list", handlerUserList)
|
2021-06-12 13:51:28 +00:00
|
|
|
|
|
|
|
// Index page
|
2021-07-15 18:14:05 +00:00
|
|
|
wikiRouter.HandleFunc("/", func(w http.ResponseWriter, rq *http.Request) {
|
2021-07-15 17:46:35 +00:00
|
|
|
// Let's pray it never fails
|
|
|
|
addr, _ := url.Parse("/hypha/" + cfg.HomeHypha)
|
2021-07-15 18:14:05 +00:00
|
|
|
rq.URL = addr
|
|
|
|
handlerHypha(w, rq)
|
2021-05-09 10:42:12 +00:00
|
|
|
})
|
2021-07-15 17:46:35 +00:00
|
|
|
|
2021-07-15 18:14:05 +00:00
|
|
|
return router
|
2021-05-09 10:42:12 +00:00
|
|
|
}
|
2021-07-15 18:58:27 +00:00
|
|
|
|
|
|
|
func groupMiddleware(group string) func(http.Handler) http.Handler {
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, rq *http.Request) {
|
|
|
|
if cfg.UseAuth && user.CanProceed(rq, group) {
|
|
|
|
next.ServeHTTP(w, rq)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: handle this better. Merge this code with all other
|
|
|
|
// authorization code in this project.
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusForbidden)
|
|
|
|
io.WriteString(w, "403 forbidden")
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|