2017-05-06 13:43:24 +02:00
package router
import (
2017-05-11 23:59:00 +02:00
"encoding/base32"
2017-05-07 02:48:24 +02:00
"encoding/hex"
2017-05-06 13:43:24 +02:00
"errors"
2017-05-07 15:55:34 +02:00
"fmt"
"io"
"io/ioutil"
"mime/multipart"
2017-05-07 10:25:09 +02:00
"net/http"
2017-05-07 02:48:24 +02:00
"net/url"
2017-05-07 15:55:34 +02:00
"os"
2017-05-07 19:47:43 +02:00
"regexp"
2017-05-07 06:26:09 +02:00
"strconv"
2017-05-07 02:48:24 +02:00
"strings"
2017-05-07 10:25:09 +02:00
2017-05-17 07:58:40 +02:00
"github.com/NyaaPantsu/nyaa/cache"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/service/upload"
"github.com/NyaaPantsu/nyaa/util"
"github.com/NyaaPantsu/nyaa/util/metainfo"
2017-05-07 11:08:44 +02:00
"github.com/microcosm-cc/bluemonday"
2017-05-06 13:43:24 +02:00
"github.com/zeebo/bencode"
)
2017-05-14 17:28:48 +02:00
// Use this, because we seem to avoid using models, and we would need
// the torrent ID to create the File in the DB
type UploadedFile struct {
2017-05-15 23:45:47 +02:00
Path [ ] string
2017-05-14 17:28:48 +02:00
Filesize int64
}
2017-05-06 13:43:24 +02:00
// UploadForm serializing HTTP form for torrent upload
type UploadForm struct {
2017-05-07 19:47:43 +02:00
Name string
Magnet string
Category string
2017-05-10 22:03:14 +02:00
Remake bool
2017-05-07 19:47:43 +02:00
Description string
2017-05-11 05:04:11 +02:00
Status int
2017-05-12 11:58:22 +02:00
CaptchaID string
2017-05-20 17:01:13 +02:00
WebsiteLink string
2017-05-07 13:48:28 +02:00
2017-05-07 15:55:34 +02:00
Infohash string
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
CategoryID int
SubCategoryID int
2017-05-07 13:48:28 +02:00
Filesize int64
2017-05-07 15:55:34 +02:00
Filepath string
2017-05-14 17:28:48 +02:00
FileList [ ] UploadedFile
2017-05-06 13:43:24 +02:00
}
// TODO: these should be in another package (?)
2017-05-10 22:03:14 +02:00
// form names
2017-05-06 13:43:24 +02:00
const UploadFormName = "name"
const UploadFormTorrent = "torrent"
const UploadFormMagnet = "magnet"
const UploadFormCategory = "c"
2017-05-10 22:03:14 +02:00
const UploadFormRemake = "remake"
2017-05-06 13:43:24 +02:00
const UploadFormDescription = "desc"
2017-05-20 17:01:13 +02:00
const UploadFormWebsiteLink = "website_link"
2017-05-10 23:53:25 +02:00
const UploadFormStatus = "status"
2017-05-06 13:43:24 +02:00
2017-05-07 13:38:46 +02:00
// error indicating that you can't send both a magnet link and torrent
2017-05-20 17:01:13 +02:00
var ErrTorrentPlusMagnet = errors . New ( "Upload either a torrent file or magnet link, not both" )
2017-05-07 13:38:46 +02:00
2017-05-06 13:43:24 +02:00
// error indicating a torrent is private
2017-05-20 17:01:13 +02:00
var ErrPrivateTorrent = errors . New ( "Torrent is private" )
2017-05-06 13:43:24 +02:00
2017-05-07 12:20:08 +02:00
// error indicating a problem with its trackers
2017-05-20 17:01:13 +02:00
var ErrTrackerProblem = errors . New ( "Torrent does not have any (working) trackers: https://" + config . WebAddress + "/faq#trackers" )
2017-05-07 12:20:08 +02:00
2017-05-06 13:43:24 +02:00
// error indicating a torrent's name is invalid
2017-05-20 17:01:13 +02:00
var ErrInvalidTorrentName = errors . New ( "Torrent name is invalid" )
2017-05-06 13:43:24 +02:00
// error indicating a torrent's description is invalid
2017-05-20 17:01:13 +02:00
var ErrInvalidTorrentDescription = errors . New ( "Torrent description is invalid" )
// error indicating a torrent's description is invalid
2017-05-20 17:13:43 +02:00
var ErrInvalidWebsiteLink = errors . New ( "Website url or IRC link is invalid" )
2017-05-06 13:43:24 +02:00
2017-05-07 06:26:09 +02:00
// error indicating a torrent's category is invalid
2017-05-20 17:01:13 +02:00
var ErrInvalidTorrentCategory = errors . New ( "Torrent category is invalid" )
2017-05-07 06:26:09 +02:00
2017-05-07 07:18:41 +02:00
var p = bluemonday . UGCPolicy ( )
2017-05-06 13:43:24 +02:00
/ * *
UploadForm . ExtractInfo takes an http request and computes all fields for this form
* /
func ( f * UploadForm ) ExtractInfo ( r * http . Request ) error {
f . Name = r . FormValue ( UploadFormName )
f . Category = r . FormValue ( UploadFormCategory )
f . Description = r . FormValue ( UploadFormDescription )
2017-05-20 17:01:13 +02:00
f . WebsiteLink = r . FormValue ( UploadFormWebsiteLink )
2017-05-10 23:53:25 +02:00
f . Status , _ = strconv . Atoi ( r . FormValue ( UploadFormStatus ) )
2017-05-06 13:43:24 +02:00
f . Magnet = r . FormValue ( UploadFormMagnet )
2017-05-10 22:03:14 +02:00
f . Remake = r . FormValue ( UploadFormRemake ) == "on"
2017-05-07 19:41:07 +02:00
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
// trim whitespace
2017-05-06 13:43:24 +02:00
f . Name = util . TrimWhitespaces ( f . Name )
2017-05-07 07:18:41 +02:00
f . Description = p . Sanitize ( util . TrimWhitespaces ( f . Description ) )
2017-05-20 17:01:13 +02:00
f . WebsiteLink = util . TrimWhitespaces ( f . WebsiteLink )
2017-05-06 13:43:24 +02:00
f . Magnet = util . TrimWhitespaces ( f . Magnet )
2017-05-12 04:21:40 +02:00
cache . Impl . ClearAll ( )
2017-05-06 13:43:24 +02:00
2017-05-07 06:26:09 +02:00
catsSplit := strings . Split ( f . Category , "_" )
// need this to prevent out of index panics
if len ( catsSplit ) == 2 {
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
CatID , err := strconv . Atoi ( catsSplit [ 0 ] )
2017-05-07 06:26:09 +02:00
if err != nil {
return ErrInvalidTorrentCategory
}
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
SubCatID , err := strconv . Atoi ( catsSplit [ 1 ] )
2017-05-07 06:26:09 +02:00
if err != nil {
return ErrInvalidTorrentCategory
}
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
f . CategoryID = CatID
f . SubCategoryID = SubCatID
2017-05-07 06:26:09 +02:00
} else {
return ErrInvalidTorrentCategory
2017-05-06 13:43:24 +02:00
}
2017-05-20 17:16:48 +02:00
if f . WebsiteLink != "" {
// WebsiteLink
2017-05-20 18:40:20 +02:00
urlRegexp , _ := regexp . Compile ( ` ^(https?:\/\/|ircs?:\/\/)?([\da-z\.-]+)\.([a-z\.] { 2,6})([\/\w \.-]*)*\/?$ ` )
2017-05-20 17:16:48 +02:00
if ! urlRegexp . MatchString ( f . WebsiteLink ) {
return ErrInvalidWebsiteLink
}
2017-05-20 17:01:13 +02:00
}
2017-05-07 13:38:46 +02:00
// first: parse torrent file (if any) to fill missing information
tfile , _ , err := r . FormFile ( UploadFormTorrent )
if err == nil {
2017-05-06 13:43:24 +02:00
var torrent metainfo . TorrentFile
2017-05-07 15:55:34 +02:00
2017-05-06 13:43:24 +02:00
// decode torrent
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
_ , seekErr := tfile . Seek ( 0 , io . SeekStart )
if seekErr != nil {
return seekErr
}
2017-05-06 13:43:24 +02:00
err = bencode . NewDecoder ( tfile ) . Decode ( & torrent )
if err != nil {
return metainfo . ErrInvalidTorrentFile
}
2017-05-07 13:38:46 +02:00
// check a few things
2017-05-06 13:43:24 +02:00
if torrent . IsPrivate ( ) {
return ErrPrivateTorrent
}
2017-05-07 12:20:08 +02:00
trackers := torrent . GetAllAnnounceURLS ( )
2017-05-11 05:04:11 +02:00
if ! uploadService . CheckTrackers ( trackers ) {
2017-05-07 12:20:08 +02:00
return ErrTrackerProblem
}
2017-05-07 13:38:46 +02:00
// Name
if len ( f . Name ) == 0 {
f . Name = torrent . TorrentName ( )
}
// Magnet link: if a file is provided it should be empty
if len ( f . Magnet ) != 0 {
return ErrTorrentPlusMagnet
}
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
binInfohash , err := torrent . Infohash ( )
if err != nil {
return err
}
2017-05-07 13:38:46 +02:00
f . Infohash = strings . ToUpper ( hex . EncodeToString ( binInfohash [ : ] ) )
2017-05-07 19:47:43 +02:00
f . Magnet = util . InfoHashToMagnet ( f . Infohash , f . Name , trackers ... )
2017-05-07 13:48:28 +02:00
// extract filesize
f . Filesize = int64 ( torrent . TotalSize ( ) )
2017-05-17 07:58:40 +02:00
2017-05-14 17:28:48 +02:00
// extract filelist
fileInfos := torrent . Info . GetFiles ( )
2017-05-15 23:45:47 +02:00
for _ , fileInfo := range fileInfos {
2017-05-14 17:28:48 +02:00
f . FileList = append ( f . FileList , UploadedFile {
2017-05-17 07:58:40 +02:00
Path : fileInfo . Path ,
2017-05-15 23:45:47 +02:00
Filesize : int64 ( fileInfo . Length ) ,
2017-05-14 17:28:48 +02:00
} )
}
2017-05-07 02:48:24 +02:00
} else {
2017-05-07 13:38:46 +02:00
// No torrent file provided
2017-05-11 23:59:00 +02:00
magnetUrl , err := url . Parse ( string ( f . Magnet ) ) //?
if err != nil {
return err
2017-05-07 02:48:24 +02:00
}
2017-05-11 23:59:00 +02:00
xt := magnetUrl . Query ( ) . Get ( "xt" )
if ! strings . HasPrefix ( xt , "urn:btih:" ) {
2017-05-20 17:01:13 +02:00
return errors . New ( "Incorrect magnet" )
2017-05-07 02:48:24 +02:00
}
2017-05-11 23:59:00 +02:00
xt = strings . SplitAfter ( xt , ":" ) [ 2 ]
f . Infohash = strings . ToUpper ( strings . Split ( xt , "&" ) [ 0 ] )
isBase32 , err := regexp . MatchString ( "^[2-7A-Z]{32}$" , f . Infohash )
2017-05-11 06:23:02 +02:00
if err != nil {
return err
}
2017-05-11 23:59:00 +02:00
if ! isBase32 {
isBase16 , err := regexp . MatchString ( "^[0-9A-F]{40}$" , f . Infohash )
if err != nil {
return err
}
if ! isBase16 {
2017-05-20 17:01:13 +02:00
return errors . New ( "Incorrect hash" )
2017-05-11 23:59:00 +02:00
}
} else {
//convert to base16
data , err := base32 . StdEncoding . DecodeString ( f . Infohash )
if err != nil {
return err
}
hash16 := make ( [ ] byte , hex . EncodedLen ( len ( data ) ) )
hex . Encode ( hash16 , data )
2017-05-12 03:28:00 +02:00
f . Infohash = strings . ToUpper ( string ( hash16 ) )
2017-05-07 13:38:46 +02:00
}
2017-05-07 13:48:28 +02:00
f . Filesize = 0
2017-05-07 15:55:34 +02:00
f . Filepath = ""
2017-05-07 13:38:46 +02:00
}
// then actually check that we have everything we need
if len ( f . Name ) == 0 {
return ErrInvalidTorrentName
2017-05-06 13:43:24 +02:00
}
2017-05-07 02:48:24 +02:00
2017-05-07 15:55:34 +02:00
// after data has been checked & extracted, write it to disk
if len ( config . TorrentFileStorage ) > 0 {
2017-05-07 19:47:43 +02:00
err := WriteTorrentToDisk ( tfile , f . Infohash + ".torrent" , & f . Filepath )
2017-05-07 15:55:34 +02:00
if err != nil {
return err
}
} else {
f . Filepath = ""
}
2017-05-06 13:43:24 +02:00
return nil
}
2017-05-11 01:46:50 +02:00
func ( f * UploadForm ) ExtractEditInfo ( r * http . Request ) error {
f . Name = r . FormValue ( UploadFormName )
f . Category = r . FormValue ( UploadFormCategory )
2017-05-21 04:10:59 +02:00
f . WebsiteLink = r . FormValue ( UploadFormWebsiteLink )
2017-05-11 01:46:50 +02:00
f . Description = r . FormValue ( UploadFormDescription )
f . Status , _ = strconv . Atoi ( r . FormValue ( UploadFormStatus ) )
// trim whitespace
f . Name = util . TrimWhitespaces ( f . Name )
f . Description = p . Sanitize ( util . TrimWhitespaces ( f . Description ) )
catsSplit := strings . Split ( f . Category , "_" )
// need this to prevent out of index panics
if len ( catsSplit ) == 2 {
CatID , err := strconv . Atoi ( catsSplit [ 0 ] )
if err != nil {
return ErrInvalidTorrentCategory
}
SubCatID , err := strconv . Atoi ( catsSplit [ 1 ] )
if err != nil {
return ErrInvalidTorrentCategory
}
f . CategoryID = CatID
f . SubCategoryID = SubCatID
} else {
return ErrInvalidTorrentCategory
}
return nil
}
2017-05-07 15:55:34 +02:00
func WriteTorrentToDisk ( file multipart . File , name string , fullpath * string ) error {
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
_ , seekErr := file . Seek ( 0 , io . SeekStart )
if seekErr != nil {
return seekErr
}
2017-05-07 15:55:34 +02:00
b , err := ioutil . ReadAll ( file )
if err != nil {
return err
}
* fullpath = fmt . Sprintf ( "%s%c%s" , config . TorrentFileStorage , os . PathSeparator , name )
return ioutil . WriteFile ( * fullpath , b , 0644 )
}
2017-05-06 13:43:24 +02:00
// NewUploadForm creates a new upload form given parameters as list
func NewUploadForm ( params ... string ) ( uploadForm UploadForm ) {
if len ( params ) > 1 {
uploadForm . Category = params [ 0 ]
} else {
uploadForm . Category = "3_12"
}
if len ( params ) > 2 {
uploadForm . Description = params [ 1 ]
} else {
uploadForm . Description = "Description"
}
return
}