2023-09-11 23:26:50 +02:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"mime/multipart"
|
|
|
|
"net/http"
|
2023-09-13 17:12:03 +02:00
|
|
|
"unicode/utf8"
|
2023-09-11 23:26:50 +02:00
|
|
|
|
|
|
|
"git.myrkvi.com/myrkvi/bin/global"
|
|
|
|
"git.myrkvi.com/myrkvi/bin/models"
|
|
|
|
"git.myrkvi.com/myrkvi/bin/utils"
|
|
|
|
"git.myrkvi.com/myrkvi/bin/views/components"
|
|
|
|
"git.myrkvi.com/myrkvi/bin/views/pages"
|
|
|
|
"github.com/alecthomas/chroma/lexers"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
|
|
)
|
|
|
|
|
|
|
|
func GetNewHandler(c echo.Context) error {
|
|
|
|
values := c.QueryParams()
|
|
|
|
wantsText := values.Has("text")
|
|
|
|
return utils.RenderComponents(c, http.StatusOK, pages.NewFull(wantsText))
|
|
|
|
}
|
|
|
|
|
|
|
|
func PostNewHandler(c echo.Context) error {
|
|
|
|
file, err := c.FormFile("file")
|
|
|
|
text := c.FormValue("text")
|
|
|
|
|
|
|
|
name := c.FormValue("name")
|
|
|
|
description := c.FormValue("description")
|
|
|
|
lang := c.FormValue("lang")
|
2023-09-12 22:30:58 +02:00
|
|
|
ip := c.RealIP()
|
2023-09-11 23:26:50 +02:00
|
|
|
|
2023-09-13 21:02:11 +02:00
|
|
|
if tooMany, period := ipHasTooManyUses(ip); tooMany {
|
|
|
|
return utils.RenderErrorToast(c,
|
|
|
|
fmt.Sprintf("This IP address has uploaded too many files in the %s", period),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-09-11 23:26:50 +02:00
|
|
|
if (file == nil || err != nil) && text == "" {
|
|
|
|
return utils.RenderErrorToast(c, "file or text must be provided")
|
|
|
|
}
|
|
|
|
|
|
|
|
code, adminCode, err := utils.GenerateCodes()
|
|
|
|
if err != nil {
|
|
|
|
return utils.RenderErrorToast(c, "server-side error occurred")
|
|
|
|
}
|
|
|
|
|
|
|
|
if file != nil {
|
2023-09-13 17:12:03 +02:00
|
|
|
// Don't bother trying to convert the contents into a string if it is too large.
|
|
|
|
if file.Size > 1024*1024 {
|
|
|
|
return utils.RenderErrorToast(c, "file cannot be larger than 1 MiB")
|
|
|
|
}
|
|
|
|
|
2023-09-11 23:26:50 +02:00
|
|
|
text, err = getTextFromFile(file)
|
|
|
|
if name == "" {
|
|
|
|
name = file.Filename
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return utils.RenderErrorToast(c, "server-side error occurred")
|
|
|
|
}
|
|
|
|
}
|
2023-09-13 17:12:03 +02:00
|
|
|
if len([]byte(text)) > 1024*1024 {
|
|
|
|
return utils.RenderErrorToast(c, "file cannot be larger than 1 MiB")
|
|
|
|
}
|
|
|
|
|
|
|
|
if !utf8.ValidString(text) {
|
|
|
|
return utils.RenderErrorToast(c, "submitted content must be utf8")
|
|
|
|
}
|
|
|
|
|
2023-09-11 23:26:50 +02:00
|
|
|
// Determine language from file extension if not set.
|
2023-09-13 11:22:52 +02:00
|
|
|
if lang == "" && name != "" {
|
2023-09-11 23:26:50 +02:00
|
|
|
lexer := lexers.Match(name)
|
|
|
|
if lexer != nil {
|
|
|
|
lang = lexer.Config().Name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-12 22:30:58 +02:00
|
|
|
createdFile, err := models.CreateNewBin(global.DB, text, name, description, lang, code, adminCode, ip)
|
2023-09-11 23:26:50 +02:00
|
|
|
if err != nil {
|
|
|
|
return utils.RenderErrorToast(c, "server-side error occurred")
|
|
|
|
}
|
|
|
|
|
2023-09-13 11:22:52 +02:00
|
|
|
binPartial := pages.BinPartial(createdFile)
|
|
|
|
setTitle := components.SetTitle(name)
|
|
|
|
|
2023-09-11 23:26:50 +02:00
|
|
|
utils.SetHeader(c, "HX-Push", fmt.Sprintf("/b/%s", code))
|
|
|
|
return utils.RenderComponents(c, http.StatusOK,
|
2023-09-13 11:22:52 +02:00
|
|
|
binPartial,
|
|
|
|
setTitle,
|
2023-09-11 23:26:50 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getTextFromFile(fileHeader *multipart.FileHeader) (text string, err error) {
|
|
|
|
f, err := fileHeader.Open()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
b, err := io.ReadAll(f)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
text = string(b)
|
|
|
|
return
|
|
|
|
}
|
2023-09-13 21:02:11 +02:00
|
|
|
|
|
|
|
func ipHasTooManyUses(ip string) (tooMany bool, period string) {
|
|
|
|
file := new(models.File)
|
|
|
|
var dayCount int64
|
|
|
|
global.DB.Model(file).
|
|
|
|
Where("ip = ? AND created_date >= DATETIME('now', '-1 day')", ip).
|
|
|
|
Count(&dayCount)
|
|
|
|
|
|
|
|
var threeDayCount int64
|
|
|
|
global.DB.Model(file).
|
|
|
|
Where("ip = ? AND created_date >= DATETIME('now', '-3 days')", ip).
|
|
|
|
Count(&threeDayCount)
|
|
|
|
|
|
|
|
var weekCount int64
|
|
|
|
global.DB.Model(file).
|
|
|
|
Where("ip = ? AND created_date >= DATETIME('now', '-7 days')", ip).
|
|
|
|
Count(&weekCount)
|
|
|
|
|
|
|
|
var monthCount int64
|
|
|
|
global.DB.Model(file).
|
|
|
|
Where("ip = ? AND created_date >= DATETIME('now', '-1 month')", ip).
|
|
|
|
Count(&monthCount)
|
|
|
|
|
|
|
|
if dayCount > 20 {
|
|
|
|
return true, "last day"
|
|
|
|
} else if threeDayCount > 50 {
|
|
|
|
return true, "last three days"
|
|
|
|
} else if weekCount > 85 {
|
|
|
|
return true, "last week"
|
|
|
|
} else if monthCount > 300 {
|
|
|
|
return true, "last month"
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, ""
|
|
|
|
|
|
|
|
}
|