Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0
Ce dépôt a été archivé le 2022-05-07. Vous pouvez voir ses fichiers ou le cloner, mais pas ouvrir de ticket ou de demandes d'ajout, ni soumettre de changements.
nyaa-pantsu/utils/validator/torrent/functions.go

296 lignes
7,5 Kio
Go
Brut Vue normale Historique

package torrentValidator
import (
"encoding/base32"
"encoding/hex"
"io"
"mime/multipart"
"net/url"
"regexp"
"strconv"
"strings"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/utils/categories"
"github.com/NyaaPantsu/nyaa/utils/cookies"
"github.com/NyaaPantsu/nyaa/utils/format"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/metainfo"
"github.com/NyaaPantsu/nyaa/utils/torrentLanguages"
"github.com/gin-gonic/gin"
"github.com/zeebo/bencode"
)
func (r *TorrentRequest) ValidateName() error {
// then actually check that we have everything we need
if len(r.Name) == 0 {
return errTorrentNameInvalid
}
return nil
}
func (r *TorrentRequest) ValidateDescription() error {
if len(r.Description) > config.Get().DescriptionLength {
return errTorrentDescInvalid
}
return nil
}
func (r *TorrentRequest) ValidateMagnet() error {
magnetURL, err := url.Parse(string(r.Magnet)) //?
if err != nil {
return err
}
xt := magnetURL.Query().Get("xt")
if !strings.HasPrefix(xt, "urn:btih:") {
return errTorrentMagnetInvalid
}
xt = strings.SplitAfter(xt, ":")[2]
r.Infohash = strings.TrimSpace(strings.ToUpper(strings.Split(xt, "&")[0]))
return nil
}
func (r *TorrentRequest) ValidateWebsiteLink() error {
if r.WebsiteLink != "" {
// WebsiteLink
urlRegexp, _ := regexp.Compile(`^(https?:\/\/|ircs?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*(\/.*)?$`)
if !urlRegexp.MatchString(r.WebsiteLink) {
return errTorrentURIInvalid
}
}
return nil
}
func (r *TorrentRequest) ValidateHash() error {
isBase32, err := regexp.MatchString("^[2-7A-Z]{32}$", r.Infohash)
if err != nil {
return err
}
if !isBase32 {
isBase16, err := regexp.MatchString("^[0-9A-F]{40}$", r.Infohash)
if err != nil {
return err
}
if !isBase16 {
return errTorrentHashInvalid
}
} else {
//convert to base16
data, err := base32.StdEncoding.DecodeString(r.Infohash)
if err != nil {
return err
}
hash16 := make([]byte, hex.EncodedLen(len(data)))
hex.Encode(hash16, data)
r.Infohash = strings.ToUpper(string(hash16))
}
return nil
}
// ExtractCategory : takes an http request and computes category field for this form
func (r *TorrentRequest) ExtractCategory() error {
catsSplit := strings.Split(r.Category, "_")
// need this to prevent out of index panics
if len(catsSplit) != 2 {
return errTorrentCatInvalid
}
CatID, err := strconv.Atoi(catsSplit[0])
if err != nil {
return errTorrentCatInvalid
}
SubCatID, err := strconv.Atoi(catsSplit[1])
if err != nil {
return errTorrentCatInvalid
}
if !categories.Exists(r.Category) {
return errTorrentCatInvalid
}
r.CategoryID = CatID
r.SubCategoryID = SubCatID
return nil
}
// ExtractLanguage : takes a http request, computes the torrent language from the form.
func (r *TorrentRequest) ExtractLanguage() error {
isEnglishCategory := false
for _, cat := range config.Get().Torrents.EnglishOnlyCategories {
if cat == r.Category {
isEnglishCategory = true
break
}
}
if len(r.Languages) == 0 {
// If no language, but in an English category, set to en-us, else just stop the check.
if !isEnglishCategory {
return nil
}
r.Languages = append(r.Languages, "en")
return nil
}
englishSelected := false
for _, language := range r.Languages {
if language == "en" {
englishSelected = true
}
if language != "" && !torrentLanguages.LanguageExists(language) {
return errTorrentLangInvalid
}
if strings.HasPrefix(language, "en") && isEnglishCategory {
englishSelected = true
}
}
// We shouldn't return an error for languages, just adding the right language is enough
if !englishSelected && isEnglishCategory {
r.Languages = append(r.Languages, "en")
return nil
}
// We shouldn't return an error if someone has selected only english for languages and missed the right category. Just move the torrent in the right one
// Multiple if conditions so we only do this for loop when needed
if len(r.Languages) == 1 && strings.HasPrefix(r.Languages[0], "en") && !isEnglishCategory && r.CategoryID > 0 {
for key, cat := range config.Get().Torrents.NonEnglishOnlyCategories {
if cat == r.Category {
r.Category = config.Get().Torrents.EnglishOnlyCategories[key]
isEnglishCategory = true
break
}
}
}
return nil
}
// ValidateMultipartUpload : Check if multipart upload is valid
func (r *TorrentRequest) ValidateMultipartUpload(c *gin.Context, uploadFormTorrent string) (multipart.File, error) {
// first: parse torrent file (if any) to fill missing information
tfile, _, err := c.Request.FormFile(uploadFormTorrent)
if err == nil {
var torrent metainfo.TorrentFile
// decode torrent
_, seekErr := tfile.Seek(0, io.SeekStart)
if seekErr != nil {
return tfile, seekErr
}
err = bencode.NewDecoder(tfile).Decode(&torrent)
if err != nil {
return tfile, metainfo.ErrInvalidTorrentFile
}
// check a few things
if torrent.IsPrivate() {
return tfile, errTorrentPrivate
}
trackers := torrent.GetAllAnnounceURLS()
r.Trackers = CheckTrackers(trackers)
if len(r.Trackers) == 0 {
return tfile, errTorrentNoTrackers
}
// Name
if len(r.Name) == 0 {
r.Name = torrent.TorrentName()
}
// Magnet link: if a file is provided it should be empty
if len(r.Magnet) != 0 {
return tfile, errTorrentAndMagnet
}
_, seekErr = tfile.Seek(0, io.SeekStart)
if seekErr != nil {
return tfile, seekErr
}
infohash, err := metainfo.DecodeInfohash(tfile)
if err != nil {
return tfile, metainfo.ErrInvalidTorrentFile
}
r.Infohash = infohash
r.Magnet = format.InfoHashToMagnet(infohash, r.Name, trackers...)
// extract filesize
r.Filesize = int64(torrent.TotalSize())
// extract filelist
fileInfos := torrent.Info.GetFiles()
for _, fileInfo := range fileInfos {
r.FileList = append(r.FileList, uploadedFile{
Path: fileInfo.Path,
Filesize: int64(fileInfo.Length),
})
}
} else {
err = r.ValidateMagnet()
if err != nil {
return tfile, err
}
err = r.ValidateHash()
if err != nil {
return tfile, err
}
// TODO: Get Trackers from magnet URL
r.Filesize = 0
r.Filepath = ""
return tfile, nil
}
return tfile, err
}
// ExtractInfo : Function to assign values from request to ReassignForm
func (f *ReassignForm) ExtractInfo(c *gin.Context) bool {
f.By = c.PostForm("by")
messages := msg.GetMessages(c)
if f.By != "olduser" && f.By != "torrentid" {
messages.AddErrorTf("errors", "no_action_exist", f.By)
return false
}
f.Data = strings.Trim(c.PostForm("data"), " \r\n")
if f.By == "olduser" {
if f.Data == "" {
messages.AddErrorT("errors", "user_not_found")
return false
} else if strings.Contains(f.Data, "\n") {
messages.AddErrorT("errors", "multiple_username_error")
return false
}
} else if f.By == "torrentid" {
if f.Data == "" {
messages.AddErrorT("errors", "no_id_given")
return false
}
splitData := strings.Split(f.Data, "\n")
for i, tmp := range splitData {
tmp = strings.Trim(tmp, " \r")
torrentID, err := strconv.ParseUint(tmp, 10, 0)
if err != nil {
messages.AddErrorTf("errors", "parse_error_line", i+1)
return false // TODO: Shouldn't it continue to parse the rest and display the errored lines?
}
f.Torrents = append(f.Torrents, uint(torrentID))
}
}
tmpID := c.PostForm("to")
parsed, err := strconv.ParseUint(tmpID, 10, 32)
if err != nil {
messages.Error(err)
return false
}
f.AssignTo = uint(parsed)
_, _, _, _, err = cookies.RetrieveUserFromRequest(c, uint(parsed))
if err != nil {
messages.AddErrorTf("errors", "no_user_found_id", int(parsed))
return false
}
return true
}