1
0
mirror of https://github.com/lus/pasty.git synced 2023-08-10 21:13:09 +03:00
pasty/internal/web/web.go

151 lines
4.3 KiB
Go
Raw Normal View History

package web
import (
2020-08-23 17:22:20 +03:00
"encoding/json"
2021-04-15 20:26:17 +03:00
"path/filepath"
"strings"
routing "github.com/fasthttp/router"
2021-04-15 21:15:42 +03:00
"github.com/lus/pasty/internal/config"
2021-04-15 20:26:17 +03:00
"github.com/lus/pasty/internal/static"
2021-06-21 21:09:40 +03:00
"github.com/lus/pasty/internal/storage"
2021-04-15 20:26:17 +03:00
v1 "github.com/lus/pasty/internal/web/controllers/v1"
v2 "github.com/lus/pasty/internal/web/controllers/v2"
2020-08-24 00:07:07 +03:00
"github.com/ulule/limiter/v3"
limitFasthttp "github.com/ulule/limiter/v3/drivers/middleware/fasthttp"
"github.com/ulule/limiter/v3/drivers/store/memory"
"github.com/valyala/fasthttp"
)
2020-08-23 17:44:06 +03:00
// Serve serves the web resources
func Serve() error {
// Create the router
router := routing.New()
2020-08-23 15:13:17 +03:00
// Define the 404 handler
router.NotFound = func(ctx *fasthttp.RequestCtx) {
ctx.SetStatusCode(fasthttp.StatusNotFound)
ctx.SetBodyString("not found")
}
// Route the frontend requests
frontend := frontendHandler()
2021-06-21 21:09:40 +03:00
raw := rawHandler()
2020-08-23 15:13:17 +03:00
router.GET("/{path:*}", func(ctx *fasthttp.RequestCtx) {
path := string(ctx.Path())
2020-08-24 19:32:14 +03:00
if !strings.HasPrefix(path, "/api") && (strings.Count(path, "/") == 1 || strings.HasPrefix(path, "/assets")) {
if strings.HasPrefix(path, "/assets/js/") {
ctx.SetContentType("text/javascript")
}
2020-08-23 15:13:17 +03:00
frontend(ctx)
return
2021-06-21 21:09:40 +03:00
} else if strings.HasSuffix(strings.TrimSuffix(path, "/"), "/raw") {
raw(ctx)
return
2020-08-23 15:13:17 +03:00
}
router.NotFound(ctx)
})
2020-08-24 00:07:07 +03:00
// Set up the rate limiter
2021-04-15 21:15:42 +03:00
rate, err := limiter.NewRateFromFormatted(config.Current.RateLimit)
2020-08-24 00:07:07 +03:00
if err != nil {
return err
}
rateLimiter := limiter.New(memory.NewStore(), rate)
rateLimiterMiddleware := limitFasthttp.NewMiddleware(rateLimiter)
// Route the API endpoints
apiRoute := router.Group("/api")
{
v1Route := apiRoute.Group("/v1")
{
2020-08-23 17:40:06 +03:00
v1Route.GET("/info", func(ctx *fasthttp.RequestCtx) {
jsonData, _ := json.Marshal(map[string]interface{}{
"version": static.Version,
"deletionTokens": config.Current.ModificationTokens,
2020-08-23 17:40:06 +03:00
})
ctx.SetBody(jsonData)
})
2020-08-24 00:07:07 +03:00
v1.InitializePastesController(v1Route.Group("/pastes"), rateLimiterMiddleware)
}
v2Route := apiRoute.Group("/v2")
{
pasteLifetime := int64(-1)
if config.Current.AutoDelete.Enabled {
pasteLifetime = config.Current.AutoDelete.Lifetime.Milliseconds()
}
v2Route.GET("/info", func(ctx *fasthttp.RequestCtx) {
jsonData, _ := json.Marshal(map[string]interface{}{
"version": static.Version,
"modificationTokens": config.Current.ModificationTokens,
"reports": config.Current.Reports.Reports,
"pasteLifetime": pasteLifetime,
})
ctx.SetBody(jsonData)
})
v2.InitializePastesController(v2Route.Group("/pastes"), rateLimiterMiddleware)
}
}
2020-08-23 17:22:20 +03:00
// Route the hastebin documents route if hastebin support is enabled
2021-04-15 21:15:42 +03:00
if config.Current.HastebinSupport {
2020-08-24 00:07:07 +03:00
router.POST("/documents", rateLimiterMiddleware.Handle(v1.HastebinSupportHandler))
2020-08-23 17:22:20 +03:00
}
2020-08-23 17:44:06 +03:00
// Serve the web resources
2020-08-23 15:13:17 +03:00
return (&fasthttp.Server{
2020-08-23 21:29:18 +03:00
Handler: func(ctx *fasthttp.RequestCtx) {
// Add the CORS headers
ctx.Response.Header.Set("Access-Control-Allow-Methods", "GET,POST,DELETE,OPTIONS")
ctx.Response.Header.Set("Access-Control-Allow-Origin", "*")
// Call the router handler
router.Handler(ctx)
},
Logger: new(nilLogger),
2021-04-15 21:15:42 +03:00
}).ListenAndServe(config.Current.WebAddress)
2020-08-23 15:13:17 +03:00
}
// frontendHandler handles the frontend routing
func frontendHandler() fasthttp.RequestHandler {
// Create the file server
fs := &fasthttp.FS{
Root: static.TempFrontendPath,
2020-08-23 15:13:17 +03:00
IndexNames: []string{"index.html"},
CacheDuration: 0,
}
fs.PathNotFound = func(ctx *fasthttp.RequestCtx) {
2020-08-24 19:32:14 +03:00
if strings.HasPrefix(string(ctx.Path()), "/assets") {
ctx.SetStatusCode(fasthttp.StatusNotFound)
ctx.SetBodyString("not found")
return
}
2020-08-23 15:13:17 +03:00
ctx.SendFile(filepath.Join(fs.Root, "index.html"))
}
return fs.NewRequestHandler()
}
2021-06-21 21:09:40 +03:00
func rawHandler() fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
path := string(ctx.Path())
pathSanitized := strings.TrimPrefix(strings.TrimSuffix(path, "/"), "/")
pasteID := strings.TrimSuffix(pathSanitized, "/raw")
paste, err := storage.Current.Get(pasteID)
if err != nil {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
ctx.SetBodyString(err.Error())
return
}
if paste == nil {
ctx.SetStatusCode(fasthttp.StatusNotFound)
ctx.SetBodyString("paste not found")
return
}
ctx.SetBodyString(paste.Content)
}
}