123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- package main
- import (
- "errors"
- "log"
- "net"
- "net/http"
- "os"
- "strings"
- "time"
- config "codeberg.org/vnpower/pixivfe/v2/core/config"
- "codeberg.org/vnpower/pixivfe/v2/pages"
- "codeberg.org/vnpower/pixivfe/v2/serve"
- "github.com/goccy/go-json"
- "github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2/middleware/cache"
- "github.com/gofiber/fiber/v2/middleware/compress"
- "github.com/gofiber/fiber/v2/middleware/limiter"
- "github.com/gofiber/fiber/v2/middleware/logger"
- "github.com/gofiber/fiber/v2/middleware/recover"
- "github.com/gofiber/fiber/v2/utils"
- "github.com/gofiber/template/jet/v2"
- )
- func CanRequestSkipLimiter(c *fiber.Ctx) bool {
- path := c.Path()
- return strings.HasPrefix(path, "/assets/") ||
- strings.HasPrefix(path, "/css/") ||
- strings.HasPrefix(path, "/js/") ||
- strings.HasPrefix(path, "/proxy/s.pximg.net/")
- }
- func main() {
- config.SetupStorage()
- config.GlobalServerConfig.InitializeConfig()
- engine := jet.New("./views", ".jet.html")
- if config.GlobalServerConfig.InDevelopment {
- engine.Reload(true)
- }
- engine.AddFuncMap(serve.GetTemplateFunctions())
- server := fiber.New(fiber.Config{
- AppName: "PixivFE",
- DisableStartupMessage: true,
- Views: engine,
- Prefork: false,
- JSONEncoder: json.Marshal,
- JSONDecoder: json.Unmarshal,
- ViewsLayout: "layout",
- EnableTrustedProxyCheck: true,
- TrustedProxies: []string{"0.0.0.0/0"},
- ProxyHeader: fiber.HeaderXForwardedFor,
- ErrorHandler: func(c *fiber.Ctx, err error) error {
- // Status code defaults to 500
- code := fiber.StatusInternalServerError
- // // Retrieve the custom status code if it's a *fiber.Error
- // var e *fiber.Error
- // if errors.As(err, &e) {
- // code = e.Code
- // }
- // Send custom error page
- err = c.Status(code).Render("pages/error", fiber.Map{"Title": "Error", "Error": err})
- if err != nil {
- // In case the SendFile fails
- return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
- }
- // Return from handler
- return nil
- },
- })
- server.Use(logger.New(
- logger.Config{
- Format: "${time} ${ip} | ${path}\n",
- Next: CanRequestSkipLimiter,
- },
- ))
- if !config.GlobalServerConfig.InDevelopment {
- server.Use(cache.New(
- cache.Config{
- Next: func(c *fiber.Ctx) bool {
- resp_code := c.Response().StatusCode()
- if resp_code < 200 || resp_code >= 300 {
- return true
- }
- // Disable cache for settings page
- return strings.Contains(c.Path(), "/settings") || c.Path() == "/"
- },
- Expiration: 5 * time.Minute,
- CacheControl: true,
- KeyGenerator: func(c *fiber.Ctx) string {
- return utils.CopyString(c.OriginalURL())
- },
- },
- ))
- }
- server.Use(recover.New())
- server.Use(compress.New(compress.Config{
- Level: compress.LevelBestSpeed, // 1
- }))
- server.Use(limiter.New(limiter.Config{
- Next: CanRequestSkipLimiter,
- Expiration: 30 * time.Second,
- Max: config.GlobalServerConfig.RequestLimit,
- LimiterMiddleware: limiter.SlidingWindow{},
- LimitReached: func(c *fiber.Ctx) error {
- log.Println("Limit Reached!")
- return errors.New("Woah! You are going too fast! I'll have to keep an eye on you.")
- },
- }))
- // Global headers (from GotHub)
- server.Use(func(c *fiber.Ctx) error {
- c.Set("X-Frame-Options", "SAMEORIGIN")
- c.Set("X-XSS-Protection", "1; mode=block")
- c.Set("X-Content-Type-Options", "nosniff")
- c.Set("Referrer-Policy", "no-referrer")
- c.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
- return c.Next()
- })
- server.Use(func(c *fiber.Ctx) error {
- baseURL := c.BaseURL() + c.OriginalURL()
- c.Bind(fiber.Map{"BaseURL": baseURL})
- return c.Next()
- })
- server.Static("/favicon.ico", "./views/assets/favicon.ico")
- server.Static("/css/", "./views/css")
- server.Static("/assets/", "./views/assets")
- server.Static("/robots.txt", "./views/assets/robots.txt")
- // Routes
- server.Get("/", pages.IndexPage)
- server.Get("/about", pages.AboutPage)
- server.Get("/newest", pages.NewestPage)
- server.Get("/discovery", pages.DiscoveryPage)
- server.Get("/ranking", pages.RankingPage)
- server.Get("/rankingCalendar", pages.RankingCalendarPage)
- server.Post("/rankingCalendar", pages.RankingCalendarPicker)
- server.Get("/users/:id/:category?", pages.UserPage)
- server.Get("/artworks/:id/", pages.ArtworkPage).Name("artworks")
- server.Get("/artworks-multi/:ids/", pages.ArtworkMultiPage)
- // Settings group
- settings := server.Group("/settings")
- settings.Get("/", pages.SettingsPage)
- settings.Post("/:type", pages.SettingsPost)
- // Personal group
- self := server.Group("/self")
- self.Get("/", pages.LoginUserPage)
- self.Get("/followingWorks", pages.FollowingWorksPage)
- self.Get("/bookmarks", pages.LoginBookmarkPage)
- self.Post("/addBookmark/:id", pages.AddBookmarkRoute)
- self.Post("/deleteBookmark/:id", pages.DeleteBookmarkRoute)
- self.Post("/like/:id", pages.LikeRoute)
- server.Get("/tags/:name", pages.TagPage)
- server.Post("/tags",
- func(c *fiber.Ctx) error {
- name := c.FormValue("name")
- return c.Redirect("/tags/"+name, http.StatusFound)
- })
- // Legacy illust URL
- server.Get("/member_illust.php", func(c *fiber.Ctx) error {
- return c.Redirect("/artworks/" + c.Query("illust_id"))
- })
- // Proxy routes
- proxy := server.Group("/proxy")
- proxy.Get("/i.pximg.net/*", pages.IPximgProxy)
- proxy.Get("/s.pximg.net/*", pages.SPximgProxy)
- proxy.Get("/ugoira.com/*", pages.UgoiraProxy)
- // Listen
- if config.GlobalServerConfig.UnixSocket != "" {
- ln, err := net.Listen("unix", config.GlobalServerConfig.UnixSocket)
- if err != nil {
- log.Fatalf("Failed to run on Unix socket. %s", err)
- os.Exit(1)
- }
- log.Printf("PixivFE is running on %v\n", config.GlobalServerConfig.UnixSocket)
- server.Listener(ln)
- } else {
- addr := config.GlobalServerConfig.Host + ":" + config.GlobalServerConfig.Port
- log.Printf("PixivFE is running on %v\n", addr)
- // note: string concatenation is very flaky
- server.Listen(addr)
- }
- }
|