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/service/api/api.go
akuma06 0f66ec9340 Trackers in Torrents + Missing comments + Function renaming (#768)
* Missing comments and Function renaming

* Added some missing comments
* Renamed functions to get user followers/following
* GetFollowers to get followers
* GetLikings to get who the user is following

* Renaming + Add support of previous trackers

* Renaming user.Likings in user.Followers
* Renaming user.Liked in user.Likings
* Add a new string field Trackers in torrent model
* Trackers from torrent file are now populated to the databse
* Needed trackers are added to the torrent trackers if not provided or
if trackers is empty in DB (backward compatibility)

* New check and url encoding

* No more regex for verifying tracker url
* Encodes tracker url for "&" & "?" character possibly existing in
tracker url and breaking magnet link

* Improvements

* Trackers are now encoded in torrent.ParseTrackers
* Faster check by using the for loop of checktrackers
* No more boolean, we need to check len of array returned
* torrent.Trackers can be directly used in url as they are encoded like
: tr=tracker1&tr=tracker2&tr=...
2017-05-27 00:45:18 +02:00

246 lignes
6,1 Kio
Go

package apiService
import (
"encoding/base32"
"encoding/hex"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"reflect"
"regexp"
"strings"
"github.com/NyaaPantsu/nyaa/model"
"github.com/NyaaPantsu/nyaa/service"
"github.com/NyaaPantsu/nyaa/service/upload"
"github.com/NyaaPantsu/nyaa/util/metainfo"
"github.com/zeebo/bencode"
)
type torrentsQuery struct {
Category int `json:"category"`
SubCategory int `json:"sub_category"`
Status int `json:"status"`
Uploader int `json:"uploader"`
Downloads int `json:"downloads"`
}
// TorrentsRequest struct
type TorrentsRequest struct {
Query torrentsQuery `json:"search"`
Page int `json:"page"`
MaxPerPage int `json:"limit"`
}
// TorrentRequest struct
//accept torrent files?
type TorrentRequest struct {
Name string `json:"name"`
Category int `json:"category"`
SubCategory int `json:"sub_category"`
Magnet string `json:"magnet"`
Hash string `json:"hash"`
Description string `json:"description"`
}
// UpdateRequest struct
type UpdateRequest struct {
ID int `json:"id"`
Update TorrentRequest `json:"update"`
}
// ToParams : Convert a torrentsrequest to searchparams
func (r *TorrentsRequest) ToParams() serviceBase.WhereParams {
res := serviceBase.WhereParams{}
conditions := ""
v := reflect.ValueOf(r.Query)
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if field.Interface() != reflect.Zero(field.Type()).Interface() {
if i != 0 {
conditions += " AND "
}
conditions += v.Type().Field(i).Tag.Get("json") + " = ?"
res.Params = append(res.Params, field.Interface())
}
}
res.Conditions = conditions
return res
}
func validateName(r *TorrentRequest) (error, int) {
/*if len(r.Name) < 100 { //isn't this too much?
return ErrShortName, http.StatusNotAcceptable
}*/
return nil, http.StatusOK
}
// TODO Check category is within accepted range
func validateCategory(r *TorrentRequest) (error, int) {
if r.Category == 0 {
return ErrCategory, http.StatusNotAcceptable
}
return nil, http.StatusOK
}
// TODO Check subCategory is within accepted range
func validateSubCategory(r *TorrentRequest) (error, int) {
if r.SubCategory == 0 {
return ErrSubCategory, http.StatusNotAcceptable
}
return nil, http.StatusOK
}
func validateMagnet(r *TorrentRequest) (error, int) {
magnetURL, err := url.Parse(string(r.Magnet)) //?
if err != nil {
return err, http.StatusInternalServerError
}
xt := magnetURL.Query().Get("xt")
if !strings.HasPrefix(xt, "urn:btih:") {
return ErrMagnet, http.StatusNotAcceptable
}
xt = strings.SplitAfter(xt, ":")[2]
r.Hash = strings.ToUpper(strings.Split(xt, "&")[0])
fmt.Println(r.Hash)
return nil, http.StatusOK
}
func validateHash(r *TorrentRequest) (error, int) {
r.Hash = strings.ToUpper(r.Hash)
isBase32, err := regexp.MatchString("^[2-7A-Z]{32}$", r.Hash)
if err != nil {
return err, http.StatusInternalServerError
}
if !isBase32 {
isBase16, err := regexp.MatchString("^[0-9A-F]{40}$", r.Hash)
if err != nil {
return err, http.StatusInternalServerError
}
if !isBase16 {
return ErrHash, http.StatusNotAcceptable
}
} else {
//convert to base16
data, err := base32.StdEncoding.DecodeString(r.Hash)
if err != nil {
return err, http.StatusInternalServerError
}
hash16 := make([]byte, hex.EncodedLen(len(data)))
hex.Encode(hash16, data)
r.Hash = strings.ToUpper(string(hash16))
}
return nil, http.StatusOK
}
// ValidateUpload : Check if an upload is valid
func (r *TorrentRequest) ValidateUpload() (err error, code int) {
validators := []func(r *TorrentRequest) (error, int){
validateName,
validateCategory,
validateSubCategory,
validateMagnet,
validateHash,
}
for i, validator := range validators {
if r.Hash != "" && i == 3 {
continue
}
err, code = validator(r)
if err != nil {
break
}
}
return err, code
}
// ValidateMultipartUpload : Check if multipart upload is valid
func (r *TorrentRequest) ValidateMultipartUpload(req *http.Request) (int64, error, int) {
tfile, _, err := req.FormFile("torrent")
if err == nil {
var torrent metainfo.TorrentFile
// decode torrent
if _, err = tfile.Seek(0, io.SeekStart); err != nil {
return 0, err, http.StatusInternalServerError
}
if err = bencode.NewDecoder(tfile).Decode(&torrent); err != nil {
return 0, err, http.StatusInternalServerError
}
// check a few things
if torrent.IsPrivate() {
return 0, errors.New("private torrents not allowed"), http.StatusNotAcceptable
}
trackers := torrent.GetAllAnnounceURLS()
trackers = uploadService.CheckTrackers(trackers)
if len(trackers) == 0 {
return 0, errors.New("tracker(s) not allowed"), http.StatusNotAcceptable
}
if r.Name == "" {
r.Name = torrent.TorrentName()
}
binInfohash, err := torrent.Infohash()
if err != nil {
return 0, err, http.StatusInternalServerError
}
r.Hash = strings.ToUpper(hex.EncodeToString(binInfohash[:]))
// extract filesize
filesize := int64(torrent.TotalSize())
err, code := r.ValidateUpload()
return filesize, err, code
}
return 0, err, http.StatusInternalServerError
}
// ValidateUpdate : Check if an update is valid
func (r *TorrentRequest) ValidateUpdate() (err error, code int) {
validators := []func(r *TorrentRequest) (error, int){
validateName,
validateCategory,
validateSubCategory,
validateMagnet,
validateHash,
}
//don't update not requested values
//rewrite with reflect?
for i, validator := range validators {
if (r.Name == "" && i == 0) || (r.Category == 0 && i == 1) ||
(r.SubCategory == 0 && i == 2) ||
(r.Hash != "" || r.Magnet == "" && i == 3) || (r.Hash == "" && i == 4) {
continue
}
err, code = validator(r)
if err != nil {
break
}
}
return err, code
}
// UpdateTorrent : Update torrent model
//rewrite with reflect ?
func (r *UpdateRequest) UpdateTorrent(t *model.Torrent) {
if r.Update.Name != "" {
t.Name = r.Update.Name
}
if r.Update.Hash != "" {
t.Hash = r.Update.Hash
}
if r.Update.Category != 0 {
t.Category = r.Update.Category
}
if r.Update.SubCategory != 0 {
t.SubCategory = r.Update.SubCategory
}
if r.Update.Description != "" {
t.Description = r.Update.Description
}
}