PixivFEからいくつか輸入しました

リクエストリミッターを構成可能にする
マニュアルページを更新する
エラーページを改善する
GoFiber v2.52.0 へのアップデート

Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>

git-svn-id: https://svn.yakumo.dev/yakumo.izuru/mai/trunk@70 e410bdd4-646f-c54f-a7ce-fffcc4f439ae
This commit is contained in:
yakumo.izuru 2024-02-12 02:42:11 +00:00
parent 439e8b9e02
commit 29e1e11c63
9 changed files with 141 additions and 72 deletions

View File

@ -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 |
| | | | | |

View File

@ -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/)

View File

@ -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)
}

View File

@ -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()

14
go.mod
View File

@ -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
)

28
go.sum
View File

@ -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=

View File

@ -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

View File

@ -1,21 +0,0 @@
<!DOCTYPE HTML PUBLIC "//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="/static/style.css">
<title>Too many requests</title>
</head>
<body>
<table border="1" align="center">
<thead>
<img src="/static/displeased_mai.png">
</thead>
<tbody>
<p>You have triggered a 429 error</p>
<p>Try again later</p>
</tbody>
<tfoot>
<i><a href="https://deviantart.com/view/1017571065">[image source]</a></i>
</tfoot>
</table>
</body>
</html>

48
views/pages/error.html Normal file
View File

@ -0,0 +1,48 @@
<!DOCTYPE HTML PUBLIC "//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style type="text/css">
body {
background-color: #282c37;
color: rgb(234, 136, 50);
text-align: center;
}
a {
color: rgb(34, 36, 42);
}
p {
color: rgb(221, 209, 203);
}
img {
height: 640px;
width: 480px;
}
</style>
<title>Mai | Error</title>
</head>
<body>
<table border="1">
<thead>
<img src="/static/displeased_mai.png">
</thead>
<tbody>
<h2>Error</h2>
<p>
Something has happened and these may be the following causes:
</p>
<p>
<ol>
<li>You might have reached the rate limit</li>
<li>There was an internal server error</li>
<li>Any other client error such as a 404 Not Found</li>
</ol>
</p>
</tbody>
<tfoot>
<p>
<a href="https://deviantart.com/view/1017571065">[image source]</a>
</p>
</tfoot>
</table>
</body>
</html>