diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 5fc71ce..4ae4500 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -26,7 +26,6 @@ checksum: name_template: 'checksums.txt' kos: - repository: codeberg.org/rimgo/rimgo - id: rimgo tags: - '{{.Version}}' - latest @@ -36,16 +35,6 @@ kos: - linux/amd64 - linux/arm64 sbom: none - - repository: codeberg.org/video-prize-ranch/rimgo - id: vpr_rimgo - tags: - - latest - bare: true - preserve_import_paths: false - platforms: - - linux/amd64 - - linux/arm64 - sbom: none gitea_urls: api: https://codeberg.org/api/v1 download: https://codeberg.org diff --git a/go.mod b/go.mod index e7b8121..306e4c9 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,8 @@ require ( github.com/PuerkitoBio/goquery v1.8.1 github.com/aymerick/raymond v2.0.2+incompatible github.com/dustin/go-humanize v1.0.1 - github.com/gofiber/fiber/v2 v2.51.0 - github.com/gofiber/template/handlebars/v2 v2.1.6 + github.com/gofiber/fiber/v2 v2.52.0 + github.com/gofiber/template/handlebars/v2 v2.1.7 github.com/joho/godotenv v1.5.1 github.com/microcosm-cc/bluemonday v1.0.26 github.com/patrickmn/go-cache v2.1.0+incompatible @@ -18,14 +18,14 @@ require ( ) require ( - github.com/andybalholm/brotli v1.0.6 // indirect + github.com/andybalholm/brotli v1.1.0 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/gofiber/template v1.8.2 // indirect github.com/gofiber/utils v1.1.0 // indirect - github.com/google/uuid v1.4.0 // indirect + github.com/google/uuid v1.5.0 // indirect github.com/gorilla/css v1.0.1 // indirect - github.com/klauspost/compress v1.17.3 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect @@ -37,7 +37,7 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index a5ccce9..6d57427 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAc github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= @@ -13,20 +15,28 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= +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/handlebars/v2 v2.1.6 h1:+z9S2/L3RZueHpRtjxyMGpNHKIMUYkvyVEGHQrau+Po= github.com/gofiber/template/handlebars/v2 v2.1.6/go.mod h1:Kes9qTj4iD73xj1bq94HjJHNqhUhuyWpLvs9fyH5aMs= +github.com/gofiber/template/handlebars/v2 v2.1.7 h1:ybU8cd2hqk6kU23WdOOhDkXS/Pg6W1J6CAgndjWxA7g= +github.com/gofiber/template/handlebars/v2 v2.1.7/go.mod h1:Az/uETJ7nFZQ0NWS37Qja1zG9dOsoI6lG2iagJCWHhY= 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.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA= github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= 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= @@ -74,6 +84,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 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= @@ -89,6 +101,10 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= diff --git a/main.go b/main.go index 5c81495..24ab8f1 100644 --- a/main.go +++ b/main.go @@ -52,14 +52,7 @@ func main() { code = e.Code } - err = ctx.Status(code).Render("errors/error", fiber.Map{ - "err": err, - }) - if err != nil { - return ctx.Status(fiber.StatusInternalServerError).SendString("Internal Server Error") - } - - return nil + return utils.RenderError(ctx, code) }, }) @@ -77,14 +70,23 @@ func main() { app.Get("/errors/429", func(c *fiber.Ctx) error { return c.Render("errors/429", nil) }) + app.Get("/errors/429/img", func(c *fiber.Ctx) error { + return c.Redirect("/static/img/error-429.png") + }) app.Get("/errors/404", func(c *fiber.Ctx) error { return c.Render("errors/404", nil) }) + app.Get("/errors/404/img", func(c *fiber.Ctx) error { + return c.Redirect("/static/img/error-404.png") + }) app.Get("/errors/error", func(c *fiber.Ctx) error { return c.Render("errors/error", fiber.Map{ "err": "Test error", }) }) + app.Get("/errors/error/img", func(c *fiber.Ctx) error { + return c.Redirect("/static/img/error-generic.png") + }) } else { app.Use("/static", filesystem.New(filesystem.Config{ MaxAge: 2592000, @@ -135,5 +137,8 @@ func main() { app.Get("/:postID", pages.HandlePost) app.Get("/:postID/embed", pages.HandleEmbed) - app.Listen(utils.Config.Addr + ":" + utils.Config.Port) + err := app.Listen(utils.Config.Addr + ":" + utils.Config.Port) + if err != nil { + fmt.Println(err) + } } diff --git a/pages/embed.go b/pages/embed.go index d48844d..bf25e8b 100644 --- a/pages/embed.go +++ b/pages/embed.go @@ -23,10 +23,10 @@ func HandleEmbed(c *fiber.Ctx) error { post, err = ApiClient.FetchMedia(c.Params("postID")) } if err != nil && err.Error() == "ratelimited by imgur" { - return c.Status(429).Render("errors/429", nil) + return utils.RenderError(c, 429) } if err != nil && post.Id == "" && strings.Contains(err.Error(), "404") { - return c.Status(404).Render("errors/404", nil) + return utils.RenderError(c, 404) } if err != nil { return err diff --git a/pages/media.go b/pages/media.go index 34208db..1e9df14 100644 --- a/pages/media.go +++ b/pages/media.go @@ -11,22 +11,25 @@ import ( func HandleMedia(c *fiber.Ctx) error { c.Set("Cache-Control", "public,max-age=31557600") + c.Set("Content-Security-Policy", "default-src 'none'; style-src 'self'; img-src 'self'") if strings.HasPrefix(c.Path(), "/stack") { - return handleMedia(c, "https://i.stack.imgur.com/" + strings.ReplaceAll(c.Params("baseName"), "stack/", "") + "." + c.Params("extension")) + return handleMedia(c, "https://i.stack.imgur.com/"+strings.ReplaceAll(c.Params("baseName"), "stack/", "")+"."+c.Params("extension")) } else { - return handleMedia(c, "https://i.imgur.com/" + c.Params("baseName") + "." + c.Params("extension")) + return handleMedia(c, "https://i.imgur.com/"+c.Params("baseName")+"."+c.Params("extension")) } } func HandleUserCover(c *fiber.Ctx) error { c.Set("Cache-Control", "public,max-age=604800") - return handleMedia(c, "https://imgur.com/user/" + c.Params("userID") + "/cover?maxwidth=2560") -}; + c.Set("Content-Security-Policy", "default-src 'none'") + return handleMedia(c, "https://imgur.com/user/"+c.Params("userID")+"/cover?maxwidth=2560") +} func HandleUserAvatar(c *fiber.Ctx) error { c.Set("Cache-Control", "public,max-age=604800") - return handleMedia(c, "https://imgur.com/user/" + c.Params("userID") + "/avatar") -}; + c.Set("Content-Security-Policy", "default-src 'none'") + return handleMedia(c, "https://imgur.com/user/"+c.Params("userID")+"/avatar") +} func handleMedia(c *fiber.Ctx, url string) error { utils.SetHeaders(c) @@ -45,7 +48,7 @@ func handleMedia(c *fiber.Ctx, url string) error { if err != nil { return err } - + utils.SetReqHeaders(req) if c.Get("Range") != "" { @@ -57,23 +60,18 @@ func handleMedia(c *fiber.Ctx, url string) error { return err } - c.Status(res.StatusCode) - if res.StatusCode == 404 { - return c.Render("errors/404", fiber.Map{ - "path": c.Path(), - }) + if res.StatusCode == 404 || strings.Contains(res.Request.URL.String(), "error/404") { + return utils.RenderError(c, 404) } else if res.StatusCode == 429 { - return c.Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } - + c.Set("Accept-Ranges", "bytes") - c.Set("Content-Type", res.Header.Get("Content-Type")); + c.Set("Content-Type", res.Header.Get("Content-Type")) c.Set("Content-Length", res.Header.Get("Content-Length")) if res.Header.Get("Content-Range") != "" { c.Set("Content-Range", res.Header.Get("Content-Range")) } - + return c.SendStream(res.Body) -} \ No newline at end of file +} diff --git a/pages/post.go b/pages/post.go index c283064..978bd97 100644 --- a/pages/post.go +++ b/pages/post.go @@ -48,12 +48,10 @@ func HandlePost(c *fiber.Ctx) error { post, err = ApiClient.FetchMedia(c.Params("postID")) } if err != nil && err.Error() == "ratelimited by imgur" { - return c.Status(429).Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil && post.Id == "" && strings.Contains(err.Error(), "404") { - return c.Status(404).Render("errors/404", nil) + return utils.RenderError(c, 404) } if err != nil { return err diff --git a/pages/privacy.go b/pages/privacy.go index 2d7851b..c2591e9 100644 --- a/pages/privacy.go +++ b/pages/privacy.go @@ -9,6 +9,7 @@ import ( func HandlePrivacy(c *fiber.Ctx) error { utils.SetHeaders(c) c.Set("X-Frame-Options", "DENY") + c.Set("Content-Security-Policy", "default-src 'none'; form-action 'self'; style-src 'self'; img-src 'self'; manifest-src 'self'; block-all-mixed-content") return c.Render("privacy", fiber.Map{ "config": utils.Config, diff --git a/pages/tag.go b/pages/tag.go index de086ec..145ef49 100644 --- a/pages/tag.go +++ b/pages/tag.go @@ -25,21 +25,19 @@ func HandleTag(c *fiber.Ctx) error { tag, err := ApiClient.FetchTag(c.Params("tag"), c.Query("sort"), page) if err != nil && err.Error() == "ratelimited by imgur" { - return c.Status(429).Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil { return err } if tag.Display == "" { - return c.Status(404).Render("errors/404", nil) + return utils.RenderError(c, 404) } return c.Render("tag", fiber.Map{ - "tag": tag, - "page": page, - "nextPage": pageNumber + 1, - "prevPage": pageNumber - 1, + "tag": tag, + "page": page, + "nextPage": pageNumber + 1, + "prevPage": pageNumber - 1, }) } diff --git a/pages/user.go b/pages/user.go index 42da651..3a07e57 100644 --- a/pages/user.go +++ b/pages/user.go @@ -25,23 +25,19 @@ func HandleUser(c *fiber.Ctx) error { user, err := ApiClient.FetchUser(c.Params("userID")) if err != nil && err.Error() == "ratelimited by imgur" { - return c.Status(429).Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil { return err } if user.Username == "" { - return c.Status(404).Render("errors/404", nil) + return utils.RenderError(c, 404) } submissions, err := ApiClient.FetchSubmissions(c.Params("userID"), "newest", page) if err != nil && err.Error() == "ratelimited by imgur" { c.Status(429) - return c.Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil { return err @@ -64,23 +60,19 @@ func HandleUserComments(c *fiber.Ctx) error { user, err := ApiClient.FetchUser(c.Params("userID")) if err != nil && err.Error() == "ratelimited by imgur" { - return c.Status(429).Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil { return err } if user.Username == "" { - return c.Status(404).Render("errors/404", nil) + return utils.RenderError(c, 404) } comments, err := ApiClient.FetchUserComments(c.Params("userID")) if err != nil && err.Error() == "ratelimited by imgur" { c.Status(429) - return c.Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil { return err @@ -110,23 +102,18 @@ func HandleUserFavorites(c *fiber.Ctx) error { user, err := ApiClient.FetchUser(c.Params("userID")) if err != nil && err.Error() == "ratelimited by imgur" { - return c.Status(429).Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil { return err } if user.Username == "" { - return c.Status(404).Render("errors/404", nil) + return utils.RenderError(c, 404) } favorites, err := ApiClient.FetchUserFavorites(c.Params("userID"), "newest", page) if err != nil && err.Error() == "ratelimited by imgur" { - c.Status(429) - return c.Render("errors/429", fiber.Map{ - "path": c.Path(), - }) + return utils.RenderError(c, 429) } if err != nil { return err diff --git a/static/favicon/site.webmanifest b/static/favicon/site.webmanifest index 3b119b2..0d77e4c 100644 --- a/static/favicon/site.webmanifest +++ b/static/favicon/site.webmanifest @@ -1,6 +1,7 @@ { "name": "rimgo", "short_name": "rimgo", + "start_url": "/", "icons": [ { "src": "/static/favicon/android-chrome-192x192.png", diff --git a/static/img/error-404.png b/static/img/error-404.png new file mode 100644 index 0000000..4cfa417 Binary files /dev/null and b/static/img/error-404.png differ diff --git a/static/img/error-429.png b/static/img/error-429.png new file mode 100644 index 0000000..c8eba31 Binary files /dev/null and b/static/img/error-429.png differ diff --git a/static/img/error-generic.png b/static/img/error-generic.png new file mode 100644 index 0000000..869ddb8 Binary files /dev/null and b/static/img/error-generic.png differ diff --git a/utils/error.go b/utils/error.go new file mode 100644 index 0000000..4da0629 --- /dev/null +++ b/utils/error.go @@ -0,0 +1,25 @@ +package utils + +import ( + "strconv" + "strings" + + "codeberg.org/rimgo/rimgo/static" + "github.com/gofiber/fiber/v2" +) + +func RenderError(c *fiber.Ctx, code int) error { + if !strings.Contains(c.Get("Accept"), "html") && c.Params("extension") != "" { + codeStr := "generic" + if code != 0 { + codeStr = strconv.Itoa(code) + } + img, _ := static.GetFiles().ReadFile("img/error-" + codeStr + ".png") + c.Set("Content-Type", "image/png") + return c.Status(code).Send(img) + } else { + return c.Status(code).Render("errors/" + strconv.Itoa(code), fiber.Map{ + "path": c.Path(), + }) + } +} \ No newline at end of file