mirror of
https://github.com/thomiceli/opengist.git
synced 2025-01-09 01:52:40 +00:00
wip
This commit is contained in:
parent
d75840eba8
commit
68c6f26385
5 changed files with 172 additions and 176 deletions
|
@ -32,9 +32,7 @@ func (h Handler) toEchoHandler() echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chain applies middleware to a handler without conversion to echo types
|
func chain(h Handler, middleware ...Middleware) Handler {
|
||||||
func Chain(h Handler, middleware ...Middleware) Handler {
|
|
||||||
// Apply middleware in reverse order
|
|
||||||
for i := len(middleware) - 1; i >= 0; i-- {
|
for i := len(middleware) - 1; i >= 0; i-- {
|
||||||
h = middleware[i](h)
|
h = middleware[i](h)
|
||||||
}
|
}
|
|
@ -1,14 +1,17 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/labstack/echo/v4/middleware"
|
"github.com/labstack/echo/v4/middleware"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/thomiceli/opengist/internal/auth"
|
||||||
"github.com/thomiceli/opengist/internal/config"
|
"github.com/thomiceli/opengist/internal/config"
|
||||||
"github.com/thomiceli/opengist/internal/db"
|
"github.com/thomiceli/opengist/internal/db"
|
||||||
"github.com/thomiceli/opengist/internal/i18n"
|
"github.com/thomiceli/opengist/internal/i18n"
|
||||||
"github.com/thomiceli/opengist/internal/web/context"
|
"github.com/thomiceli/opengist/internal/web/context"
|
||||||
|
"github.com/thomiceli/opengist/internal/web/handler"
|
||||||
"golang.org/x/text/cases"
|
"golang.org/x/text/cases"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
@ -27,7 +30,7 @@ func (s *Server) useCustomContext() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) RegisterMiddlewares() {
|
func (s *Server) registerMiddlewares() {
|
||||||
s.echo.Use(Middleware(dataInit).ToEcho())
|
s.echo.Use(Middleware(dataInit).ToEcho())
|
||||||
s.echo.Use(Middleware(locale).ToEcho())
|
s.echo.Use(Middleware(locale).ToEcho())
|
||||||
|
|
||||||
|
@ -61,6 +64,28 @@ func (s *Server) RegisterMiddlewares() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) errorHandler(err error, ctx echo.Context) {
|
||||||
|
var httpErr *echo.HTTPError
|
||||||
|
if errors.As(err, &httpErr) {
|
||||||
|
acceptJson := strings.Contains(ctx.Request().Header.Get("Accept"), "application/json")
|
||||||
|
data := ctx.Request().Context().Value("data").(echo.Map)
|
||||||
|
data["error"] = err
|
||||||
|
if acceptJson {
|
||||||
|
if err := ctx.JSON(httpErr.Code, httpErr); err != nil {
|
||||||
|
log.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ctx.Render(httpErr.Code, "error", data); err != nil {
|
||||||
|
log.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Fatal().Err(err).Send()
|
||||||
|
}
|
||||||
|
|
||||||
func dataInit(next Handler) Handler {
|
func dataInit(next Handler) Handler {
|
||||||
return func(ctx *context.OGContext) error {
|
return func(ctx *context.OGContext) error {
|
||||||
ctx.SetData("loadStartTime", time.Now())
|
ctx.SetData("loadStartTime", time.Now())
|
||||||
|
@ -96,6 +121,77 @@ func dataInit(next Handler) Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writePermission(next Handler) Handler {
|
||||||
|
return func(ctx *context.OGContext) error {
|
||||||
|
gist := ctx.GetData("gist")
|
||||||
|
user := ctx.User
|
||||||
|
if !gist.(*db.Gist).CanWrite(user) {
|
||||||
|
return ctx.RedirectTo("/" + gist.(*db.Gist).User.Username + "/" + gist.(*db.Gist).Identifier())
|
||||||
|
}
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminPermission(next Handler) Handler {
|
||||||
|
return func(ctx *context.OGContext) error {
|
||||||
|
user := ctx.User
|
||||||
|
if user == nil || !user.IsAdmin {
|
||||||
|
return ctx.NotFound("User not found")
|
||||||
|
}
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func logged(next Handler) Handler {
|
||||||
|
return func(ctx *context.OGContext) error {
|
||||||
|
user := ctx.User
|
||||||
|
if user != nil {
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
return ctx.RedirectTo("/all")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inMFASession(next Handler) Handler {
|
||||||
|
return func(ctx *context.OGContext) error {
|
||||||
|
sess := ctx.GetSession()
|
||||||
|
_, ok := sess.Values["mfaID"].(uint)
|
||||||
|
if !ok {
|
||||||
|
return ctx.ErrorRes(400, ctx.Tr("error.not-in-mfa-session"), nil)
|
||||||
|
}
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeCheckRequireLogin(isSingleGistAccess bool) Middleware {
|
||||||
|
return func(next Handler) Handler {
|
||||||
|
return func(ctx *context.OGContext) error {
|
||||||
|
if user := ctx.User; user != nil {
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
allow, err := auth.ShouldAllowUnauthenticatedGistAccess(handler.ContextAuthInfo{Context: ctx}, isSingleGistAccess)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Failed to check if unauthenticated access is allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !allow {
|
||||||
|
ctx.AddFlash(ctx.Tr("flash.auth.must-be-logged-in"), "error")
|
||||||
|
return ctx.RedirectTo("/login")
|
||||||
|
}
|
||||||
|
return next(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRequireLogin(next Handler) Handler {
|
||||||
|
return makeCheckRequireLogin(false)(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
func noRouteFound(ctx *context.OGContext) error {
|
||||||
|
return ctx.NotFound("Page not found")
|
||||||
|
}
|
||||||
|
|
||||||
func locale(next Handler) Handler {
|
func locale(next Handler) Handler {
|
||||||
return func(ctx *context.OGContext) error {
|
return func(ctx *context.OGContext) error {
|
||||||
// Check URL arguments
|
// Check URL arguments
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
gojson "encoding/json"
|
gojson "encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/thomiceli/opengist/internal/config"
|
"github.com/thomiceli/opengist/internal/config"
|
||||||
"github.com/thomiceli/opengist/internal/db"
|
"github.com/thomiceli/opengist/internal/db"
|
||||||
|
@ -25,6 +26,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Template struct {
|
||||||
|
templates *template.Template
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Template) Render(w io.Writer, name string, data interface{}, _ echo.Context) error {
|
||||||
|
return t.templates.ExecuteTemplate(w, name, data)
|
||||||
|
}
|
||||||
|
|
||||||
var re = regexp.MustCompile("[^a-z0-9]+")
|
var re = regexp.MustCompile("[^a-z0-9]+")
|
||||||
|
|
||||||
func (s *Server) setFuncMap() {
|
func (s *Server) setFuncMap() {
|
||||||
|
@ -189,7 +198,7 @@ func (s *Server) setFuncMap() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseManifestEntries() {
|
func (s *Server) parseManifestEntries() {
|
||||||
file, err := public.Files.Open("manifest.json")
|
file, err := public.Files.Open("manifest.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal().Err(err).Msg("Failed to open manifest.json")
|
log.Fatal().Err(err).Msg("Failed to open manifest.json")
|
||||||
|
|
|
@ -15,12 +15,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) setupRoutes() {
|
func (s *Server) registerRoutes() {
|
||||||
r := NewRouter(s.echo.Group(""))
|
r := NewRouter(s.echo.Group(""))
|
||||||
|
|
||||||
// Web based routes
|
|
||||||
{
|
{
|
||||||
|
|
||||||
r.GET("/", handler.Create, logged)
|
r.GET("/", handler.Create, logged)
|
||||||
r.POST("/", handler.ProcessCreate, logged)
|
r.POST("/", handler.ProcessCreate, logged)
|
||||||
r.POST("/preview", handler.Preview, logged)
|
r.POST("/preview", handler.Preview, logged)
|
||||||
|
@ -45,38 +43,42 @@ func (s *Server) setupRoutes() {
|
||||||
r.GET("/mfa", handler.Mfa, inMFASession)
|
r.GET("/mfa", handler.Mfa, inMFASession)
|
||||||
r.POST("/mfa/totp/assertion", handler.AssertTotp, inMFASession)
|
r.POST("/mfa/totp/assertion", handler.AssertTotp, inMFASession)
|
||||||
|
|
||||||
r.GET("/settings", handler.UserSettings, logged)
|
sA := r.SubGroup("/settings")
|
||||||
r.POST("/settings/email", handler.EmailProcess, logged)
|
|
||||||
r.DELETE("/settings/account", handler.AccountDeleteProcess, logged)
|
|
||||||
r.POST("/settings/ssh-keys", handler.SshKeysProcess, logged)
|
|
||||||
r.DELETE("/settings/ssh-keys/:id", handler.SshKeysDelete, logged)
|
|
||||||
r.DELETE("/settings/passkeys/:id", handler.PasskeyDelete, logged)
|
|
||||||
r.PUT("/settings/password", handler.PasswordProcess, logged)
|
|
||||||
r.PUT("/settings/username", handler.UsernameProcess, logged)
|
|
||||||
r.GET("/settings/totp/generate", handler.BeginTotp, logged)
|
|
||||||
r.POST("/settings/totp/generate", handler.FinishTotp, logged)
|
|
||||||
r.DELETE("/settings/totp", handler.DisableTotp, logged)
|
|
||||||
r.POST("/settings/totp/regenerate", handler.RegenerateTotpRecoveryCodes, logged)
|
|
||||||
|
|
||||||
g2 := r.SubGroup("/admin-panel")
|
|
||||||
{
|
{
|
||||||
g2.Use(adminPermission)
|
sA.Use(logged)
|
||||||
g2.GET("", handler.AdminIndex)
|
sA.GET("", handler.UserSettings)
|
||||||
g2.GET("/users", handler.AdminUsers)
|
sA.POST("/email", handler.EmailProcess)
|
||||||
g2.POST("/users/:user/delete", handler.AdminUserDelete)
|
sA.DELETE("/account", handler.AccountDeleteProcess)
|
||||||
g2.GET("/gists", handler.AdminGists)
|
sA.POST("/ssh-keys", handler.SshKeysProcess)
|
||||||
g2.POST("/gists/:gist/delete", handler.AdminGistDelete)
|
sA.DELETE("/ssh-keys/:id", handler.SshKeysDelete)
|
||||||
g2.GET("/invitations", handler.AdminInvitations)
|
sA.DELETE("/passkeys/:id", handler.PasskeyDelete)
|
||||||
g2.POST("/invitations", handler.AdminInvitationsCreate)
|
sA.PUT("/password", handler.PasswordProcess)
|
||||||
g2.POST("/invitations/:id/delete", handler.AdminInvitationsDelete)
|
sA.PUT("/username", handler.UsernameProcess)
|
||||||
g2.POST("/sync-fs", handler.AdminSyncReposFromFS)
|
sA.GET("/totp/generate", handler.BeginTotp)
|
||||||
g2.POST("/sync-db", handler.AdminSyncReposFromDB)
|
sA.POST("/totp/generate", handler.FinishTotp)
|
||||||
g2.POST("/gc-repos", handler.AdminGcRepos)
|
sA.DELETE("/totp", handler.DisableTotp)
|
||||||
g2.POST("/sync-previews", handler.AdminSyncGistPreviews)
|
sA.POST("/totp/regenerate", handler.RegenerateTotpRecoveryCodes)
|
||||||
g2.POST("/reset-hooks", handler.AdminResetHooks)
|
}
|
||||||
g2.POST("/index-gists", handler.AdminIndexGists)
|
|
||||||
g2.GET("/configuration", handler.AdminConfig)
|
sB := r.SubGroup("/admin-panel")
|
||||||
g2.PUT("/set-config", handler.AdminSetConfig)
|
{
|
||||||
|
sB.Use(adminPermission)
|
||||||
|
sB.GET("", handler.AdminIndex)
|
||||||
|
sB.GET("/users", handler.AdminUsers)
|
||||||
|
sB.POST("/users/:user/delete", handler.AdminUserDelete)
|
||||||
|
sB.GET("/gists", handler.AdminGists)
|
||||||
|
sB.POST("/gists/:gist/delete", handler.AdminGistDelete)
|
||||||
|
sB.GET("/invitations", handler.AdminInvitations)
|
||||||
|
sB.POST("/invitations", handler.AdminInvitationsCreate)
|
||||||
|
sB.POST("/invitations/:id/delete", handler.AdminInvitationsDelete)
|
||||||
|
sB.POST("/sync-fs", handler.AdminSyncReposFromFS)
|
||||||
|
sB.POST("/sync-db", handler.AdminSyncReposFromDB)
|
||||||
|
sB.POST("/gc-repos", handler.AdminGcRepos)
|
||||||
|
sB.POST("/sync-previews", handler.AdminSyncGistPreviews)
|
||||||
|
sB.POST("/reset-hooks", handler.AdminResetHooks)
|
||||||
|
sB.POST("/index-gists", handler.AdminIndexGists)
|
||||||
|
sB.GET("/configuration", handler.AdminConfig)
|
||||||
|
sB.PUT("/set-config", handler.AdminSetConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.C.HttpGit {
|
if config.C.HttpGit {
|
||||||
|
@ -95,24 +97,24 @@ func (s *Server) setupRoutes() {
|
||||||
r.GET("/:user/liked", handler.AllGists, checkRequireLogin)
|
r.GET("/:user/liked", handler.AllGists, checkRequireLogin)
|
||||||
r.GET("/:user/forked", handler.AllGists, checkRequireLogin)
|
r.GET("/:user/forked", handler.AllGists, checkRequireLogin)
|
||||||
|
|
||||||
g3 := r.SubGroup("/:user/:gistname")
|
sC := r.SubGroup("/:user/:gistname")
|
||||||
{
|
{
|
||||||
g3.Use(makeCheckRequireLogin(true), GistInit)
|
sC.Use(makeCheckRequireLogin(true), GistInit)
|
||||||
g3.GET("", handler.GistIndex)
|
sC.GET("", handler.GistIndex)
|
||||||
g3.GET("/rev/:revision", handler.GistIndex)
|
sC.GET("/rev/:revision", handler.GistIndex)
|
||||||
g3.GET("/revisions", handler.Revisions)
|
sC.GET("/revisions", handler.Revisions)
|
||||||
g3.GET("/archive/:revision", handler.DownloadZip)
|
sC.GET("/archive/:revision", handler.DownloadZip)
|
||||||
g3.POST("/visibility", handler.EditVisibility, logged, writePermission)
|
sC.POST("/visibility", handler.EditVisibility, logged, writePermission)
|
||||||
g3.POST("/delete", handler.DeleteGist, logged, writePermission)
|
sC.POST("/delete", handler.DeleteGist, logged, writePermission)
|
||||||
g3.GET("/raw/:revision/:file", handler.RawFile)
|
sC.GET("/raw/:revision/:file", handler.RawFile)
|
||||||
g3.GET("/download/:revision/:file", handler.DownloadFile)
|
sC.GET("/download/:revision/:file", handler.DownloadFile)
|
||||||
g3.GET("/edit", handler.Edit, logged, writePermission)
|
sC.GET("/edit", handler.Edit, logged, writePermission)
|
||||||
g3.POST("/edit", handler.ProcessCreate, logged, writePermission)
|
sC.POST("/edit", handler.ProcessCreate, logged, writePermission)
|
||||||
g3.POST("/like", handler.Like, logged)
|
sC.POST("/like", handler.Like, logged)
|
||||||
g3.GET("/likes", handler.Likes, checkRequireLogin)
|
sC.GET("/likes", handler.Likes, checkRequireLogin)
|
||||||
g3.POST("/fork", handler.Fork, logged)
|
sC.POST("/fork", handler.Fork, logged)
|
||||||
g3.GET("/forks", handler.Forks, checkRequireLogin)
|
sC.GET("/forks", handler.Forks, checkRequireLogin)
|
||||||
g3.PUT("/checkbox", handler.Checkbox, logged, writePermission)
|
sC.PUT("/checkbox", handler.Checkbox, logged, writePermission)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +163,7 @@ func (r *Router) SubGroup(prefix string, m ...Middleware) *Router {
|
||||||
for i, mw := range m {
|
for i, mw := range m {
|
||||||
mw := mw // capture for closure
|
mw := mw // capture for closure
|
||||||
echoMiddleware[i] = func(next echo.HandlerFunc) echo.HandlerFunc {
|
echoMiddleware[i] = func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return Chain(func(c *context.OGContext) error {
|
return chain(func(c *context.OGContext) error {
|
||||||
return next(c)
|
return next(c)
|
||||||
}, mw).toEchoHandler()
|
}, mw).toEchoHandler()
|
||||||
}
|
}
|
||||||
|
@ -169,37 +171,35 @@ func (r *Router) SubGroup(prefix string, m ...Middleware) *Router {
|
||||||
return NewRouter(r.Group.Group(prefix, echoMiddleware...))
|
return NewRouter(r.Group.Group(prefix, echoMiddleware...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route registration methods
|
|
||||||
func (r *Router) GET(path string, h Handler, m ...Middleware) {
|
func (r *Router) GET(path string, h Handler, m ...Middleware) {
|
||||||
r.Group.GET(path, Chain(h, m...).toEchoHandler())
|
r.Group.GET(path, chain(h, m...).toEchoHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) POST(path string, h Handler, m ...Middleware) {
|
func (r *Router) POST(path string, h Handler, m ...Middleware) {
|
||||||
r.Group.POST(path, Chain(h, m...).toEchoHandler())
|
r.Group.POST(path, chain(h, m...).toEchoHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) PUT(path string, h Handler, m ...Middleware) {
|
func (r *Router) PUT(path string, h Handler, m ...Middleware) {
|
||||||
r.Group.PUT(path, Chain(h, m...).toEchoHandler())
|
r.Group.PUT(path, chain(h, m...).toEchoHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) DELETE(path string, h Handler, m ...Middleware) {
|
func (r *Router) DELETE(path string, h Handler, m ...Middleware) {
|
||||||
r.Group.DELETE(path, Chain(h, m...).toEchoHandler())
|
r.Group.DELETE(path, chain(h, m...).toEchoHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) PATCH(path string, h Handler, m ...Middleware) {
|
func (r *Router) PATCH(path string, h Handler, m ...Middleware) {
|
||||||
r.Group.PATCH(path, Chain(h, m...).toEchoHandler())
|
r.Group.PATCH(path, chain(h, m...).toEchoHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) Any(path string, h Handler, m ...Middleware) {
|
func (r *Router) Any(path string, h Handler, m ...Middleware) {
|
||||||
r.Group.Any(path, Chain(h, m...).toEchoHandler())
|
r.Group.Any(path, chain(h, m...).toEchoHandler())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use registers middleware for the entire router group
|
|
||||||
func (r *Router) Use(middleware ...Middleware) {
|
func (r *Router) Use(middleware ...Middleware) {
|
||||||
for _, m := range middleware {
|
for _, m := range middleware {
|
||||||
m := m // capture for closure
|
m := m // capture for closure
|
||||||
r.Group.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
r.Group.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return Chain(func(c *context.OGContext) error {
|
return chain(func(c *context.OGContext) error {
|
||||||
return next(c)
|
return next(c)
|
||||||
}, m).toEchoHandler()
|
}, m).toEchoHandler()
|
||||||
})
|
})
|
||||||
|
|
|
@ -3,30 +3,16 @@ package server
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/thomiceli/opengist/internal/utils"
|
"github.com/thomiceli/opengist/internal/utils"
|
||||||
"github.com/thomiceli/opengist/internal/web/context"
|
|
||||||
"github.com/thomiceli/opengist/internal/web/handler"
|
|
||||||
"html/template"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/thomiceli/opengist/internal/auth"
|
|
||||||
"github.com/thomiceli/opengist/internal/config"
|
"github.com/thomiceli/opengist/internal/config"
|
||||||
"github.com/thomiceli/opengist/internal/db"
|
|
||||||
"github.com/thomiceli/opengist/internal/i18n"
|
"github.com/thomiceli/opengist/internal/i18n"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Template struct {
|
|
||||||
templates *template.Template
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Template) Render(w io.Writer, name string, data interface{}, _ echo.Context) error {
|
|
||||||
return t.templates.ExecuteTemplate(w, name, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
echo *echo.Echo
|
echo *echo.Echo
|
||||||
flashStore *sessions.CookieStore // session store for flash messages
|
flashStore *sessions.CookieStore // session store for flash messages
|
||||||
|
@ -50,17 +36,17 @@ func NewServer(isDev bool, sessionsPath string, ignoreCsrf bool) *Server {
|
||||||
log.Fatal().Err(err).Msg("Failed to load locales")
|
log.Fatal().Err(err).Msg("Failed to load locales")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.RegisterMiddlewares()
|
s.registerMiddlewares()
|
||||||
s.setFuncMap()
|
s.setFuncMap()
|
||||||
s.echo.HTTPErrorHandler = s.errorHandler
|
s.echo.HTTPErrorHandler = s.errorHandler
|
||||||
|
|
||||||
e.Validator = utils.NewValidator()
|
e.Validator = utils.NewValidator()
|
||||||
|
|
||||||
if !s.dev {
|
if !s.dev {
|
||||||
parseManifestEntries()
|
s.parseManifestEntries()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.setupRoutes()
|
s.registerRoutes()
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
@ -83,96 +69,3 @@ func (s *Server) Stop() {
|
||||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
s.echo.ServeHTTP(w, r)
|
s.echo.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writePermission(next Handler) Handler {
|
|
||||||
return func(ctx *context.OGContext) error {
|
|
||||||
gist := ctx.GetData("gist")
|
|
||||||
user := ctx.User
|
|
||||||
if !gist.(*db.Gist).CanWrite(user) {
|
|
||||||
return ctx.RedirectTo("/" + gist.(*db.Gist).User.Username + "/" + gist.(*db.Gist).Identifier())
|
|
||||||
}
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func adminPermission(next Handler) Handler {
|
|
||||||
return func(ctx *context.OGContext) error {
|
|
||||||
user := ctx.User
|
|
||||||
if user == nil || !user.IsAdmin {
|
|
||||||
return ctx.NotFound("User not found")
|
|
||||||
}
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func logged(next Handler) Handler {
|
|
||||||
return func(ctx *context.OGContext) error {
|
|
||||||
user := ctx.User
|
|
||||||
if user != nil {
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
return ctx.RedirectTo("/all")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func inMFASession(next Handler) Handler {
|
|
||||||
return func(ctx *context.OGContext) error {
|
|
||||||
sess := ctx.GetSession()
|
|
||||||
_, ok := sess.Values["mfaID"].(uint)
|
|
||||||
if !ok {
|
|
||||||
return ctx.ErrorRes(400, ctx.Tr("error.not-in-mfa-session"), nil)
|
|
||||||
}
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeCheckRequireLogin(isSingleGistAccess bool) Middleware {
|
|
||||||
return func(next Handler) Handler {
|
|
||||||
return func(ctx *context.OGContext) error {
|
|
||||||
if user := ctx.User; user != nil {
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
allow, err := auth.ShouldAllowUnauthenticatedGistAccess(handler.ContextAuthInfo{Context: ctx}, isSingleGistAccess)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal().Err(err).Msg("Failed to check if unauthenticated access is allowed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !allow {
|
|
||||||
ctx.AddFlash(ctx.Tr("flash.auth.must-be-logged-in"), "error")
|
|
||||||
return ctx.RedirectTo("/login")
|
|
||||||
}
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkRequireLogin(next Handler) Handler {
|
|
||||||
return makeCheckRequireLogin(false)(next)
|
|
||||||
}
|
|
||||||
|
|
||||||
func noRouteFound(ctx *context.OGContext) error {
|
|
||||||
return ctx.NotFound("Page not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) errorHandler(err error, ctx echo.Context) {
|
|
||||||
var httpErr *echo.HTTPError
|
|
||||||
if errors.As(err, &httpErr) {
|
|
||||||
acceptJson := strings.Contains(ctx.Request().Header.Get("Accept"), "application/json")
|
|
||||||
data := ctx.Request().Context().Value("data").(echo.Map)
|
|
||||||
data["error"] = err
|
|
||||||
if acceptJson {
|
|
||||||
if err := ctx.JSON(httpErr.Code, httpErr); err != nil {
|
|
||||||
log.Fatal().Err(err).Send()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ctx.Render(httpErr.Code, "error", data); err != nil {
|
|
||||||
log.Fatal().Err(err).Send()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Fatal().Err(err).Send()
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue