diff --git a/router/apiHandler.go b/router/apiHandler.go index 2939ea50..9c67fc1b 100644 --- a/router/apiHandler.go +++ b/router/apiHandler.go @@ -6,6 +6,7 @@ import ( "html" "net/http" "strconv" + "strings" "time" "github.com/ewhal/nyaa/config" @@ -100,22 +101,22 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) { return } + token := r.Header.Get("Authorization") + user := model.User{} + db.ORM.Where("api_token = ?", token).First(&user) //i don't like this + if user.ID == 0 { + http.Error(w, apiService.ErrApiKey.Error(), http.StatusForbidden) + return + } + + upload := apiService.TorrentRequest{} + var filesize int64 + contentType := r.Header.Get("Content-Type") if contentType == "application/json" { - token := r.Header.Get("Authorization") - user := model.User{} - db.ORM.Where("api_token = ?", token).First(&user) //i don't like this - if user.ID == 0 { - http.Error(w, apiService.ErrApiKey.Error(), http.StatusForbidden) - return - } defer r.Body.Close() - //verify token - //token := r.Header.Get("Authorization") - - upload := apiService.TorrentRequest{} d := json.NewDecoder(r.Body) if err := d.Decode(&upload); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -126,27 +127,41 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), code) return } + } else if strings.HasPrefix(contentType, "multipart/form-data") { - torrent := model.Torrent{ - Name: upload.Name, - Category: upload.Category, - SubCategory: upload.SubCategory, - Status: 1, - Hash: upload.Hash, - Date: time.Now(), - Filesize: 0, //? - Description: upload.Description, - UploaderID: user.ID, - Uploader: &user, - } + upload.Name = r.FormValue("name") + upload.Category, _ = strconv.Atoi(r.FormValue("category")) + upload.SubCategory, _ = strconv.Atoi(r.FormValue("sub_category")) + upload.Description = r.FormValue("description") - db.ORM.Create(&torrent) + var err error + var code int + + filesize, err, code = upload.ValidateMultipartUpload(r) if err != nil { - util.SendError(w, err, 500) + http.Error(w, err.Error(), code) return } - fmt.Printf("%+v\n", torrent) } + + torrent := model.Torrent{ + Name: upload.Name, + Category: upload.Category, + SubCategory: upload.SubCategory, + Status: 1, + Hash: upload.Hash, + Date: time.Now(), + Filesize: filesize, + Description: upload.Description, + UploaderID: user.ID, + Uploader: &user, + } + db.ORM.Create(&torrent) + /*if err != nil { + util.SendError(w, err, 500) + return + }*/ + fmt.Printf("%+v\n", torrent) } func ApiUpdateHandler(w http.ResponseWriter, r *http.Request) { diff --git a/router/upload.go b/router/upload.go index 1eeb3b5c..91564d50 100644 --- a/router/upload.go +++ b/router/upload.go @@ -17,6 +17,7 @@ import ( "github.com/ewhal/nyaa/cache" "github.com/ewhal/nyaa/config" "github.com/ewhal/nyaa/service/captcha" + "github.com/ewhal/nyaa/service/upload" "github.com/ewhal/nyaa/util" "github.com/ewhal/nyaa/util/metainfo" "github.com/microcosm-cc/bluemonday" @@ -30,7 +31,7 @@ type UploadForm struct { Category string Remake bool Description string - Status int + Status int captcha.Captcha Infohash string @@ -133,7 +134,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error { return ErrPrivateTorrent } trackers := torrent.GetAllAnnounceURLS() - if !CheckTrackers(trackers) { + if !uploadService.CheckTrackers(trackers) { return ErrTrackerProblem } @@ -236,35 +237,6 @@ func WriteTorrentToDisk(file multipart.File, name string, fullpath *string) erro return ioutil.WriteFile(*fullpath, b, 0644) } -func CheckTrackers(trackers []string) bool { - // TODO: move to runtime configuration - var deadTrackers = []string{ // substring matches! - "://open.nyaatorrents.info:6544", - "://tracker.openbittorrent.com:80", - "://tracker.publicbt.com:80", - "://stats.anisource.net:2710", - "://exodus.desync.com", - "://open.demonii.com:1337", - "://tracker.istole.it:80", - "://tracker.ccc.de:80", - "://bt2.careland.com.cn:6969", - "://announce.torrentsmd.com:8080"} - - var numGood int - for _, t := range trackers { - good := true - for _, check := range deadTrackers { - if strings.Contains(t, check) { - good = false - } - } - if good { - numGood++ - } - } - return numGood > 0 -} - // NewUploadForm creates a new upload form given parameters as list func NewUploadForm(params ...string) (uploadForm UploadForm) { if len(params) > 1 { diff --git a/service/api/api.go b/service/api/api.go index 3c5a3547..3f15dbbc 100644 --- a/service/api/api.go +++ b/service/api/api.go @@ -1,6 +1,9 @@ package apiService import ( + "encoding/hex" + "errors" + "io" "net/http" "net/url" "reflect" @@ -9,6 +12,9 @@ import ( "github.com/ewhal/nyaa/model" "github.com/ewhal/nyaa/service" + "github.com/ewhal/nyaa/service/upload" + "github.com/ewhal/nyaa/util/metainfo" + "github.com/zeebo/bencode" ) type torrentsQuery struct { @@ -60,9 +66,9 @@ func (r *TorrentsRequest) ToParams() serviceBase.WhereParams { } func validateName(r *TorrentRequest) (error, int) { - if len(r.Name) < 100 { //isn't this too much? + /*if len(r.Name) < 100 { //isn't this too much? return ErrShortName, http.StatusNotAcceptable - } + }*/ return nil, http.StatusOK } @@ -105,8 +111,6 @@ func validateHash(r *TorrentRequest) (error, int) { return nil, http.StatusOK } -//rewrite validators!!! - func (r *TorrentRequest) ValidateUpload() (err error, code int) { validators := []func(r *TorrentRequest) (error, int){ validateName, @@ -128,6 +132,45 @@ func (r *TorrentRequest) ValidateUpload() (err error, code int) { return err, code } +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.StatusBadRequest + } + trackers := torrent.GetAllAnnounceURLS() + if !uploadService.CheckTrackers(trackers) { + return 0, errors.New("tracker(s) not allowed"), http.StatusBadRequest + } + + 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 +} + func (r *TorrentRequest) ValidateUpdate() (err error, code int) { validators := []func(r *TorrentRequest) (error, int){ validateName, diff --git a/service/upload/upload.go b/service/upload/upload.go new file mode 100644 index 00000000..8335db1a --- /dev/null +++ b/service/upload/upload.go @@ -0,0 +1,34 @@ +package uploadService + +import ( + "strings" +) + +func CheckTrackers(trackers []string) bool { + // TODO: move to runtime configuration + var deadTrackers = []string{ // substring matches! + "://open.nyaatorrents.info:6544", + "://tracker.openbittorrent.com:80", + "://tracker.publicbt.com:80", + "://stats.anisource.net:2710", + "://exodus.desync.com", + "://open.demonii.com:1337", + "://tracker.istole.it:80", + "://tracker.ccc.de:80", + "://bt2.careland.com.cn:6969", + "://announce.torrentsmd.com:8080"} + + var numGood int + for _, t := range trackers { + good := true + for _, check := range deadTrackers { + if strings.Contains(t, check) { + good = false + } + } + if good { + numGood++ + } + } + return numGood > 0 +}