diff --git a/INSTANCES.md b/INSTANCES.md index 0e9f011..65cefa3 100644 --- a/INSTANCES.md +++ b/INSTANCES.md @@ -1,6 +1,6 @@ # List of known instances -* [tr.chaotic.ninja](https://tr.chaotic.ninja) - * Location: Germany - * Cloudflare: No - +| Name | Cloudflare? | Country | URL | Engines supported | +|---------------------------------------------|-------------|---------|--------------------------|-------------------| +| Chaotic Ninja Communication Network Limited | No | Germany | https://tr.chaotic.ninja | Google, Reverso | +| | | | | | diff --git a/README.md b/README.md index f2bf040..d51287c 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,8 @@ A privacy friendly frontend to multiple translation engines. ### Other projects * [Mozhi](https://codeberg.org/aryak/mozhi), also a fork of SimplyTranslate + +### Credits +* SimpleWeb (fattalion, ManeraKai, metalune) +* [VnPower](https://vnpower.exozy.me) ([PixivFE](https://codeberg.org/VnPower/PixivFE) developer), for most of the stuff I borrowed from his project, as we both use [Fiber](https://gofiber.io) +* [z3bra](http://z3bra.org), for the `.ini` loading function, and privilege dropping from [Partage](http://z3bra.org/partage/) diff --git a/cmd/mai/main.go b/cmd/mai/main.go index f573eee..247c933 100644 --- a/cmd/mai/main.go +++ b/cmd/mai/main.go @@ -2,12 +2,14 @@ package main import ( "bytes" - "fmt" + "errors" + "log" "net/http" "net/url" "os" "time" "runtime" + "strings" "syscall" "marisa.chaotic.ninja/mai" @@ -17,6 +19,7 @@ import ( "github.com/gofiber/fiber/v2/middleware/favicon" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/limiter" + "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/template/html/v2" ) var ( @@ -25,10 +28,17 @@ var ( username string ) var conf struct { + danmaku int listen string staticpath string tmplpath string } +func MaiSkipLimiter(c *fiber.Ctx) bool { + // Paths listed here are not considered for rate limiting + path := c.Path() + return strings.HasPrefix(path, "/static") || + strings.HasPrefix(path, "/docs") +} func main() { parseFlags() @@ -37,6 +47,7 @@ func main() { } // Default settings + conf.danmaku = 10 conf.listen = "127.0.0.1:5000" conf.staticpath = "./static" conf.tmplpath = "./views" @@ -44,8 +55,7 @@ func main() { if username != "" { uid, gid, err := usergroupids(username, groupname) if err != nil { - fmt.Println(err) - os.Exit(1) + log.Fatal(err) } syscall.Setuid(uid) syscall.Setgid(gid) @@ -54,39 +64,52 @@ func main() { engine := html.New(conf.tmplpath, ".html") engine.AddFunc("inc", func(i int) int { return i + 1 }) - app := fiber.New( + server := fiber.New( fiber.Config{ AppName: "Mai", ProxyHeader: fiber.HeaderXForwardedFor, TrustedProxies: []string{"0.0.0.0/0"}, ServerHeader: "Mai (using Fiber v2.x)", Views: engine, - }) + ErrorHandler: func(c *fiber.Ctx, err error) error { + code := fiber.StatusInternalServerError + err = c.Status(code).Render("pages/error", fiber.Map{"Title": "Error", "Error": err}) + if err != nil { + return c.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") + } + return nil + }, + }) - app.Use(favicon.New( + server.Use(recover.New()) + + server.Use(favicon.New( favicon.Config{ File: conf.staticpath + "/favicon.ico", }, )) - app.Use(logger.New( + server.Use(logger.New( logger.Config{ Format: "==> ${ip}:${port} ${status} - ${method} ${path}\n", DisableColors: true, Output: os.Stdout, + Next: MaiSkipLimiter, }, )) - app.Use(limiter.New(limiter.Config{ - Max: 10, - Expiration: 180 * time.Second, + server.Use(limiter.New(limiter.Config{ + Next: MaiSkipLimiter, + Max: conf.danmaku, + Expiration: 30 * time.Second, + LimiterMiddleware: limiter.SlidingWindow{}, LimitReached: func(c *fiber.Ctx) error { - return c.SendStatus(429) - return c.SendFile(conf.tmplpath + "/429.html") + log.Println("Limit reached!") + return errors.New("You're firing way too many danmaku really fast!") }, })) - app.All("/", func(c *fiber.Ctx) error { + server.All("/", func(c *fiber.Ctx) error { engine := c.Cookies("engine") if c.Query("engine") != "" { engine = c.Query("engine") @@ -185,7 +208,7 @@ func main() { }) }) - app.All("/api/translate", func(c *fiber.Ctx) error { + server.All("/api/translate", func(c *fiber.Ctx) error { from := "" to := "" engine := "" @@ -216,7 +239,7 @@ func main() { } }) - app.Get("/api/source_languages", func(c *fiber.Ctx) error { + server.Get("/api/source_languages", func(c *fiber.Ctx) error { engine := c.Query("engine") if _, ok := engines.Engines[engine]; !ok || engine == "" { engine = "google" @@ -228,7 +251,7 @@ func main() { } }) - app.Get("/api/target_languages", func(c *fiber.Ctx) error { + server.Get("/api/target_languages", func(c *fiber.Ctx) error { engine := c.Query("engine") if _, ok := engines.Engines[engine]; !ok || engine == "" { engine = "google" @@ -240,7 +263,7 @@ func main() { } }) - app.Get("/api/tts", func(c *fiber.Ctx) error { + server.Get("/api/tts", func(c *fiber.Ctx) error { engine := c.Query("engine") if _, ok := engines.Engines[engine]; !ok || engine == "" { engine = "google" @@ -267,17 +290,25 @@ func main() { } } }) - app.Get("/robots.txt", func(c *fiber.Ctx) error { + + server.Get("/robots.txt", func(c *fiber.Ctx) error { return c.SendString("User-Agent: *\nDisallow: /\n") }) - app.Get("/version", func(c *fiber.Ctx) error { + + server.Get("/toomanyrequests", func(c *fiber.Ctx) error { + return c.SendFile(conf.tmplpath + "/429.html") + return c.SendStatus(429) + }) + + server.Get("/version", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{ "fiberversion": fiber.Version, "goversion": runtime.Version(), "maiversion": mai.FullVersion(), }) }) - app.Post("/switchlanguages", func(c *fiber.Ctx) error { + + server.Post("/switchlanguages", func(c *fiber.Ctx) error { if c.Cookies("from") != "" { fromCookie := new(fiber.Cookie) fromCookie.Name = "from" @@ -294,11 +325,13 @@ func main() { } return c.Redirect("/") }) - app.Static("/static", conf.staticpath, fiber.Static{ + server.Static("/static", conf.staticpath, fiber.Static{ Compress: true, ByteRange: true, Browse: true, }) - app.Static("/docs", "./docs", fiber.Static{}) - app.Listen(conf.listen) + + server.Static("/docs", "./docs", fiber.Static{}) + + server.Listen(conf.listen) } diff --git a/cmd/mai/readconf.go b/cmd/mai/readconf.go index c184797..e7b03ba 100644 --- a/cmd/mai/readconf.go +++ b/cmd/mai/readconf.go @@ -10,6 +10,7 @@ func readConf(file string) error { if err != nil { return err } + conf.danmaku, _ = cfg.Section("mai").Key("danmaku").Int() conf.listen = cfg.Section("mai").Key("listen").String() conf.staticpath = cfg.Section("mai").Key("static").String() conf.tmplpath = cfg.Section("mai").Key("templates").String() diff --git a/go.mod b/go.mod index 7d36c77..dd72b4b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/PuerkitoBio/goquery v1.8.1 - github.com/gofiber/fiber/v2 v2.50.0 + github.com/gofiber/fiber/v2 v2.52.0 github.com/gofiber/template/html/v2 v2.0.5 gopkg.in/ini.v1 v1.67.0 ) @@ -14,18 +14,18 @@ require ( github.com/andybalholm/cascadia v1.3.1 // indirect github.com/gofiber/template v1.8.2 // indirect github.com/gofiber/utils v1.1.0 // indirect - github.com/google/uuid v1.3.1 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/tinylib/msgp v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.50.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.13.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.15.0 // indirect ) diff --git a/go.sum b/go.sum index 3a9ed17..20a7cda 100644 --- a/go.sum +++ b/go.sum @@ -5,23 +5,23 @@ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/gofiber/fiber/v2 v2.50.0 h1:ia0JaB+uw3GpNSCR5nvC5dsaxXjRU5OEu36aytx+zGw= -github.com/gofiber/fiber/v2 v2.50.0/go.mod h1:21eytvay9Is7S6z+OgPi7c7n4++tnClWmhpimVHMimw= +github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE= +github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/template v1.8.2 h1:PIv9s/7Uq6m+Fm2MDNd20pAFFKt5wWs7ZBd8iV9pWwk= github.com/gofiber/template v1.8.2/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= github.com/gofiber/template/html/v2 v2.0.5 h1:BKLJ6Qr940NjntbGmpO3zVa4nFNGDCi/IfUiDB9OC20= github.com/gofiber/template/html/v2 v2.0.5/go.mod h1:RCF14eLeQDCSUPp0IGc2wbSSDv6yt+V54XB/+Unz+LM= github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= @@ -35,8 +35,8 @@ github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= -github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -50,8 +50,8 @@ golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -65,8 +65,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= diff --git a/mai.ini.5 b/mai.ini.5 index 7f05709..98d3066 100644 --- a/mai.ini.5 +++ b/mai.ini.5 @@ -7,13 +7,16 @@ .Sh OPTIONS .Ss [mai] section .Bl -tag -width 11n -.It listen +.It danmaku (int) +Control the maximum amount of requests +before a ratelimit happens +.It listen (string) HTTP port for the server to listen. Default is "localhost:5000" -.It static +.It static (string) Directory where the static resources are located. Default is "./static" -.It templates +.It templates (string) Directory where the templates are located. Default is "./views" .El diff --git a/views/429.html b/views/429.html deleted file mode 100644 index b1d4f9d..0000000 --- a/views/429.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Too many requests - - - - - - - -

You have triggered a 429 error

-

Try again later

- - - [image source] - -
- - diff --git a/views/pages/error.html b/views/pages/error.html new file mode 100644 index 0000000..d1a1c3d --- /dev/null +++ b/views/pages/error.html @@ -0,0 +1,48 @@ + + + + + Mai | Error + + + + + + + +

Error

+

+ Something has happened and these may be the following causes: +

+

+

    +
  1. You might have reached the rate limit
  2. +
  3. There was an internal server error
  4. +
  5. Any other client error such as a 404 Not Found
  6. +
+

+ + +

+ [image source] +

+ +
+ +