Albirew/nyaa-pantsu
Albirew
/
nyaa-pantsu
Archivé
1
0
Bifurcation 0

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.
Cette révision appartient à :
Chris MacLeod 2017-05-09 22:34:40 -04:00 révisé par Austin
Parent 130ef6f6ad
révision c9b72206a5
56 fichiers modifiés avec 750 ajouts et 720 suppressions

Voir le fichier

@ -3,7 +3,6 @@ package config
import (
"bufio"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
@ -11,19 +10,20 @@ import (
)
const (
// Highest torrent ID that was copied from nyaa
LastOldTorrentId = 923000
// LastOldTorrentID is the highest torrent ID
// that was copied from the original Nyaa
LastOldTorrentID = 923000
)
type Config struct {
Host string `json: "host"`
Port int `json: "port"`
DBType string `json: "db_type"`
// This will be directly passed to Gorm, and its internal
Host string `json:"host"`
Port int `json:"port"`
DBType string `json:"db_type"`
// DBParams will be directly passed to Gorm, and its internal
// structure depends on the dialect for each db type
DBParams string `json: "db_params"`
DBParams string `json:"db_params"`
// optional i2p configuration
I2P *I2PConfig `json: "i2p"`
I2P *I2PConfig `json:"i2p"`
}
var Defaults = Config{"localhost", 9999, "sqlite3", "./nyaa.db?cache_size=50", nil}
@ -35,7 +35,7 @@ var allowedDatabaseTypes = map[string]bool{
"mssql": true,
}
func NewConfig() *Config {
func New() *Config {
var config Config
config.Host = Defaults.Host
config.Port = Defaults.Port
@ -44,28 +44,25 @@ func NewConfig() *Config {
return &config
}
type processFlags func() error
func (config *Config) BindFlags() processFlags {
// This function returns a function which is to be used after
// flag.Parse to check and copy the flags' values to the Config instance.
conf_file := flag.String("conf", "", "path to the configuration file")
db_type := flag.String("dbtype", Defaults.DBType, "database backend")
// BindFlags returns a function which is to be used after
// flag.Parse to check and copy the flags' values to the Config instance.
func (config *Config) BindFlags() func() error {
confFile := flag.String("conf", "", "path to the configuration file")
dbType := flag.String("dbtype", Defaults.DBType, "database backend")
host := flag.String("host", Defaults.Host, "binding address of the server")
port := flag.Int("port", Defaults.Port, "port of the server")
db_params := flag.String("dbparams", Defaults.DBParams, "parameters to open the database (see Gorm's doc)")
dbParams := flag.String("dbparams", Defaults.DBParams, "parameters to open the database (see Gorm's doc)")
return func() error {
// You can override fields in the config file with flags.
config.Host = *host
config.Port = *port
config.DBParams = *db_params
err := config.SetDBType(*db_type)
config.DBParams = *dbParams
err := config.SetDBType(*dbType)
if err != nil {
return err
}
err = config.HandleConfFileFlag(*conf_file)
err = config.HandleConfFileFlag(*confFile)
return err
}
}
@ -74,12 +71,12 @@ func (config *Config) HandleConfFileFlag(path string) error {
if path != "" {
file, err := os.Open(path)
if err != nil {
return errors.New(fmt.Sprintf("Can't read file '%s'.", path))
return fmt.Errorf("can't read file '%s'", path)
}
err = config.Read(bufio.NewReader(file))
if err != nil {
return errors.New(fmt.Sprintf("Failed to parse file '%s' (%s).", path, err))
return fmt.Errorf("failed to parse file '%s' (%s)", path, err)
}
}
return nil
@ -87,7 +84,7 @@ func (config *Config) HandleConfFileFlag(path string) error {
func (config *Config) SetDBType(db_type string) error {
if !allowedDatabaseTypes[db_type] {
return errors.New(fmt.Sprintf("Unknown database backend '%s'.", db_type))
return fmt.Errorf("unknown database backend '%s'", db_type)
}
config.DBType = db_type
return nil

Voir le fichier

@ -2,6 +2,9 @@ package config
import "time"
// TODO: Perform email configuration at runtime
// Future hosts shouldn't have to rebuild the binary to update a setting
const (
SendEmail = true
EmailFrom = "donotrespond@nyaa.pantsu.cat"
@ -10,8 +13,7 @@ const (
EmailUsername = ""
EmailPassword = ""
EmailPort = 465
// EmailTimeout = 80 * time.Millisecond
EmailTimeout = 10 * time.Second
EmailTimeout = 10 * time.Second
)
var EmailTokenHashKey = []byte("CHANGE_THIS_BEFORE_DEPLOYING_YOU_RETARD")

Voir le fichier

@ -1,10 +1,11 @@
package config
// Constants for environment.
// TODO: Perform environment configuration at runtime
// Future hosts shouldn't have to rebuild the binary to update a setting
const (
// DEVELOPMENT | TEST | PRODUCTION
Environment = "DEVELOPMENT"
// Environment = "PRODUCTION"
WebAddress = "nyaa.pantsu.cat"
// Environment should be one of: DEVELOPMENT, TEST, PRODUCTION
Environment = "DEVELOPMENT"
WebAddress = "nyaa.pantsu.cat"
AuthTokenExpirationDay = 1000
)

Voir le fichier

@ -1,8 +1,7 @@
package config
// i2p connectivity config
type I2PConfig struct {
Name string `json: "name"`
Addr string `json: "samaddr"`
Keyfile string `json: "keyfile"`
Name string `json:"name"`
Addr string `json:"samaddr"`
Keyfile string `json:"keyfile"`
}

Voir le fichier

@ -1,6 +1,5 @@
package config
// Constants for logger.
const (
AccessLogFilePath = "log/access"
AccessLogFileExtension = ".txt"

Voir le fichier

@ -1,6 +1,8 @@
package config
// Constants for pagination.
// TODO: Perform navigation configuration at runtime
// Future hosts shouldn't have to rebuild the binary to update a setting
const (
TorrentsPerPage = 50
TorrentsPerPage = 50
)

Voir le fichier

@ -1,7 +1,9 @@
package config
// Constants for ordering models.
// TODO: Perform sorting configuration at runtime
// Future hosts shouldn't have to rebuild the binary to update a setting
const (
TorrentOrder = "torrent_id"
TorrentOrder = "torrent_id"
TorrentSort = "DESC"
)

Voir le fichier

@ -1,6 +1,7 @@
package config
// remember to update the FAQ when updating these
// TODO: Update FAQ template to use this variable
var Trackers = []string{
"udp://tracker.coppersurfer.tk:6969",
"udp://zer0day.to:1337/announce",

Voir le fichier

@ -8,7 +8,5 @@ const (
// TODO: deprecate this and move all files to the same server
TorrentCacheLink = "http://anicache.com/torrent/%s.torrent"
//disable uploads by default
UploadsDisabled = 1
UploadsDisabled = true
)

Voir le fichier

@ -5,36 +5,33 @@ import (
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/util/log"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
_ "github.com/jinzhu/gorm/dialects/postgres"
// _ "github.com/go-sql-driver/mysql"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
var ORM *gorm.DB
// GormInit init gorm ORM.
func GormInit(conf *config.Config) (*gorm.DB, error) {
db, err := gorm.Open(conf.DBType, conf.DBParams)
// db, err := gorm.Open("mysql", config.MysqlDSL())
//db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
db, openErr := gorm.Open(conf.DBType, conf.DBParams)
if openErr != nil {
log.CheckError(openErr)
return nil, openErr
}
// Get database connection handle [*sql.DB](http://golang.org/pkg/database/sql/#DB)
db.DB()
// Then you could invoke `*sql.DB`'s functions with it
db.DB().Ping()
connectionErr := db.DB().Ping()
if connectionErr != nil {
log.CheckError(connectionErr)
return nil, connectionErr
}
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
// Disable table name's pluralization
// db.SingularTable(true)
// TODO: Enable Gorm initialization for non-development builds
if config.Environment == "DEVELOPMENT" {
db.LogMode(true)
db.AutoMigrate(&model.Torrents{}, &model.UserFollows{}, &model.User{}, &model.Comment{}, &model.OldComment{})
// db.Model(&model.User{}).AddIndex("idx_user_token", "token")
db.AutoMigrate(&model.Torrent{}, &model.UserFollows{}, &model.User{}, &model.Comment{}, &model.OldComment{})
}
log.CheckError(err)
return db, err
return db, nil
}

21
main.go
Voir le fichier

@ -48,17 +48,23 @@ func RunServer(conf *config.Config) {
}
func main() {
conf := config.NewConfig()
process_flags := conf.BindFlags()
conf := config.New()
processFlags := conf.BindFlags()
defaults := flag.Bool("print-defaults", false, "print the default configuration file on stdout")
flag.Parse()
if *defaults {
stdout := bufio.NewWriter(os.Stdout)
conf.Pretty(stdout)
stdout.Flush()
err := conf.Pretty(stdout)
if err != nil {
log.Fatal(err.Error())
}
err = stdout.Flush()
if err != nil {
log.Fatal(err.Error())
}
os.Exit(0)
} else {
err := process_flags()
err := processFlags()
if err != nil {
log.CheckError(err)
}
@ -69,7 +75,10 @@ func main() {
initI18N()
go signals.Handle()
if len(config.TorrentFileStorage) > 0 {
os.MkdirAll(config.TorrentFileStorage, 0755)
err := os.MkdirAll(config.TorrentFileStorage, 0700)
if err != nil {
log.Fatal(err.Error())
}
}
RunServer(conf)
}

Voir le fichier

@ -5,27 +5,29 @@ import (
)
type Comment struct {
Id uint `gorm:"column:comment_id;primary_key"`
TorrentId uint `gorm:"column:torrent_id"`
UserId uint `gorm:"column:user_id"`
ID uint `gorm:"column:comment_id;primary_key"`
TorrentID uint `gorm:"column:torrent_id"`
UserID uint `gorm:"column:user_id"`
Content string `gorm:"column:content"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
Torrent *Torrents `gorm:"ForeignKey:torrent_id"`
User *User `gorm:"ForeignKey:user_id"`
Torrent *Torrent `gorm:"ForeignKey:torrent_id"`
User *User `gorm:"ForeignKey:user_id"`
}
type OldComment struct {
TorrentId uint `gorm:"column:torrent_id"`
TorrentID uint `gorm:"column:torrent_id"`
Username string `gorm:"column:username"`
Content string `gorm:"column:content"`
Date time.Time `gorm:"column:date"`
Torrent *Torrents `gorm:"ForeignKey:torrent_id"`
Torrent *Torrent `gorm:"ForeignKey:torrent_id"`
}
func (c OldComment) TableName() string {
// cba to rename this in the db
// TODO: Update database schema to fix this hack
// I find this odd considering how often the schema changes already
return "comments_old"
}

Voir le fichier

@ -1,7 +1,6 @@
package model
// Language is a language model.
type Language struct {
Id uint `json:"id"`
ID uint `json:"id"`
Name string `json:"name"`
}

Voir le fichier

@ -5,6 +5,7 @@ import (
"github.com/ewhal/nyaa/util"
"fmt"
"html"
"html/template"
"strconv"
"strings"
@ -12,100 +13,101 @@ import (
)
type Feed struct {
Id int
ID int
Name string
Hash string
Magnet string
Timestamp string
}
type Torrents struct {
Id uint `gorm:"column:torrent_id;primary_key"`
Name string `gorm:"column:torrent_name"`
Hash string `gorm:"column:torrent_hash"`
Category int `gorm:"column:category"`
Sub_Category int `gorm:"column:sub_category"`
Status int `gorm:"column:status"`
Date time.Time `gorm:"column:date"`
UploaderId uint `gorm:"column:uploader"`
Downloads int `gorm:"column:downloads"`
Stardom int `gorm:"column:stardom"`
Filesize int64 `gorm:"column:filesize"`
Description string `gorm:"column:description"`
WebsiteLink string `gorm:"column:website_link"`
type Torrent struct {
ID uint `gorm:"column:torrent_id;primary_key"`
Name string `gorm:"column:torrent_name"`
Hash string `gorm:"column:torrent_hash"`
Category int `gorm:"column:category"`
SubCategory int `gorm:"column:sub_category"`
Status int `gorm:"column:status"`
Date time.Time `gorm:"column:date"`
UploaderID uint `gorm:"column:uploader"`
Downloads int `gorm:"column:downloads"`
Stardom int `gorm:"column:stardom"`
Filesize int64 `gorm:"column:filesize"`
Description string `gorm:"column:description"`
WebsiteLink string `gorm:"column:website_link"`
Uploader *User `gorm:"ForeignKey:UploaderId"`
OldComments []OldComment `gorm:"ForeignKey:torrent_id"`
Comments []Comment `gorm:"ForeignKey:torrent_id"`
}
/* We need JSON Object instead because of Magnet URL that is not in the database but generated dynamically */
/* We need a JSON object instead of a Gorm structure because magnet URLs are
not in the database and have to be generated dynamically */
type ApiResultJson struct {
Torrents []TorrentsJson `json:"torrents"`
QueryRecordCount int `json:"queryRecordCount"`
TotalRecordCount int `json:"totalRecordCount"`
type ApiResultJSON struct {
Torrents []TorrentJSON `json:"torrents"`
QueryRecordCount int `json:"queryRecordCount"`
TotalRecordCount int `json:"totalRecordCount"`
}
type CommentsJson struct {
type CommentJSON struct {
Username string `json:"username"`
Content template.HTML `json:"content"`
Date time.Time `json:"date"`
}
type TorrentsJson struct {
Id string `json:"id"`
Name string `json:"name"`
Status int `json:"status"`
Hash string `json:"hash"`
Date string `json:"date"`
Filesize string `json:"filesize"`
Description template.HTML `json:"description"`
Comments []CommentsJson `json:"comments"`
Sub_Category string `json:"sub_category"`
Category string `json:"category"`
Downloads int `json:"downloads"`
UploaderId uint `json:"uploader_id"`
UploaderName template.HTML `json:"uploader_name"`
WebsiteLink template.URL `json:"website_link"`
Magnet template.URL `json:"magnet"`
TorrentLink template.URL `json:"torrent"`
type TorrentJSON struct {
ID string `json:"id"`
Name string `json:"name"`
Status int `json:"status"`
Hash string `json:"hash"`
Date string `json:"date"`
Filesize string `json:"filesize"`
Description template.HTML `json:"description"`
Comments []CommentJSON `json:"comments"`
SubCategory string `json:"sub_category"`
Category string `json:"category"`
Downloads int `json:"downloads"`
UploaderID uint `json:"uploader_id"`
UploaderName template.HTML `json:"uploader_name"`
WebsiteLink template.URL `json:"website_link"`
Magnet template.URL `json:"magnet"`
TorrentLink template.URL `json:"torrent"`
}
/* Model Conversion to Json */
func (t *Torrents) ToJson() TorrentsJson {
// ToJSON converts a model.Torrent to its equivalent JSON structure
func (t *Torrent) ToJSON() TorrentJSON {
magnet := util.InfoHashToMagnet(strings.TrimSpace(t.Hash), t.Name, config.Trackers...)
commentsJson := make([]CommentsJson, 0, len(t.OldComments)+len(t.Comments))
commentsJSON := make([]CommentJSON, 0, len(t.OldComments)+len(t.Comments))
for _, c := range t.OldComments {
commentsJson = append(commentsJson, CommentsJson{Username: c.Username, Content: template.HTML(c.Content), Date: c.Date})
escapedContent := template.HTML(html.EscapeString(c.Content))
commentsJSON = append(commentsJSON, CommentJSON{Username: c.Username, Content: escapedContent, Date: c.Date})
}
for _, c := range t.Comments {
commentsJson = append(commentsJson, CommentsJson{Username: c.User.Username, Content: util.MarkdownToHTML(c.Content), Date: c.CreatedAt})
commentsJSON = append(commentsJSON, CommentJSON{Username: c.User.Username, Content: util.MarkdownToHTML(c.Content), Date: c.CreatedAt})
}
uploader := ""
if t.Uploader != nil {
uploader = t.Uploader.Username
}
torrentlink := ""
if t.Id <= config.LastOldTorrentId && len(config.TorrentCacheLink) > 0 {
if t.ID <= config.LastOldTorrentID && len(config.TorrentCacheLink) > 0 {
torrentlink = fmt.Sprintf(config.TorrentCacheLink, t.Hash)
} else if t.Id > config.LastOldTorrentId && len(config.TorrentStorageLink) > 0 {
torrentlink = fmt.Sprintf(config.TorrentStorageLink, t.Hash)
} else if t.ID > config.LastOldTorrentID && len(config.TorrentStorageLink) > 0 {
torrentlink = fmt.Sprintf(config.TorrentStorageLink, t.Hash) // TODO: Fix as part of configuration changes
}
res := TorrentsJson{
Id: strconv.FormatUint(uint64(t.Id), 10),
res := TorrentJSON{
ID: strconv.FormatUint(uint64(t.ID), 10),
Name: t.Name,
Status: t.Status,
Hash: t.Hash,
Date: t.Date.Format(time.RFC3339),
Filesize: util.FormatFilesize2(t.Filesize),
Description: util.MarkdownToHTML(t.Description),
Comments: commentsJson,
Sub_Category: strconv.Itoa(t.Sub_Category),
Comments: commentsJSON,
SubCategory: strconv.Itoa(t.SubCategory),
Category: strconv.Itoa(t.Category),
Downloads: t.Downloads,
UploaderId: t.UploaderId,
UploaderID: t.UploaderID,
UploaderName: util.SafeText(uploader),
WebsiteLink: util.Safe(t.WebsiteLink),
Magnet: util.Safe(magnet),
@ -117,10 +119,10 @@ func (t *Torrents) ToJson() TorrentsJson {
/* Complete the functions when necessary... */
// Map Torrents to TorrentsToJSON without reallocations
func TorrentsToJSON(t []Torrents) []TorrentsJson {
json := make([]TorrentsJson, len(t))
func TorrentsToJSON(t []Torrent) []TorrentJSON { // TODO: Convert to singular version
json := make([]TorrentJSON, len(t))
for i := range t {
json[i] = t[i].ToJson()
json[i] = t[i].ToJSON()
}
return json
}

Voir le fichier

@ -5,7 +5,7 @@ import (
)
type User struct {
Id uint `gorm:"column:user_id;primary_key"`
ID uint `gorm:"column:user_id;primary_key"`
Username string `gorm:"column:username"`
Password string `gorm:"column:password"`
Email string `gorm:"column:email"`
@ -17,17 +17,17 @@ type User struct {
Language string `gorm:"column:language"`
// TODO: move this to PublicUser
LikingCount int `json:"likingCount" gorm:"-"`
LikedCount int `json:"likedCount" gorm:"-"`
Likings []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
Liked []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`
LikingCount int `json:"likingCount" gorm:"-"`
LikedCount int `json:"likedCount" gorm:"-"`
Likings []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
Liked []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`
Md5 string `json:"md5"` // Used for gravatar
Torrents []Torrents `gorm:"ForeignKey:UploaderId"`
MD5 string `json:"md5"` // Hash of email address, used for Gravatar
Torrents []Torrent `gorm:"ForeignKey:UploaderId"`
}
type PublicUser struct {
User *User
User *User
}
// different users following eachother

Voir le fichier

@ -5,7 +5,6 @@ import (
"fmt"
"html"
"net/http"
//"sort"
"strconv"
"time"
@ -15,6 +14,7 @@ import (
"github.com/ewhal/nyaa/service/api"
"github.com/ewhal/nyaa/service/torrent"
"github.com/ewhal/nyaa/util"
"github.com/ewhal/nyaa/util/log"
"github.com/gorilla/mux"
)
@ -40,26 +40,32 @@ func ApiHandler(w http.ResponseWriter, r *http.Request) {
whereParams = req.ToParams()
} else {
var errConv error
req.MaxPerPage, errConv = strconv.Atoi(r.URL.Query().Get("max"))
if errConv != nil || req.MaxPerPage == 0 {
req.MaxPerPage = 50 // default Value maxPerPage
var err error
maxString := r.URL.Query().Get("max")
if maxString != "" {
req.MaxPerPage, err = strconv.Atoi(maxString)
if !log.CheckError(err) {
req.MaxPerPage = 50 // default Value maxPerPage
}
}
req.Page, _ = strconv.Atoi(html.EscapeString(page))
if req.Page == 0 {
req.Page = 1
req.Page = 1
if page != "" {
req.Page, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
}
nbTorrents := 0
torrents, nbTorrents, err := torrentService.GetTorrents(whereParams, req.MaxPerPage, req.MaxPerPage*(req.Page-1))
if err != nil {
util.SendError(w, err, 400)
return
}
b := model.ApiResultJson{
b := model.ApiResultJSON{
Torrents: model.TorrentsToJSON(torrents),
}
b.QueryRecordCount = req.MaxPerPage
@ -73,13 +79,11 @@ func ApiHandler(w http.ResponseWriter, r *http.Request) {
}
func ApiViewHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
torrent, err := torrentService.GetTorrentById(id)
b := torrent.ToJson()
b := torrent.ToJSON()
w.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(w).Encode(b)
@ -90,7 +94,7 @@ func ApiViewHandler(w http.ResponseWriter, r *http.Request) {
}
func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
if config.UploadsDisabled == 1 {
if config.UploadsDisabled {
http.Error(w, "Error uploads are disabled", http.StatusInternalServerError)
return
}
@ -100,13 +104,16 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
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 {
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 {
@ -119,17 +126,17 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
return
}
torrent := model.Torrents{
Name: upload.Name,
Category: upload.Category,
Sub_Category: upload.SubCategory,
Status: 1,
Hash: upload.Hash,
Date: time.Now(),
Filesize: 0, //?
Description: upload.Description,
UploaderId: user.Id,
Uploader: &user,
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,
}
db.ORM.Create(&torrent)
@ -142,7 +149,7 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
}
func ApiUpdateHandler(w http.ResponseWriter, r *http.Request) {
if config.UploadsDisabled == 1 {
if config.UploadsDisabled {
http.Error(w, "Error uploads are disabled", http.StatusInternalServerError)
return
}
@ -152,7 +159,7 @@ func ApiUpdateHandler(w http.ResponseWriter, r *http.Request) {
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 {
if user.ID == 0 {
http.Error(w, apiService.ErrApiKey.Error(), http.StatusForbidden)
return
}
@ -166,14 +173,14 @@ func ApiUpdateHandler(w http.ResponseWriter, r *http.Request) {
return
}
id := update.Id
torrent := model.Torrents{}
id := update.ID
torrent := model.Torrent{}
db.ORM.Where("torrent_id = ?", id).First(&torrent)
if torrent.Id == 0 {
if torrent.ID == 0 {
http.Error(w, apiService.ErrTorrentId.Error(), http.StatusBadRequest)
return
}
if torrent.UploaderId != 0 && torrent.UploaderId != user.Id { //&& user.Status != mod
if torrent.UploaderID != 0 && torrent.UploaderID != user.ID { //&& user.Status != mod
http.Error(w, apiService.ErrRights.Error(), http.StatusForbidden)
return
}

Voir le fichier

@ -1,16 +1,15 @@
package router
import (
"html"
"net/http"
"strconv"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/torrent"
"github.com/ewhal/nyaa/util"
"github.com/ewhal/nyaa/util/languages"
"github.com/ewhal/nyaa/util/log"
"github.com/gorilla/mux"
"html"
"net/http"
"strconv"
)
func HomeHandler(w http.ResponseWriter, r *http.Request) {
@ -18,19 +17,27 @@ func HomeHandler(w http.ResponseWriter, r *http.Request) {
page := vars["page"]
// db params url
maxPerPage, errConv := strconv.Atoi(r.URL.Query().Get("max"))
if errConv != nil {
maxPerPage = 50 // default Value maxPerPage
var err error
maxPerPage := 50
maxString := r.URL.Query().Get("max")
if maxString != "" {
maxPerPage, err = strconv.Atoi(maxString)
if !log.CheckError(err) {
maxPerPage = 50 // default Value maxPerPage
}
}
nbTorrents := 0
pagenum, _ := strconv.Atoi(html.EscapeString(page))
if pagenum == 0 {
pagenum = 1
pagenum := 1
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
torrents, nbTorrents, err := torrentService.GetAllTorrents(maxPerPage, maxPerPage*(pagenum-1))
if err != nil {
if !log.CheckError(err) {
util.SendError(w, err, 400)
return
}

Voir le fichier

@ -26,7 +26,7 @@ func init() {
gzipAPIUploadHandler := handlers.CompressHandler(http.HandlerFunc(ApiUploadHandler))
gzipAPIUpdateHandler := handlers.CompressHandler(http.HandlerFunc(ApiUpdateHandler))
gzipFaqHandler := handlers.CompressHandler(http.HandlerFunc(FaqHandler))
gzipRssHandler := handlers.CompressHandler(http.HandlerFunc(RssHandler))
gzipRSSHandler := handlers.CompressHandler(http.HandlerFunc(RSSHandler))
gzipViewHandler := handlers.CompressHandler(http.HandlerFunc(ViewHandler))
gzipUploadHandler := handlers.CompressHandler(http.HandlerFunc(UploadHandler))
gzipUserRegisterFormHandler := handlers.CompressHandler(http.HandlerFunc(UserRegisterFormHandler))
@ -55,7 +55,7 @@ func init() {
Router.Handle("/api/upload", gzipAPIUploadHandler).Methods("POST")
Router.Handle("/api/update", gzipAPIUpdateHandler).Methods("PUT")
Router.Handle("/faq", gzipFaqHandler).Name("faq")
Router.Handle("/feed", gzipRssHandler).Name("feed")
Router.Handle("/feed", gzipRSSHandler).Name("feed")
Router.Handle("/view/{id}", gzipViewHandler).Methods("GET").Name("view_torrent")
Router.HandleFunc("/view/{id}", PostCommentHandler).Methods("POST").Name("post_comment")
Router.Handle("/upload", gzipUploadHandler).Name("upload")

Voir le fichier

@ -1,53 +1,54 @@
package router
import (
"net/http"
"strconv"
"time"
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/util"
"github.com/ewhal/nyaa/util/search"
"github.com/gorilla/feeds"
"net/http"
"strconv"
"time"
)
func RssHandler(w http.ResponseWriter, r *http.Request) {
func RSSHandler(w http.ResponseWriter, r *http.Request) {
_, torrents, err := search.SearchByQueryNoCount(r, 1)
if err != nil {
util.SendError(w, err, 400)
return
}
created_as_time := time.Now()
createdAsTime := time.Now()
if len(torrents) > 0 {
created_as_time = torrents[0].Date
createdAsTime = torrents[0].Date
}
feed := &feeds.Feed{
Title: "Nyaa Pantsu",
Link: &feeds.Link{Href: "https://" + config.WebAddress + "/"},
Created: created_as_time,
Created: createdAsTime,
}
feed.Items = []*feeds.Item{}
feed.Items = make([]*feeds.Item, len(torrents))
for i, _ := range torrents {
torrent_json := torrents[i].ToJson()
for i := range torrents {
torrentJSON := torrents[i].ToJSON()
feed.Items[i] = &feeds.Item{
// need a torrent view first
Id: "https://" + config.WebAddress + "/view/" + strconv.FormatUint(uint64(torrents[i].Id), 10),
Id: "https://" + config.WebAddress + "/view/" + strconv.FormatUint(uint64(torrents[i].ID), 10),
Title: torrents[i].Name,
Link: &feeds.Link{Href: string(torrent_json.Magnet)},
Link: &feeds.Link{Href: string(torrentJSON.Magnet)},
Description: "",
Created: torrents[0].Date,
Updated: torrents[0].Date,
}
}
rss, err := feed.ToRss()
if err == nil {
w.Write([]byte(rss))
} else {
rss, rssErr := feed.ToRss()
if rssErr != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
_, writeErr := w.Write([]byte(rss))
if writeErr != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}

Voir le fichier

@ -1,15 +1,15 @@
package router
import (
"html"
"net/http"
"strconv"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/util"
"github.com/ewhal/nyaa/util/languages"
"github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/util/search"
"github.com/gorilla/mux"
"html"
"net/http"
"strconv"
)
func SearchHandler(w http.ResponseWriter, r *http.Request) {
@ -17,12 +17,17 @@ func SearchHandler(w http.ResponseWriter, r *http.Request) {
page := vars["page"]
// db params url
pagenum, _ := strconv.Atoi(html.EscapeString(page))
if pagenum == 0 {
pagenum = 1
var err error
pagenum := 1
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
search_param, torrents, nbTorrents, err := search.SearchByQuery(r, pagenum)
searchParam, torrents, nbTorrents, err := search.SearchByQuery(r, pagenum)
if err != nil {
util.SendError(w, err, 400)
return
@ -30,11 +35,11 @@ func SearchHandler(w http.ResponseWriter, r *http.Request) {
b := model.TorrentsToJSON(torrents)
navigationTorrents := Navigation{nbTorrents, int(search_param.Max), pagenum, "search_page"}
navigationTorrents := Navigation{nbTorrents, int(searchParam.Max), pagenum, "search_page"}
// Convert back to strings for now.
searchForm := SearchForm{
SearchParam: search_param,
Category: search_param.Category.String(),
SearchParam: searchParam,
Category: searchParam.Category.String(),
HideAdvancedSearch: false,
}
htv := HomeTemplateVariables{b, searchForm, navigationTorrents, GetUser(r), r.URL, mux.CurrentRoute(r)}

Voir le fichier

@ -1,14 +1,14 @@
package router
import (
"github.com/ewhal/nyaa/service/user/permission"
"github.com/nicksnyder/go-i18n/i18n"
"html/template"
"log"
"math"
"net/url"
"strconv"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/ewhal/nyaa/service/user/permission"
)
)
var FuncMap = template.FuncMap{
"min": math.Min,
@ -22,7 +22,7 @@ var FuncMap = template.FuncMap{
"genRouteWithQuery": func(name string, currentUrl *url.URL, params ...string) template.HTML {
url, err := Router.Get(name).URL(params...)
if err == nil {
return template.HTML(url.String()+ "?" + currentUrl.RawQuery)
return template.HTML(template.HTMLEscapeString(url.String() + "?" + currentUrl.RawQuery)) // TODO: Review application of character escaping
}
return "error"
},
@ -38,7 +38,7 @@ var FuncMap = template.FuncMap{
if nav.CurrentPage > pagesSelectable/2 {
startValue = (int(math.Min((float64(nav.CurrentPage)+math.Floor(float64(pagesSelectable)/2)), maxPages)) - pagesSelectable + 1)
}
endValue := (startValue + pagesSelectable -1)
endValue := (startValue + pagesSelectable - 1)
if endValue > int(maxPages) {
endValue = int(maxPages)
}
@ -60,12 +60,12 @@ var FuncMap = template.FuncMap{
return template.HTML(ret)
},
"T": i18n.IdentityTfunc,
"getAvatar": func (hash string, size int) string {
return "https://www.gravatar.com/avatar/"+hash+"?s="+strconv.Itoa(size)
"getAvatar": func(hash string, size int) string {
return "https://www.gravatar.com/avatar/" + hash + "?s=" + strconv.Itoa(size)
},
"CurrentOrAdmin": userPermission.CurrentOrAdmin,
"CurrentOrAdmin": userPermission.CurrentOrAdmin,
"CurrentUserIdentical": userPermission.CurrentUserIdentical,
"HasAdmin": userPermission.HasAdmin,
"GetRole": userPermission.GetRole,
"IsFollower": userPermission.IsFollower,
"HasAdmin": userPermission.HasAdmin,
"GetRole": userPermission.GetRole,
"IsFollower": userPermission.IsFollower,
}

Voir le fichier

@ -35,7 +35,7 @@ type NotFoundTemplateVariables struct {
}
type ViewTemplateVariables struct {
Torrent model.TorrentsJson
Torrent model.TorrentJSON
Captcha captcha.Captcha
Search SearchForm
Navigation Navigation
@ -55,15 +55,15 @@ type UserRegisterTemplateVariables struct {
}
type UserProfileEditVariables struct {
UserProfile *model.User
UserForm userForms.UserForm
FormErrors map[string][]string
FormInfos map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
UserProfile *model.User
UserForm userForms.UserForm
FormErrors map[string][]string
FormInfos map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
type UserVerifyTemplateVariables struct {
@ -96,7 +96,7 @@ type UserProfileVariables struct {
}
type HomeTemplateVariables struct {
ListTorrents []model.TorrentsJson
ListTorrents []model.TorrentJSON
Search SearchForm
Navigation Navigation
User *model.User

Voir le fichier

@ -31,8 +31,8 @@ type UploadForm struct {
captcha.Captcha
Infohash string
CategoryId int
SubCategoryId int
CategoryID int
SubCategoryID int
Filesize int64
Filepath string
}
@ -86,11 +86,11 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
f.Captcha = captcha.Extract(r)
if !captcha.Authenticate(f.Captcha) {
// TODO: Prettier passing of mistyoed captcha errors
// TODO: Prettier passing of mistyped Captcha errors
return errors.New(captcha.ErrInvalidCaptcha.Error())
}
// trim whitespaces
// trim whitespace
f.Name = util.TrimWhitespaces(f.Name)
f.Description = p.Sanitize(util.TrimWhitespaces(f.Description))
f.Magnet = util.TrimWhitespaces(f.Magnet)
@ -98,17 +98,17 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
catsSplit := strings.Split(f.Category, "_")
// need this to prevent out of index panics
if len(catsSplit) == 2 {
CatId, err := strconv.Atoi(catsSplit[0])
CatID, err := strconv.Atoi(catsSplit[0])
if err != nil {
return ErrInvalidTorrentCategory
}
SubCatId, err := strconv.Atoi(catsSplit[1])
SubCatID, err := strconv.Atoi(catsSplit[1])
if err != nil {
return ErrInvalidTorrentCategory
}
f.CategoryId = CatId
f.SubCategoryId = SubCatId
f.CategoryID = CatID
f.SubCategoryID = SubCatID
} else {
return ErrInvalidTorrentCategory
}
@ -119,7 +119,10 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
var torrent metainfo.TorrentFile
// decode torrent
tfile.Seek(0, io.SeekStart)
_, seekErr := tfile.Seek(0, io.SeekStart)
if seekErr != nil {
return seekErr
}
err = bencode.NewDecoder(tfile).Decode(&torrent)
if err != nil {
return metainfo.ErrInvalidTorrentFile
@ -143,7 +146,10 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
if len(f.Magnet) != 0 {
return ErrTorrentPlusMagnet
}
binInfohash := torrent.Infohash()
binInfohash, err := torrent.Infohash()
if err != nil {
return err
}
f.Infohash = strings.ToUpper(hex.EncodeToString(binInfohash[:]))
f.Magnet = util.InfoHashToMagnet(f.Infohash, f.Name, trackers...)
@ -151,11 +157,11 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
f.Filesize = int64(torrent.TotalSize())
} else {
// No torrent file provided
magnetUrl, parseErr := url.Parse(f.Magnet)
magnetURL, parseErr := url.Parse(f.Magnet)
if parseErr != nil {
return metainfo.ErrInvalidTorrentFile
}
exactTopic := magnetUrl.Query().Get("xt")
exactTopic := magnetURL.Query().Get("xt")
if !strings.HasPrefix(exactTopic, "urn:btih:") {
return metainfo.ErrInvalidTorrentFile
}
@ -174,10 +180,6 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
return ErrInvalidTorrentName
}
//if len(f.Description) == 0 {
// return ErrInvalidTorrentDescription
//}
// after data has been checked & extracted, write it to disk
if len(config.TorrentFileStorage) > 0 {
err := WriteTorrentToDisk(tfile, f.Infohash+".torrent", &f.Filepath)
@ -192,7 +194,10 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
}
func WriteTorrentToDisk(file multipart.File, name string, fullpath *string) error {
file.Seek(0, io.SeekStart)
_, seekErr := file.Seek(0, io.SeekStart)
if seekErr != nil {
return seekErr
}
b, err := ioutil.ReadAll(file)
if err != nil {
return err
@ -201,29 +206,30 @@ func WriteTorrentToDisk(file multipart.File, name string, fullpath *string) erro
return ioutil.WriteFile(*fullpath, b, 0644)
}
var dead_trackers = []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"}
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 {
var good bool = true
for _, check := range dead_trackers {
good := true
for _, check := range deadTrackers {
if strings.Contains(t, check) {
good = false
}
}
if good {
numGood += 1
numGood++
}
}
return numGood > 0

Voir le fichier

@ -11,59 +11,58 @@ import (
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/captcha"
"github.com/ewhal/nyaa/service/user"
"github.com/ewhal/nyaa/util"
"github.com/ewhal/nyaa/util/languages"
"github.com/gorilla/mux"
)
func UploadHandler(w http.ResponseWriter, r *http.Request) {
if config.UploadsDisabled == 1 {
if config.UploadsDisabled {
http.Error(w, "Error uploads are disabled", http.StatusInternalServerError)
return
}
var err error
var uploadForm UploadForm
if r.Method == "POST" {
defer r.Body.Close()
// validation is done in ExtractInfo()
err = uploadForm.ExtractInfo(r)
if err == nil {
user, _, err := userService.RetrieveCurrentUser(r)
if err != nil {
fmt.Printf("error %+v\n", err)
}
//add to db and redirect depending on result
torrent := model.Torrents{
Name: uploadForm.Name,
Category: uploadForm.CategoryId,
Sub_Category: uploadForm.SubCategoryId,
Status: 1,
Hash: uploadForm.Infohash,
Date: time.Now(),
Filesize: uploadForm.Filesize, // FIXME: should set to NULL instead of 0
Description: uploadForm.Description,
UploaderId: user.Id}
err = db.ORM.Create(&torrent).Error
if err != nil {
util.SendError(w, err, 500)
return
}
fmt.Printf("%+v\n", torrent)
url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.Id), 10))
if err == nil {
http.Redirect(w, r, url.String(), 302)
}
err := uploadForm.ExtractInfo(r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
user, _, err := userService.RetrieveCurrentUser(r)
if err != nil {
fmt.Printf("error %+v\n", err)
}
//add to db and redirect depending on result
torrent := model.Torrent{
Name: uploadForm.Name,
Category: uploadForm.CategoryID,
SubCategory: uploadForm.SubCategoryID,
Status: 1,
Hash: uploadForm.Infohash,
Date: time.Now(),
Filesize: uploadForm.Filesize,
Description: uploadForm.Description,
UploaderID: user.ID}
db.ORM.Create(&torrent)
fmt.Printf("%+v\n", torrent)
url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.ID), 10))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, url.String(), 302)
} else if r.Method == "GET" {
uploadForm.CaptchaID = captcha.GetID()
htv := UploadTemplateVariables{uploadForm, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
languages.SetTranslationFromRequest(uploadTemplate, r, "en-us")
err = uploadTemplate.ExecuteTemplate(w, "index.html", htv)
err := uploadTemplate.ExecuteTemplate(w, "index.html", htv)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
} else {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}

Voir le fichier

@ -5,7 +5,6 @@ import (
"net/http"
"strconv"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/captcha"
"github.com/ewhal/nyaa/service/user"
@ -16,13 +15,10 @@ import (
"github.com/gorilla/mux"
)
//var viewTemplate = template.Must(template.New("view").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/view.html"))
//var viewTemplate = template.Must(template.New("view").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/view.html"))
// Getting View User Registration
func UserRegisterFormHandler(w http.ResponseWriter, r *http.Request) {
_, errorUser := userService.CurrentUser(r)
if (errorUser != nil) {
if errorUser != nil {
b := form.RegistrationForm{}
modelHelper.BindValueForm(&b, r)
b.CaptchaID = captcha.GetID()
@ -56,15 +52,15 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
userProfile, _, errorUser := userService.RetrieveUserForAdmin(id)
if (errorUser == nil) {
currentUser := GetUser(r)
view := r.URL.Query()["edit"]
follow := r.URL.Query()["followed"]
unfollow := r.URL.Query()["unfollowed"]
infosForm := form.NewInfos()
if errorUser == nil {
currentUser := GetUser(r)
view := r.URL.Query()["edit"]
follow := r.URL.Query()["followed"]
unfollow := r.URL.Query()["unfollowed"]
infosForm := form.NewInfos()
deleteVar := r.URL.Query()["delete"]
deleteVar := r.URL.Query()["delete"]
if ((view != nil)&&(userPermission.CurrentOrAdmin(currentUser, userProfile.Id))) {
if (view != nil) && (userPermission.CurrentOrAdmin(currentUser, userProfile.ID)) {
b := form.UserForm{}
modelHelper.BindValueForm(&b, r)
languages.SetTranslationFromRequest(viewProfileEditTemplate, r, "en-us")
@ -74,10 +70,10 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
} else if ((deleteVar != nil)&&(userPermission.CurrentOrAdmin(currentUser, userProfile.Id))) {
} else if (deleteVar != nil) && (userPermission.CurrentOrAdmin(currentUser, userProfile.ID)) {
err := form.NewErrors()
_, errUser := userService.DeleteUser(w, currentUser, id)
if (errUser != nil) {
if errUser != nil {
err["errors"] = append(err["errors"], errUser.Error())
}
languages.SetTranslationFromRequest(viewUserDeleteTemplate, r, "en-us")
@ -86,14 +82,14 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
if errorTmpl != nil {
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
}
} else {
} else {
T := languages.SetTranslationFromRequest(viewProfileTemplate, r, "en-us")
if (follow != nil) {
if follow != nil {
infosForm["infos"] = append(infosForm["infos"], fmt.Sprintf(T("user_followed_msg"), userProfile.Username))
}
if (unfollow != nil) {
if unfollow != nil {
infosForm["infos"] = append(infosForm["infos"], fmt.Sprintf(T("user_unfollowed_msg"), userProfile.Username))
}
}
htv := UserProfileVariables{&userProfile, infosForm, NewSearchForm(), Navigation{}, currentUser, r.URL, mux.CurrentRoute(r)}
err := viewProfileTemplate.ExecuteTemplate(w, "index.html", htv)
@ -119,8 +115,8 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) {
id := vars["id"]
currentUser := GetUser(r)
userProfile, _, errorUser := userService.RetrieveUserForAdmin(id)
if (errorUser == nil) {
if (userPermission.CurrentOrAdmin(currentUser, userProfile.Id)) {
if errorUser == nil {
if userPermission.CurrentOrAdmin(currentUser, userProfile.ID) {
b := form.UserForm{}
err := form.NewErrors()
infos := form.NewInfos()
@ -129,20 +125,20 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) {
_, err = form.EmailValidation(r.PostFormValue("email"), err)
}
if len(r.PostFormValue("username")) > 0 {
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
}
if (len(err) == 0) {
if len(err) == 0 {
modelHelper.BindValueForm(&b, r)
err = modelHelper.ValidateForm(&b, err)
if (len(err) == 0) {
if len(err) == 0 {
userProfile, _, errorUser = userService.UpdateUser(w, &b, currentUser, id)
if (errorUser != nil) {
if errorUser != nil {
err["errors"] = append(err["errors"], errorUser.Error())
}
if (len(err) == 0) {
if len(err) == 0 {
infos["infos"] = append(infos["infos"], T("profile_updated"))
}
}
}
}
}
htv := UserProfileEditVariables{&userProfile, b, err, infos, NewSearchForm(), Navigation{}, currentUser, r.URL, mux.CurrentRoute(r)}
errorTmpl := viewProfileEditTemplate.ExecuteTemplate(w, "index.html", htv)
@ -179,20 +175,20 @@ func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) {
if !captcha.Authenticate(captcha.Extract(r)) {
err["errors"] = append(err["errors"], "Wrong captcha!")
}
if (len(err) == 0) {
if len(err) == 0 {
if len(r.PostFormValue("email")) > 0 {
_, err = form.EmailValidation(r.PostFormValue("email"), err)
}
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
if (len(err) == 0) {
if len(err) == 0 {
modelHelper.BindValueForm(&b, r)
err = modelHelper.ValidateForm(&b, err)
if (len(err) == 0) {
if len(err) == 0 {
_, errorUser := userService.CreateUser(w, r)
if (errorUser != nil) {
if errorUser != nil {
err["errors"] = append(err["errors"], errorUser.Error())
}
if (len(err) == 0) {
if len(err) == 0 {
languages.SetTranslationFromRequest(viewRegisterSuccessTemplate, r, "en-us")
u := model.User{
Email: r.PostFormValue("email"), // indicate whether user had email set
@ -202,11 +198,11 @@ func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) {
if errorTmpl != nil {
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
}
}
}
}
}
}
}
}
if (len(err) > 0) {
if len(err) > 0 {
b.CaptchaID = captcha.GetID()
languages.SetTranslationFromRequest(viewRegisterTemplate, r, "en-us")
htv := UserRegisterTemplateVariables{b, err, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
@ -222,7 +218,7 @@ func UserVerifyEmailHandler(w http.ResponseWriter, r *http.Request) {
token := vars["token"]
err := form.NewErrors()
_, errEmail := userService.EmailVerification(token, w)
if (errEmail != nil) {
if errEmail != nil {
err["errors"] = append(err["errors"], errEmail.Error())
}
languages.SetTranslationFromRequest(viewVerifySuccessTemplate, r, "en-us")
@ -239,9 +235,9 @@ func UserLoginPostHandler(w http.ResponseWriter, r *http.Request) {
modelHelper.BindValueForm(&b, r)
err := form.NewErrors()
err = modelHelper.ValidateForm(&b, err)
if (len(err) == 0) {
if len(err) == 0 {
_, errorUser := userService.CreateUserAuthentication(w, r)
if (errorUser != nil) {
if errorUser != nil {
err["errors"] = append(err["errors"], errorUser.Error())
languages.SetTranslationFromRequest(viewLoginTemplate, r, "en-us")
htv := UserLoginFormVariables{b, err, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
@ -265,15 +261,14 @@ func UserLogoutHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, url.String(), http.StatusSeeOther)
}
func UserFollowHandler(w http.ResponseWriter, r *http.Request) {
var followAction string
vars := mux.Vars(r)
id := vars["id"]
currentUser := GetUser(r)
user, _, errorUser := userService.RetrieveUserForAdmin(id)
if (errorUser == nil) {
if (!userPermission.IsFollower(&user, currentUser)) {
if errorUser == nil {
if !userPermission.IsFollower(&user, currentUser) {
followAction = "followed"
userService.SetFollow(&user, currentUser)
} else {
@ -281,6 +276,6 @@ func UserFollowHandler(w http.ResponseWriter, r *http.Request) {
userService.RemoveFollow(&user, currentUser)
}
}
url, _ := Router.Get("user_profile").URL("id", strconv.Itoa(int(user.Id)), "username", user.Username)
url, _ := Router.Get("user_profile").URL("id", strconv.Itoa(int(user.ID)), "username", user.Username)
http.Redirect(w, r, url.String()+"?"+followAction, http.StatusSeeOther)
}

Voir le fichier

@ -24,7 +24,7 @@ func ViewHandler(w http.ResponseWriter, r *http.Request) {
NotFoundHandler(w, r)
return
}
b := torrent.ToJson()
b := torrent.ToJSON()
htv := ViewTemplateVariables{b, captcha.Captcha{CaptchaID: captcha.GetID()}, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
languages.SetTranslationFromRequest(viewTemplate, r, "en-us")
@ -45,14 +45,14 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) {
currentUser := GetUser(r)
content := p.Sanitize(r.FormValue("comment"))
idNum_, err := strconv.Atoi(id)
var idNum uint = uint(idNum_)
var userId uint = 0
if currentUser.Id > 0 {
userId = currentUser.Id
idNum, err := strconv.Atoi(id)
if currentUser.ID <= 0 {
http.Error(w, "Invalid user ID", http.StatusInternalServerError)
}
comment := model.Comment{TorrentId: idNum, UserId: userId, Content: content, CreatedAt: time.Now()}
err = db.ORM.Create(&comment).Error
userID := currentUser.ID
comment := model.Comment{TorrentID: uint(idNum), UserID: userID, Content: content, CreatedAt: time.Now()}
err = db.ORM.Create(&comment).Error
if err != nil {
util.SendError(w, err, 500)
return

Voir le fichier

@ -36,7 +36,7 @@ type TorrentRequest struct {
}
type UpdateRequest struct {
Id int `json:"id"`
ID int `json:"id"`
Update TorrentRequest `json:"update"`
}
@ -155,7 +155,7 @@ func (r *TorrentRequest) ValidateUpdate() (err error, code int) {
}
//rewrite with reflect ?
func (r *UpdateRequest) UpdateTorrent(t *model.Torrents) {
func (r *UpdateRequest) UpdateTorrent(t *model.Torrent) {
if r.Update.Name != "" {
t.Name = r.Update.Name
}
@ -166,7 +166,7 @@ func (r *UpdateRequest) UpdateTorrent(t *model.Torrents) {
t.Category = r.Update.Category
}
if r.Update.SubCategory != 0 {
t.Sub_Category = r.Update.SubCategory
t.SubCategory = r.Update.SubCategory
}
if r.Update.Description != "" {
t.Description = r.Update.Description

Voir le fichier

@ -19,12 +19,12 @@ func init() {
captcha.SetCustomStore(captcha.NewMemoryStore(1<<10, lifetime))
}
// Captcha is to be embedded into any form struct requiring a captcha
// Captcha is to be embedded into any form struct requiring a Captcha
type Captcha struct {
CaptchaID, Solution string
}
// GetID returns a new captcha id
// GetID returns a new Captcha ID
func GetID() string {
return captcha.New()
}
@ -37,12 +37,12 @@ func Extract(r *http.Request) Captcha {
}
}
// ServeFiles serves captcha images and audio
// ServeFiles serves Captcha images and audio
func ServeFiles(w http.ResponseWriter, r *http.Request) {
server.ServeHTTP(w, r)
}
// Authenticate check's if a captcha solution is valid
// Authenticate check's if a Captcha solution is valid
func Authenticate(req Captcha) bool {
return captcha.VerifyString(req.CaptchaID, req.Solution)
}

Voir le fichier

@ -2,13 +2,12 @@ package torrentService
import (
"errors"
"strconv"
"strings"
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/util"
"strconv"
"strings"
)
type WhereParams struct {
@ -36,20 +35,20 @@ func GetFeeds() (result []model.Feed, err error) {
for rows.Next() {
item := model.Feed{}
err = rows.Scan(&item.Id, &item.Name, &item.Hash, &item.Timestamp)
err = rows.Scan(&item.ID, &item.Name, &item.Hash, &item.Timestamp)
if err != nil {
return
}
magnet := util.InfoHashToMagnet(strings.TrimSpace(item.Hash), item.Name, config.Trackers...)
item.Magnet = magnet
// memory hog
// TODO: memory hog
result = append(result, item)
}
err = rows.Err()
return
}
func GetTorrentById(id string) (torrent model.Torrents, err error) {
func GetTorrentById(id string) (torrent model.Torrent, err error) {
id_int, err := strconv.Atoi(id)
if err != nil {
return
@ -60,7 +59,7 @@ func GetTorrentById(id string) (torrent model.Torrents, err error) {
if err != nil {
return
}
if id_int <= config.LastOldTorrentId {
if id_int <= config.LastOldTorrentID {
// only preload old comments if they could actually exist
tmp = tmp.Preload("OldComments")
}
@ -71,10 +70,10 @@ func GetTorrentById(id string) (torrent model.Torrents, err error) {
// GORM relly likes not doing its job correctly
// (or maybe I'm just retarded)
torrent.Uploader = new(model.User)
db.ORM.Where("user_id = ?", torrent.UploaderId).Find(torrent.Uploader)
db.ORM.Where("user_id = ?", torrent.UploaderID).Find(torrent.Uploader)
for i := range torrent.Comments {
torrent.Comments[i].User = new(model.User)
err = db.ORM.Where("user_id = ?", torrent.Comments[i].UserId).Find(torrent.Comments[i].User).Error
err = db.ORM.Where("user_id = ?", torrent.Comments[i].UserID).Find(torrent.Comments[i].User).Error
if err != nil {
return
}
@ -83,22 +82,22 @@ func GetTorrentById(id string) (torrent model.Torrents, err error) {
return
}
func GetTorrentsOrderByNoCount(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrents, err error) {
func GetTorrentsOrderByNoCount(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, err error) {
torrents, _, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, false)
return
}
func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrents, count int, err error) {
func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, count int, err error) {
torrents, count, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, true)
return
}
func getTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int, countAll bool) (
torrents []model.Torrents, count int, err error,
torrents []model.Torrent, count int, err error,
) {
var conditionArray []string
if strings.HasPrefix(orderBy, "filesize") {
// torrents w/ NULL filesize fuck up the sorting on postgres
// torrents w/ NULL filesize fuck up the sorting on Postgres
conditionArray = append(conditionArray, "filesize IS NOT NULL")
}
var params []interface{}
@ -137,32 +136,28 @@ func getTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offs
return
}
/* Functions to simplify the get parameters of the main function
*
* Get Torrents with where parameters and limits, order by default
*/
func GetTorrents(parameters WhereParams, limit int, offset int) ([]model.Torrents, int, error) {
// GetTorrents obtain a list of torrents matching 'parameters' from the
// database. The list will be of length 'limit' and in default order.
// GetTorrents returns the first records found. Later records may be retrieved
// by providing a positive 'offset'
func GetTorrents(parameters WhereParams, limit int, offset int) ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(&parameters, "", limit, offset)
}
/* Get Torrents with where parameters but no limit and order by default (get all the torrents corresponding in the db)
*/
func GetTorrentsDB(parameters WhereParams) ([]model.Torrents, int, error) {
// Get Torrents with where parameters but no limit and order by default (get all the torrents corresponding in the db)
func GetTorrentsDB(parameters WhereParams) ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(&parameters, "", 0, 0)
}
/* Function to get all torrents
*/
func GetAllTorrentsOrderBy(orderBy string, limit int, offset int) ([]model.Torrents, int, error) {
func GetAllTorrentsOrderBy(orderBy string, limit int, offset int) ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(nil, orderBy, limit, offset)
}
func GetAllTorrents(limit int, offset int) ([]model.Torrents, int, error) {
func GetAllTorrents(limit int, offset int) ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(nil, "", limit, offset)
}
func GetAllTorrentsDB() ([]model.Torrents, int, error) {
func GetAllTorrentsDB() ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(nil, "", 0, 0)
}

Voir le fichier

@ -2,8 +2,6 @@ package userService
import (
"errors"
"net/http"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
formStruct "github.com/ewhal/nyaa/service/user/form"
@ -11,12 +9,14 @@ import (
"github.com/ewhal/nyaa/util/modelHelper"
"github.com/gorilla/securecookie"
"golang.org/x/crypto/bcrypt"
"net/http"
)
var cookieHandler = securecookie.New(
securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32))
// TODO: Figure out what this is about before I delete it
// // UserName get username from a cookie.
// func UserName(c *gin.Context) (string, error) {
// var userName string
@ -47,7 +47,7 @@ func Token(r *http.Request) (string, error) {
}
token = cookieValue["token"]
if len(token) == 0 {
return token, errors.New("Token is empty.")
return token, errors.New("token is empty")
}
return token, nil
}
@ -91,17 +91,17 @@ func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, er
if isValidEmail {
log.Debug("User entered valid email.")
if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() {
return http.StatusNotFound, errors.New("User is not found.")
return http.StatusNotFound, errors.New("user not found")
}
} else {
log.Debug("User entered username.")
if db.ORM.Where("username = ?", email).First(&user).RecordNotFound() {
return http.StatusNotFound, errors.New("User is not found.")
return http.StatusNotFound, errors.New("user not found")
}
}
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(pass))
if err != nil {
return http.StatusUnauthorized, errors.New("Password incorrect.")
return http.StatusUnauthorized, errors.New("password incorrect")
}
status, err := SetCookie(w, user.Token)
if err != nil {
@ -109,17 +109,13 @@ func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, er
}
w.Header().Set("X-Auth-Token", user.Token)
return http.StatusOK, nil
} else {
return http.StatusNotFound, errors.New("User is not found.")
}
return http.StatusNotFound, errors.New("user not found")
}
// RegisterHanderFromForm sets cookie from a RegistrationForm.
func RegisterHanderFromForm(w http.ResponseWriter, registrationForm formStruct.RegistrationForm) (int, error) {
email := registrationForm.Email
if email == "" {
email = registrationForm.Username
}
pass := registrationForm.Password
log.Debugf("RegisterHandler UserEmail : %s", email)
log.Debugf("RegisterHandler UserPassword : %s", pass)
@ -140,16 +136,16 @@ func CurrentUser(r *http.Request) (model.User, error) {
var err error
token = r.Header.Get("X-Auth-Token")
if len(token) > 0 {
log.Debug("header token exist.")
log.Debug("header token exists")
} else {
token, err = Token(r)
log.Debug("header token not exist.")
log.Debug("header token does not exist")
if err != nil {
return user, err
}
}
if db.ORM.Where("api_token = ?", token).First(&user).RecordNotFound() {
return user, errors.New("User is not found.")
return user, errors.New("user not found")
}
err = db.ORM.Model(&user).Error
return user, err

Voir le fichier

@ -15,11 +15,12 @@ func EmailValidation(email string, err map[string][]string) (bool, map[string][]
if exp.MatchString(email) {
return true, err
}
}
}
err["email"] = append(err["email"], "Email Address is not valid")
return false, err
}
func ValidateUsername(username string, err map[string][]string) (bool, map[string][]string) {
func ValidateUsername(username string, err map[string][]string) (bool, map[string][]string) {
exp, errorRegex := regexp.Compile(USERNAME_REGEX)
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
if exp.MatchString(username) {
@ -40,38 +41,36 @@ func NewInfos() map[string][]string {
infos := make(map[string][]string)
return infos
}
func IsAgreed(t_and_c string) bool {
if t_and_c == "1" {
return true
}
return false
func IsAgreed(termsAndConditions string) bool { // TODO: Inline function
return termsAndConditions == "1"
}
// RegistrationForm is used when creating a user.
type RegistrationForm struct {
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email" needed:"true"`
Password string `form:"password" needed:"true" len_min:"6" len_max:"25" equalInput:"Confirm_Password"`
Confirm_Password string `form:"password_confirmation" omit:"true" needed:"true"`
CaptchaID string `form:"captchaID" omit:"true" needed:"true"`
T_and_C bool `form:"t_and_c" omit:"true" needed:"true" equal:"true" hum_name:"Terms and Conditions"`
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email" needed:"true"`
Password string `form:"password" needed:"true" len_min:"6" len_max:"25" equalInput:"ConfirmPassword"`
ConfirmPassword string `form:"password_confirmation" omit:"true" needed:"true"`
CaptchaID string `form:"captchaID" omit:"true" needed:"true"`
TermsAndConditions bool `form:"t_and_c" omit:"true" needed:"true" equal:"true" hum_name:"Terms and Conditions"`
}
// LoginForm is used when a user logs in.
type LoginForm struct {
Username string `form:"username" needed="true"`
Password string `form:"password" needed="true"`
Username string `form:"username" needed:"true"`
Password string `form:"password" needed:"true"`
}
// UserForm is used when updating a user.
type UserForm struct {
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email" needed:"true"`
Language string `form:"language" default:"en-us"`
CurrentPassword string `form:"password" len_min:"6" len_max:"25" omit:"true"`
Password string `form:"password" len_min:"6" len_max:"25" equalInput:"Confirm_Password"`
Confirm_Password string `form:"password_confirmation" omit:"true"`
Status int `form:"language" default:"0"`
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email" needed:"true"`
Language string `form:"language" default:"en-us"`
CurrentPassword string `form:"password" len_min:"6" len_max:"25" omit:"true"`
Password string `form:"password" len_min:"6" len_max:"25" equalInput:"ConfirmPassword"`
ConfirmPassword string `form:"password_confirmation" omit:"true"`
Status int `form:"language" default:"0"`
}
// PasswordForm is used when updating a user password.

Voir le fichier

@ -1,9 +1,9 @@
package userPermission
import (
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/db"
)
// HasAdmin checks that user has an admin permission.
@ -12,29 +12,26 @@ func HasAdmin(user *model.User) bool {
}
// CurrentOrAdmin check that user has admin permission or user is the current user.
func CurrentOrAdmin(user *model.User, userId uint) bool {
log.Debugf("user.Id == userId %d %d %s", user.Id, userId, user.Id == userId)
return (HasAdmin(user) || user.Id == userId)
func CurrentOrAdmin(user *model.User, userID uint) bool {
log.Debugf("user.ID == userID %d %d %s", user.ID, userID, user.ID == userID)
return (HasAdmin(user) || user.ID == userID)
}
// CurrentUserIdentical check that userId is same as current user's Id.
func CurrentUserIdentical(user *model.User, userId uint) (bool) {
if user.Id != userId {
return false
}
return true
// CurrentUserIdentical check that userID is same as current user's ID.
// TODO: Inline this
func CurrentUserIdentical(user *model.User, userID uint) bool {
return user.ID != userID
}
func GetRole(user *model.User) string {
switch user.Status {
case -1 :
case -1:
return "Banned"
case 0 :
case 0:
return "Member"
case 1 :
case 1:
return "Trusted Member"
case 2 :
case 2:
return "Moderator"
}
return "Member"
@ -42,9 +39,9 @@ func GetRole(user *model.User) string {
func IsFollower(user *model.User, currentUser *model.User) bool {
var likingUserCount int
db.ORM.Model(&model.UserFollows{}).Where("user_id = ? and following = ?", user.Id, currentUser.Id).Count(&likingUserCount)
db.ORM.Model(&model.UserFollows{}).Where("user_id = ? and following = ?", user.ID, currentUser.ID).Count(&likingUserCount)
if likingUserCount != 0 {
return true
}
return false
}
}

Voir le fichier

@ -19,8 +19,6 @@ import (
"golang.org/x/crypto/bcrypt"
)
var userFields []string = []string{"name", "email", "createdAt", "updatedAt"}
// SuggestUsername suggest user's name if user's name already occupied.
func SuggestUsername(username string) string {
var count int
@ -29,17 +27,16 @@ func SuggestUsername(username string) string {
log.Debugf("count Before : %d", count)
if count == 0 {
return username
} else {
var postfix int
for {
usernameCandidate = username + strconv.Itoa(postfix)
log.Debugf("usernameCandidate: %s\n", usernameCandidate)
db.ORM.Model(model.User{}).Where(&model.User{Username: usernameCandidate}).Count(&count)
log.Debugf("count after : %d\n", count)
postfix = postfix + 1
if count == 0 {
break
}
}
var postfix int
for {
usernameCandidate = username + strconv.Itoa(postfix)
log.Debugf("usernameCandidate: %s\n", usernameCandidate)
db.ORM.Model(model.User{}).Where(&model.User{Username: usernameCandidate}).Count(&count)
log.Debugf("count after : %d\n", count)
postfix = postfix + 1
if count == 0 {
break
}
}
return usernameCandidate
@ -63,20 +60,24 @@ func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.Use
log.Debugf("registrationForm %+v\n", registrationForm)
modelHelper.AssignValue(&user, &registrationForm)
if user.Email == "" {
user.Md5 = ""
user.MD5 = ""
} else {
user.Md5 = crypto.GenerateMD5Hash(user.Email)
var err error
user.MD5, err = crypto.GenerateMD5Hash(user.Email)
if err != nil {
return user, err
}
}
token, err := crypto.GenerateRandomToken32()
if err != nil {
return user, errors.New("Token not generated.")
return user, errors.New("token not generated")
}
user.Token = token
user.TokenExpiration = timeHelper.FewDaysLater(config.AuthTokenExpirationDay)
log.Debugf("user %+v\n", user)
if db.ORM.Create(&user).Error != nil {
return user, errors.New("User is not created.")
return user, errors.New("user not created")
}
user.CreatedAt = time.Now()
@ -96,7 +97,7 @@ func CreateUser(w http.ResponseWriter, r *http.Request) (int, error) {
return http.StatusInternalServerError, fmt.Errorf("Username already taken, you can choose: %s", usernameCandidate)
}
if CheckEmail(registrationForm.Email) {
return http.StatusInternalServerError, errors.New("Email Address already in our database!")
return http.StatusInternalServerError, errors.New("email address already in database")
}
password, err := bcrypt.GenerateFromPassword([]byte(registrationForm.Password), 10)
if err != nil {
@ -115,20 +116,19 @@ func CreateUser(w http.ResponseWriter, r *http.Request) (int, error) {
// RetrieveUser retrieves a user.
func RetrieveUser(r *http.Request, id string) (*model.PublicUser, bool, uint, int, error) {
var user model.User
var currentUserId uint
var currentUserID uint
var isAuthor bool
// var publicUser *model.PublicUser
// publicUser.User = &user
if db.ORM.First(&user, id).RecordNotFound() {
return nil, isAuthor, currentUserId, http.StatusNotFound, errors.New("User is not found.")
return nil, isAuthor, currentUserID, http.StatusNotFound, errors.New("user not found")
}
currentUser, err := CurrentUser(r)
if err == nil {
currentUserId = currentUser.Id
isAuthor = currentUser.Id == user.Id
currentUserID = currentUser.ID
isAuthor = currentUser.ID == user.ID
}
return &model.PublicUser{User: &user}, isAuthor, currentUserId, http.StatusOK, nil
return &model.PublicUser{User: &user}, isAuthor, currentUserID, http.StatusOK, nil
}
// RetrieveUsers retrieves users.
@ -144,19 +144,23 @@ func RetrieveUsers() []*model.PublicUser {
// UpdateUserCore updates a user. (Applying the modifed data of user).
func UpdateUserCore(user *model.User) (int, error) {
if user.Email == "" {
user.Md5 = ""
user.MD5 = ""
} else {
user.Md5 = crypto.GenerateMD5Hash(user.Email)
var err error
user.MD5, err = crypto.GenerateMD5Hash(user.Email)
if err != nil {
return http.StatusInternalServerError, err
}
}
token, err := crypto.GenerateRandomToken32()
if err != nil {
return http.StatusInternalServerError, errors.New("Token not generated.")
return http.StatusInternalServerError, err
}
user.Token = token
user.TokenExpiration = timeHelper.FewDaysLater(config.AuthTokenExpirationDay)
if db.ORM.Save(user).Error != nil {
return http.StatusInternalServerError, errors.New("User is not updated.")
return http.StatusInternalServerError, err
}
user.UpdatedAt = time.Now()
@ -167,22 +171,20 @@ func UpdateUserCore(user *model.User) (int, error) {
func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *model.User, id string) (model.User, int, error) {
var user model.User
if db.ORM.First(&user, id).RecordNotFound() {
return user, http.StatusNotFound, errors.New("User is not found.")
return user, http.StatusNotFound, errors.New("user not found")
}
if form.Password != "" {
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(form.CurrentPassword))
if err != nil && !userPermission.HasAdmin(currentUser) {
log.Error("Password Incorrect.")
return user, http.StatusInternalServerError, errors.New("User is not updated. Password Incorrect.")
} else {
newPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), 10)
if err != nil {
return user, http.StatusInternalServerError, errors.New("User is not updated. Password not Generated.")
} else {
form.Password = string(newPassword)
}
return user, http.StatusInternalServerError, errors.New("password incorrect")
}
newPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), 10)
if err != nil {
return user, http.StatusInternalServerError, errors.New("password not generated")
}
form.Password = string(newPassword)
} else { // Then no change of password
form.Password = user.Password
}
@ -197,7 +199,7 @@ func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *m
if err != nil {
return user, status, err
}
if userPermission.CurrentUserIdentical(currentUser, user.Id) {
if userPermission.CurrentUserIdentical(currentUser, user.ID) {
status, err = SetCookie(w, user.Token)
}
return user, status, err
@ -207,12 +209,12 @@ func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *m
func DeleteUser(w http.ResponseWriter, currentUser *model.User, id string) (int, error) {
var user model.User
if db.ORM.First(&user, id).RecordNotFound() {
return http.StatusNotFound, errors.New("User is not found.")
return http.StatusNotFound, errors.New("user not found")
}
if db.ORM.Delete(&user).Error != nil {
return http.StatusInternalServerError, errors.New("User is not deleted.")
return http.StatusInternalServerError, errors.New("user not deleted")
}
if userPermission.CurrentUserIdentical(currentUser, user.Id) {
if userPermission.CurrentUserIdentical(currentUser, user.ID) {
return ClearCookie(w)
}
return http.StatusOK, nil
@ -231,7 +233,7 @@ func RetrieveCurrentUser(r *http.Request) (model.User, int, error) {
func RetrieveUserByEmail(email string) (*model.PublicUser, string, int, error) {
var user model.User
if db.ORM.Unscoped().Where("email = ?", email).First(&user).RecordNotFound() {
return &model.PublicUser{User: &user}, email, http.StatusNotFound, errors.New("User is not found.")
return &model.PublicUser{User: &user}, email, http.StatusNotFound, errors.New("user not found")
}
return &model.PublicUser{User: &user}, email, http.StatusOK, nil
}
@ -251,7 +253,7 @@ func RetrieveUsersByEmail(email string) []*model.PublicUser {
func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, error) {
var user model.User
if db.ORM.Where("username = ?", username).First(&user).RecordNotFound() {
return &model.PublicUser{User: &user}, username, http.StatusNotFound, errors.New("User is not found.")
return &model.PublicUser{User: &user}, username, http.StatusNotFound, errors.New("user not found")
}
return &model.PublicUser{User: &user}, username, http.StatusOK, nil
}
@ -260,11 +262,11 @@ func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, er
func RetrieveUserForAdmin(id string) (model.User, int, error) {
var user model.User
if db.ORM.Preload("Torrents").First(&user, id).RecordNotFound() {
return user, http.StatusNotFound, errors.New("User is not found.")
return user, http.StatusNotFound, errors.New("user not found")
}
var liked,likings []model.User
db.ORM.Joins("JOIN user_follows on user_follows.user_id=?", user.Id).Where("users.user_id = user_follows.following").Group("users.user_id").Find(&likings)
db.ORM.Joins("JOIN user_follows on user_follows.following=?", user.Id).Where("users.user_id = user_follows.user_id").Group("users.user_id").Find(&liked)
var liked, likings []model.User
db.ORM.Joins("JOIN user_follows on user_follows.user_id=?", user.ID).Where("users.user_id = user_follows.following").Group("users.user_id").Find(&likings)
db.ORM.Joins("JOIN user_follows on user_follows.following=?", user.ID).Where("users.user_id = user_follows.user_id").Group("users.user_id").Find(&liked)
user.Likings = likings
user.Liked = liked
return user, http.StatusOK, nil
@ -277,7 +279,7 @@ func RetrieveUsersForAdmin() []model.User {
db.ORM.Find(&users)
for _, user := range users {
db.ORM.Model(&user)
db.ORM.Model(&user).Related("Torrents").Related("Likings").Related("Liked").Find(&model.Torrents{})
db.ORM.Model(&user).Related("Torrents").Related("Likings").Related("Liked").Find(&model.Torrent{})
userArr = append(userArr, user)
}
return userArr
@ -294,15 +296,15 @@ func CreateUserAuthentication(w http.ResponseWriter, r *http.Request) (int, erro
}
func SetFollow(user *model.User, follower *model.User) {
if (follower.Id > 0 && user.Id > 0) {
var userFollows = model.UserFollows{UserID: user.Id, FollowerID: follower.Id}
if follower.ID > 0 && user.ID > 0 {
var userFollows = model.UserFollows{UserID: user.ID, FollowerID: follower.ID}
db.ORM.Create(&userFollows)
}
}
func RemoveFollow(user *model.User, follower *model.User) {
if (follower.Id > 0 && user.Id > 0) {
var userFollows = model.UserFollows{UserID: user.Id, FollowerID: follower.Id}
if follower.ID > 0 && user.ID > 0 {
var userFollows = model.UserFollows{UserID: user.ID, FollowerID: follower.ID}
db.ORM.Delete(&userFollows)
}
}
}

Voir le fichier

@ -1,9 +1,9 @@
package userService
import (
"errors"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
"errors"
"net/http"
"github.com/ewhal/nyaa/util/log"
@ -23,14 +23,14 @@ func FindUserByUserName(userName string) (model.User, int, error) {
func FindOrCreateUser(username string) (model.User, int, error) {
var user model.User
if db.ORM.Where("username=?", username).First(&user).RecordNotFound() {
var user model.User
user.Username = username
log.Debugf("user %+v\n", user)
if db.ORM.Create(&user).Error != nil {
return user, http.StatusBadRequest, errors.New("User is not created.")
var newUser model.User
newUser.Username = username
log.Debugf("user %+v\n", newUser)
if db.ORM.Create(&newUser).Error != nil {
return newUser, http.StatusBadRequest, errors.New("user not created")
}
log.Debugf("retrived User %v\n", user)
return user, http.StatusOK, nil
log.Debugf("retrieved User %v\n", newUser)
return newUser, http.StatusOK, nil
}
return user, http.StatusBadRequest, nil
}

Voir le fichier

@ -10,6 +10,7 @@ import (
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
// "github.com/ewhal/nyaa/util/crypto"
"github.com/ewhal/nyaa/util/email"
"github.com/ewhal/nyaa/util/timeHelper"
"github.com/gorilla/securecookie"
@ -20,9 +21,12 @@ var verificationHandler = securecookie.New(config.EmailTokenHashKey, nil)
// SendEmailVerfication sends an email verification token via email.
func SendEmailVerification(to string, token string, locale string) error {
T, _ := i18n.Tfunc(locale)
content := T("link")+" : https://"+config.WebAddress+"/verify/email/"+token
content_html := T("verify_email_content")+"<br/>"+"<a href=\"https://"+config.WebAddress+"/verify/email/"+token+"\" target=\"_blank\">"+config.WebAddress+"/verify/email/"+token+"</a>"
T, err := i18n.Tfunc(locale)
if err != nil {
return err
}
content := T("link") + " : https://" + config.WebAddress + "/verify/email/" + token
content_html := T("verify_email_content") + "<br/>" + "<a href=\"https://" + config.WebAddress + "/verify/email/" + token + "\" target=\"_blank\">" + config.WebAddress + "/verify/email/" + token + "</a>"
return email.SendEmailFromAdmin(to, T("verify_email_title"), content, content_html)
return nil
}
@ -31,8 +35,8 @@ func SendEmailVerification(to string, token string, locale string) error {
func SendVerificationToUser(user model.User) (int, error) {
validUntil := timeHelper.TwentyFourHoursLater() // TODO: longer duration?
value := map[string]string{
"t": strconv.FormatInt(validUntil.Unix(), 10),
"u": strconv.FormatUint(uint64(user.Id), 10),
"t": strconv.FormatInt(validUntil.Unix(), 10),
"u": strconv.FormatUint(uint64(user.ID), 10),
"e": user.Email,
}
encoded, err := verificationHandler.Encode("", value)
@ -51,10 +55,10 @@ func SendVerification(r *http.Request) (int, error) {
var user model.User
currentUser, err := CurrentUser(r)
if err != nil {
return http.StatusUnauthorized, errors.New("Unauthorized.")
return http.StatusUnauthorized, errors.New("unauthorized")
}
if db.ORM.First(&user, currentUser.Id).RecordNotFound() {
return http.StatusNotFound, errors.New("User is not found.")
if db.ORM.First(&user, currentUser.ID).RecordNotFound() {
return http.StatusNotFound, errors.New("user not found")
}
status, err := SendVerificationToUser(user)
return status, err

Voir le fichier

@ -2,11 +2,11 @@
{{with .User}}
<ul class="nav navbar-nav navbar-right badgemenu">
<li class="dropdown">
{{if gt .Id 0}}
<a href="{{ genRoute "user_profile" "id" (print .Id) "username" .Username }}" class="dropdown-toggle profile-image" data-toggle="dropdown">
<img src="https://www.gravatar.com/avatar/{{ .Md5 }}?s=50" class="img-circle special-img"> {{ .Username }} <b class="caret"></b></a>
{{if gt .ID 0}}
<a href="{{ genRoute "user_profile" "id" (print .ID) "username" .Username }}" class="dropdown-toggle profile-image" data-toggle="dropdown">
<img src="https://www.gravatar.com/avatar/{{ .MD5 }}?s=50" class="img-circle special-img"> {{ .Username }} <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="{{ genRoute "user_profile" "id" (print .Id) "username" .Username }}"><i class="fa fa-cog"></i> Profile</a></li>
<li><a href="{{ genRoute "user_profile" "id" (print .ID) "username" .Username }}"><i class="fa fa-cog"></i> Profile</a></li>
<li class="divider"></li>
<li><a href="{{ genRoute "user_logout" }}"><i class="fa fa-sign-out"></i> {{ T "sign_out"}}</a></li>
</ul>

Voir le fichier

@ -97,9 +97,9 @@
</div>
</div>
</form>
{{ if CurrentOrAdmin $.User .Id }}
{{ if CurrentOrAdmin $.User .ID }}
<hr>
<a href="?delete" onclick="if (!confirm('{{ T "delete_account_confirm" }}')) return false;" class="btn btn-danger btn-lg"><i class="glyphicon glyphicon-trash"></i> {{ T "delete_account"}}</a>
{{end}}
{{end}}
{{end}}
{{end}}

Voir le fichier

@ -18,12 +18,12 @@
{{if eq .Status 4}}aplus{{end}}">
<!-- forced width because the <td> gets bigger randomly otherwise -->
<td style="width:80px">
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .Sub_Category) }}">
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .Sub_Category) }}">
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .SubCategory) }}">
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}">
</a>
</td>
<td class="name">
<a href="{{genRoute "view_torrent" "id" .Id }}">
<a href="{{genRoute "view_torrent" "id" .ID }}">
{{.Name}}
</a>
</td>
@ -45,7 +45,7 @@
</table>
<nav class="torrentNav" aria-label="Page navigation">
<ul class="pagination">
<li><a href="{{ genRoute "search" }}?userId={{ .Id }}" aria-label="Next"><span class="glyphicon glyphicon-add"></span> {{ T "see_more_torrents_from" .Username }}</a></li>
<li><a href="{{ genRoute "search" }}?userID={{ .ID }}" aria-label="Next"><span class="glyphicon glyphicon-add"></span> {{ T "see_more_torrents_from" .Username }}</a></li>
</ul>
</nav>
</div>

Voir le fichier

@ -25,12 +25,12 @@
{{if eq .Status 4}}aplus{{end}}">
<!-- forced width because the <td> gets bigger randomly otherwise -->
<td class="hidden-xs" style="width:80px">
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .Sub_Category) }}">
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .Sub_Category) }}">
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .SubCategory) }}">
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}">
</a>
</td>
<td class="name">
<a href="{{genRoute "view_torrent" "id" .Id }}">
<a href="{{genRoute "view_torrent" "id" .ID }}">
{{.Name}}
</a>
</td>

Voir le fichier

@ -10,7 +10,7 @@
<div class="profile-sidebar">
<!-- SIDEBAR USERPIC -->
<div class="profile-userpic">
<img src="{{ getAvatar .Md5 130 }}" class="img-responsive" alt="{{.Username}}">
<img src="{{ getAvatar .MD5 130 }}" class="img-responsive" alt="{{.Username}}">
</div>
<!-- END SIDEBAR USERPIC -->
<!-- SIDEBAR USER TITLE -->
@ -25,12 +25,12 @@
<!-- END SIDEBAR USER TITLE -->
<!-- SIDEBAR BUTTONS -->
<div class="profile-userbuttons">
{{if gt $.User.Id 0 }}
{{if not (CurrentUserIdentical $.User .Id) }}
{{if gt $.User.ID 0 }}
{{if not (CurrentUserIdentical $.User .ID) }}
{{if not (IsFollower . $.User)}}
<a href="{{ genRoute "user_follow" "id" ( print .Id ) "username" .Username }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
<a href="{{ genRoute "user_follow" "id" ( print .ID ) "username" .Username }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
{{else}}
<a href="{{ genRoute "user_follow" "id" ( print .Id ) "username" .Username }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
<a href="{{ genRoute "user_follow" "id" ( print .ID ) "username" .Username }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
{{end}}
{{end}}
{{end}}
@ -45,8 +45,8 @@
<i class="glyphicon glyphicon-home"></i>
{{T "torrents"}} </a>
</li>
{{if gt $.User.Id 0 }}
{{if CurrentOrAdmin $.User .Id }}
{{if gt $.User.ID 0 }}
{{if CurrentOrAdmin $.User .ID }}
<li>
<a href="?edit">
<i class="glyphicon glyphicon-user"></i>
@ -66,4 +66,4 @@
</div>
</div>
</div>
{{end}}
{{end}}

Voir le fichier

@ -22,12 +22,12 @@
<!-- END SIDEBAR USER TITLE -->
<!-- SIDEBAR BUTTONS -->
<div class="profile-userbuttons">
{{if gt $.User.Id 0 }}
{{if not (CurrentUserIdentical $.User .Id) }}
{{if gt $.User.ID 0 }}
{{if not (CurrentUserIdentical $.User .ID) }}
{{if not (IsFollower . $.User)}}
<a href="{{ genRoute "user_follow" "id" .Id }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
<a href="{{ genRoute "user_follow" "id" .ID }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
{{else}}
<a href="{{ genRoute "user_follow" "id" .Id }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
<a href="{{ genRoute "user_follow" "id" .ID }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
{{end}}
{{end}}
{{end}}
@ -42,8 +42,8 @@
<i class="glyphicon glyphicon-home"></i>
{{T "torrents"}} </a>
</li>
{{if gt $.User.Id 0 }}
{{if CurrentOrAdmin $.User .Id }}
{{if gt $.User.ID 0 }}
{{if CurrentOrAdmin $.User .ID }}
<li class="active">
<a href="?edit">
<i class="glyphicon glyphicon-user"></i>
@ -63,4 +63,4 @@
</div>
</div>
</div>
{{end}}
{{end}}

Voir le fichier

@ -1,35 +1,38 @@
{{define "title"}}{{.Torrent.Name}}{{end}} {{define "contclass"}}cont-view{{end}} {{define "content"}}
<div class="blockBody">
{{with .Torrent}}
<hr>
<table class="table table-borderless">
<tr {{if eq .Status 2}}class="remake" {{end}} {{if eq .Status 3}}class="trusted" {{end}} {{if eq .Status 4}}class="aplus"
{{end}}>
<td>{{T "name"}}</td>
<td>
{{.Name}}
<img style="float:right" src="{{$.URL.Parse (printf " /img/torrents/%s.png " .Sub_Category) }}">
</td>
</tr>
<tr>
<td>{{T "hash"}}</td>
<td class="torrent-hash">{{.Hash}}</td>
</tr>
<tr>
<td>{{T "date"}}</td>
<td class="date-full">{{.Date}}</td>
</tr>
<tr>
<td>{{T "size"}}</td>
<td>{{.Filesize}}</td>
</tr>
<tr>
<td>Uploader</td>
<td><a href="{{$.URL.Parse (printf " /user/%d/- " .UploaderId) }}">{{.UploaderName}}</a></td>
{{if ne .WebsiteLink ""}}
<tr>
<td>{{T "Link"}}</td>
<td><a href="{{.WebsiteLink}}">{{.WebsiteLink}}</td>
{{define "title"}}{{.Torrent.Name}}{{end}}
{{define "contclass"}}cont-view{{end}}
{{define "content"}}
<div class="blockBody">
{{with .Torrent}}
<hr>
<table class="table table-borderless">
<tr {{if eq .Status 2}}class="remake"{{end}}
{{if eq .Status 3}}class="trusted"{{end}}
{{if eq .Status 4}}class="aplus"{{end}}>
<td>{{T "name"}}</td>
<td>
{{.Name}}
<img style="float:right" src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}">
</td>
</tr>
<tr>
<td>{{T "hash"}}</td>
<td class="torrent-hash">{{.Hash}}</td>
</tr>
<tr>
<td>{{T "date"}}</td>
<td class="date-full">{{.Date}}</td>
</tr>
<tr>
<td>{{T "size"}}</td>
<td>{{.Filesize}}</td>
</tr>
<tr>
<td>Uploader</td>
<td><a href="{{$.URL.Parse (printf "/user/%d/-" .UploaderID) }}">{{.UploaderName}}</a></td>
{{if ne .WebsiteLink ""}}
<tr>
<td>{{T "Link"}}</td>
<td><a href="{{.WebsiteLink}}">{{.WebsiteLink}}</td>
</tr>
{{end}}
<tr>
@ -72,7 +75,7 @@
<form method="post">
<div class="form-group">
{{/* There should be a better way to use translation on this... */}}
<label for="comment">{{ if gt .User.Id 0}} {{T "submit_a_comment_as_username" .User.Username}} {{else}} {{T "submit_a_comment_as_anonymous"}} {{end}}</label>
<label for="comment">{{ if gt .User.ID 0}} {{T "submit_a_comment_as_username" .User.Username}} {{else}} {{T "submit_a_comment_as_anonymous"}} {{end}}</label>
<textarea name="comment" class="form-control" rows="5"></textarea>
</div>
{{with .Captcha}} {{block "captcha" .}}{{end}} {{end}}
@ -87,7 +90,7 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Report Torrent #{{.Id}}</h4>
<h4 class="modal-title">Report Torrent #{{.ID}}</h4>
</div>
{{end}}
<div class="modal-body">
@ -105,4 +108,4 @@
</div>
</div>
{{end}}
{{end}}

Voir le fichier

@ -7,12 +7,16 @@ import (
"strings"
)
func GenerateMD5Hash(email string) string {
email = strings.ToLower(strings.TrimSpace(email))
func GenerateMD5Hash(str string) (string, error) {
str = strings.ToLower(strings.TrimSpace(str))
hash := md5.New()
hash.Write([]byte(email))
return fmt.Sprintf("%x", hash.Sum(nil))
_, err := hash.Write([]byte(str))
if err != nil {
return "", err
}
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
func GenerateRandomToken16() (string, error) {
return GenerateRandomToken(16)
}

Voir le fichier

@ -15,8 +15,8 @@ var (
)
func InitGomail() *gomail.Dialer {
mailer := gomail.NewDialer(config.EmailHost, config.EmailPort, config.EmailUsername, config.EmailPassword)
return mailer
newMailer := gomail.NewDialer(config.EmailHost, config.EmailPort, config.EmailUsername, config.EmailPassword)
return newMailer
}
func SendEmailFromAdmin(to string, subject string, body string, bodyHTML string) error {
@ -33,7 +33,7 @@ func SendEmailFromAdmin(to string, subject string, body string, bodyHTML string)
if config.SendEmail {
log.Debug("SendEmail performed.")
err := mailer.DialAndSend(msg);
err := mailer.DialAndSend(msg)
return err
}
return nil
@ -52,7 +52,6 @@ func SendTestEmail() error {
panic(err)
}
msg.Attach(path)
// SendEmail(msg)
err = mailer.DialAndSend(msg)
return err

Voir le fichier

@ -1,35 +1,34 @@
package util
import (
"fmt"
"fmt"
)
func FormatFilesize(bytes int64) string {
var unit string
var value float64
if bytes >= 1024*1024*1024*1024 {
unit = "TiB"
value = float64(bytes) / (1024*1024*1024*1024)
} else if bytes >= 1024*1024*1024 {
unit = "GiB"
value = float64(bytes) / (1024*1024*1024)
} else if bytes >= 1024*1024 {
unit = "MiB"
value = float64(bytes) / (1024*1024)
} else if bytes >= 1024 {
unit = "KiB"
value = float64(bytes) / (1024)
} else {
unit = "B"
value = float64(bytes)
}
return fmt.Sprintf("%.1f %s", value, unit)
var unit string
var value float64
if bytes >= 1024*1024*1024*1024 {
unit = "TiB"
value = float64(bytes) / (1024 * 1024 * 1024 * 1024)
} else if bytes >= 1024*1024*1024 {
unit = "GiB"
value = float64(bytes) / (1024 * 1024 * 1024)
} else if bytes >= 1024*1024 {
unit = "MiB"
value = float64(bytes) / (1024 * 1024)
} else if bytes >= 1024 {
unit = "KiB"
value = float64(bytes) / (1024)
} else {
unit = "B"
value = float64(bytes)
}
return fmt.Sprintf("%.1f %s", value, unit)
}
func FormatFilesize2(bytes int64) string {
if bytes == 0 { // this is what gorm returns for NULL
return "Unknown"
} else {
return FormatFilesize(bytes)
}
return FormatFilesize(bytes)
}

Voir le fichier

@ -1,8 +1,8 @@
package languages
import (
"github.com/nicksnyder/go-i18n/i18n"
"fmt"
"github.com/nicksnyder/go-i18n/i18n"
"html/template"
"net/http"
)

Voir le fichier

@ -4,7 +4,7 @@ import (
"fmt"
"github.com/Sirupsen/logrus"
"runtime"
)
)
// CheckError check error and return true if error is nil and return false if error is not nil.
func CheckError(err error) bool {
@ -16,14 +16,12 @@ func CheckErrorWithMessage(err error, msg string, args ...interface{}) bool {
if err != nil {
var stack [4096]byte
runtime.Stack(stack[:], false)
// logrus.Errorf(msg, args)
if len(args) == 0 {
logrus.Error(msg + fmt.Sprintf("%q\n%s\n", err, stack[:]))
} else {
logrus.Error(fmt.Sprintf(msg, args...) + fmt.Sprintf("%q\n%s\n", err, stack[:]))
}
// logrus.Printf(msg+"\n%q\n%s\n",args, err, stack[:])
return false
}
return true
}
}

Voir le fichier

@ -35,13 +35,10 @@ func InitLogToFile() {
out := LumberJackLogger(config.ErrorLogFilePath+config.ErrorLogFileExtension, config.ErrorLogMaxSize, config.ErrorLogMaxBackups, config.ErrorLogMaxAge)
logrus.SetOutput(out)
logrus.SetLevel(logrus.WarnLevel)
}
// Init logrus
func Init(environment string) {
switch environment {
@ -120,8 +117,14 @@ func DebugResponse(response *http.Response) string {
bodyBuffer := make([]byte, 5000)
var str string
count, err := response.Body.Read(bodyBuffer)
if err != nil {
Debug(err.Error())
return ""
}
for ; count > 0; count, err = response.Body.Read(bodyBuffer) {
if err != nil {
Debug(err.Error())
continue
}
str += string(bodyBuffer[:count])
}

Voir le fichier

@ -7,7 +7,7 @@ import (
"html/template"
)
// TODO restrict certain types of markdown
// TODO: restrict certain types of markdown
func MarkdownToHTML(markdown string) template.HTML {
unsafe := blackfriday.MarkdownCommon([]byte(markdown))
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)

Voir le fichier

@ -107,7 +107,7 @@ func (tf *TorrentFile) GetAllAnnounceURLS() (l []string) {
}
func (tf *TorrentFile) TorrentName() string {
return string(tf.Info.Path)
return tf.Info.Path
}
// return true if this torrent is private otherwise return false
@ -116,10 +116,13 @@ func (tf *TorrentFile) IsPrivate() bool {
}
// calculate infohash
func (tf *TorrentFile) Infohash() (ih [20]byte) {
func (tf *TorrentFile) Infohash() (ih [20]byte, err error) {
s := sha1.New()
enc := bencode.NewEncoder(s)
enc.Encode(&tf.Info)
err = enc.Encode(&tf.Info)
if err != nil {
return
}
d := s.Sum(nil)
copy(ih[:], d[:])
return

Voir le fichier

@ -1,13 +1,16 @@
package modelHelper
import (
"reflect"
"net/http"
"github.com/ewhal/nyaa/util/log"
"strconv"
"fmt"
"github.com/ewhal/nyaa/util/log"
"net/http"
"reflect"
"strconv"
)
// TODO: Rewrite module
// Functions are highly complex and require a lot of additional error handling
func IsZeroOfUnderlyingType(x interface{}) bool {
return x == reflect.Zero(reflect.TypeOf(x)).Interface()
}
@ -39,101 +42,99 @@ func BindValueForm(form interface{}, r *http.Request) {
typeField := formElem.Type().Field(i)
tag := typeField.Tag
switch typeField.Type.Name() {
case "string" :
formElem.Field(i).SetString(r.PostFormValue(tag.Get("form")))
case "int" :
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
formElem.Field(i).SetInt(int64(nbr))
case "float" :
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
formElem.Field(i).SetFloat(float64(nbr))
case "bool" :
nbr, _ := strconv.ParseBool(r.PostFormValue(tag.Get("form")))
formElem.Field(i).SetBool(nbr)
case "string":
formElem.Field(i).SetString(r.PostFormValue(tag.Get("form")))
case "int":
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
formElem.Field(i).SetInt(int64(nbr))
case "float":
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
formElem.Field(i).SetFloat(float64(nbr))
case "bool":
nbr, _ := strconv.ParseBool(r.PostFormValue(tag.Get("form")))
formElem.Field(i).SetBool(nbr)
}
}
}
func ValidateForm(form interface{}, errorForm map[string][]string) (map[string][]string) {
func ValidateForm(form interface{}, errorForm map[string][]string) map[string][]string {
formElem := reflect.ValueOf(form).Elem()
for i := 0; i < formElem.NumField(); i++ {
typeField := formElem.Type().Field(i)
tag := typeField.Tag
inputName := typeField.Name
if (tag.Get("hum_name") != "") { // For more human input name than gibberish
if tag.Get("hum_name") != "" { // For more human input name than gibberish
inputName = tag.Get("hum_name")
}
if tag.Get("len_min") != "" && (tag.Get("needed") != ""||formElem.Field(i).Len()>0) { // Check minimum length
if tag.Get("len_min") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check minimum length
lenMin, _ := strconv.Atoi(tag.Get("len_min"))
if formElem.Field(i).Len() < lenMin {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Minimal length of %s required for the input: %s", strconv.Itoa(lenMin), inputName))
}
}
if tag.Get("len_max") != "" && (tag.Get("needed") != ""||formElem.Field(i).Len()>0) { // Check maximum length
if tag.Get("len_max") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check maximum length
lenMax, _ := strconv.Atoi(tag.Get("len_max"))
if formElem.Field(i).Len() > lenMax {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Maximal length of %s required for the input: %s", strconv.Itoa(lenMax), inputName))
}
}
if tag.Get("equalInput") != "" && (tag.Get("needed") != ""||formElem.Field(i).Len()>0) {
if tag.Get("equalInput") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) {
otherInput := formElem.FieldByName(tag.Get("equalInput"))
if formElem.Field(i).Interface() != otherInput.Interface() {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Must be same %s", inputName))
}
}
switch typeField.Type.Name() {
case "string" :
if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") {
case "string":
if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
}
if tag.Get("needed") != "" && formElem.Field(i).String() == "" {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
}
if tag.Get("default") != "" {
formElem.Field(i).SetString(tag.Get("default"))
}
case "int":
if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.Atoi(tag.Get("equal"))
if formElem.Field(i).Int() > int64(equal) {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
}
if tag.Get("needed") != "" && formElem.Field(i).String() == "" {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
}
if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
}
if tag.Get("default") != "" {
defaultValue, _ := strconv.Atoi(tag.Get("default"))
formElem.Field(i).SetInt(int64(defaultValue))
}
case "float":
if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.Atoi(tag.Get("equal"))
if formElem.Field(i).Float() != float64(equal) {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
}
if tag.Get("default") != "" {
formElem.Field(i).SetString(tag.Get("default"))
}
case "int" :
if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.Atoi(tag.Get("equal"))
if formElem.Field(i).Int() > int64(equal) {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
}
}
if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
}
if tag.Get("default") != "" {
defaultValue, _ := strconv.Atoi(tag.Get("default"))
formElem.Field(i).SetInt(int64(defaultValue))
}
case "float" :
if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.Atoi(tag.Get("equal"))
if formElem.Field(i).Float() != float64(equal) {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
}
}
if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
}
if tag.Get("default") != "" {
defaultValue, _ := strconv.Atoi(tag.Get("default"))
formElem.Field(i).SetFloat(float64(defaultValue))
}
case "bool" :
if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.ParseBool(tag.Get("equal"))
if formElem.Field(i).Bool() != equal {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
}
}
if tag.Get("default") != "" {
defaultValue, _ := strconv.ParseBool(tag.Get("default"))
formElem.Field(i).SetBool(defaultValue)
}
if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
}
if tag.Get("default") != "" {
defaultValue, _ := strconv.Atoi(tag.Get("default"))
formElem.Field(i).SetFloat(float64(defaultValue))
}
case "bool":
if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.ParseBool(tag.Get("equal"))
if formElem.Field(i).Bool() != equal {
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
}
}
if tag.Get("default") != "" {
defaultValue, _ := strconv.ParseBool(tag.Get("default"))
formElem.Field(i).SetBool(defaultValue)
}
}
}
return errorForm
}
}

Voir le fichier

@ -6,7 +6,7 @@ import (
)
func Safe(s string) template.URL {
return template.URL(s)
return template.URL(html.EscapeString(s))
}
func SafeText(s string) template.HTML {

Voir le fichier

@ -1,16 +1,15 @@
package search
import (
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/torrent"
"github.com/ewhal/nyaa/util/log"
"net/http"
"strconv"
"strings"
"unicode"
"unicode/utf8"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/torrent"
"github.com/ewhal/nyaa/util/log"
)
type Status uint8
@ -56,20 +55,19 @@ type SearchParam struct {
Query string
}
func SearchByQuery(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrents, count int, err error) {
func SearchByQuery(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrent, count int, err error) {
search, tor, count, err = searchByQuery(r, pagenum, true)
return
}
func SearchByQueryNoCount(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrents, err error) {
func SearchByQueryNoCount(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrent, err error) {
search, tor, _, err = searchByQuery(r, pagenum, false)
return
}
func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchParam, tor []model.Torrents, count int, err error) {
func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchParam, tor []model.Torrent, count int, err error) {
max, err := strconv.ParseUint(r.URL.Query().Get("max"), 10, 32)
if err != nil {
err = nil
max = 50 // default Value maxPerPage
} else if max > 300 {
max = 300
@ -105,36 +103,36 @@ func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchPa
}
}
order_by := ""
orderBy := ""
switch s := r.URL.Query().Get("sort"); s {
case "1":
search.Sort = Name
order_by += "torrent_name"
orderBy += "torrent_name"
case "2":
search.Sort = Date
order_by += "date"
orderBy += "date"
case "3":
search.Sort = Downloads
order_by += "downloads"
orderBy += "downloads"
case "4":
search.Sort = Size
order_by += "filesize"
orderBy += "filesize"
default:
order_by += "torrent_id"
orderBy += "torrent_id"
}
order_by += " "
orderBy += " "
switch s := r.URL.Query().Get("order"); s {
case "true":
search.Order = true
order_by += "asc"
orderBy += "asc"
default:
order_by += "desc"
orderBy += "desc"
}
userId := r.URL.Query().Get("userId")
userID := r.URL.Query().Get("userID")
parameters := torrentService.WhereParams{
Params: make([]interface{}, 0, 64),
@ -148,9 +146,9 @@ func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchPa
conditions = append(conditions, "sub_category = ?")
parameters.Params = append(parameters.Params, string(catString[2]))
}
if userId != "" {
if userID != "" {
conditions = append(conditions, "uploader = ?")
parameters.Params = append(parameters.Params, userId)
parameters.Params = append(parameters.Params, userID)
}
if search.Status != 0 {
if search.Status == 3 {
@ -191,9 +189,9 @@ func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchPa
parameters.Conditions = strings.Join(conditions[:], " AND ")
log.Infof("SQL query is :: %s\n", parameters.Conditions)
if countAll {
tor, count, err = torrentService.GetTorrentsOrderBy(&parameters, order_by, int(search.Max), int(search.Max)*(pagenum-1))
tor, count, err = torrentService.GetTorrentsOrderBy(&parameters, orderBy, int(search.Max), int(search.Max)*(pagenum-1))
} else {
tor, err = torrentService.GetTorrentsOrderByNoCount(&parameters, order_by, int(search.Max), int(search.Max)*(pagenum-1))
tor, err = torrentService.GetTorrentsOrderByNoCount(&parameters, orderBy, int(search.Max), int(search.Max)*(pagenum-1))
}
return
}

Voir le fichier

@ -4,4 +4,5 @@ package signals
func Handle() {
// windows has no sighup LOOOOL, this does nothing
// TODO: Something about SIGHUP for Windows
}

Voir le fichier

@ -30,8 +30,6 @@ func InTimeSpanNow(start, end time.Time) bool {
func FewDurationLater(duration time.Duration) time.Time {
// When Save time should considering UTC
// baseTime := time.Now()
// log.Debugf("basetime : %s", baseTime)
fewDurationLater := time.Now().Add(duration)
log.Debugf("time : %s", fewDurationLater)
return fewDurationLater
@ -42,11 +40,7 @@ func FewDurationLaterMillisecond(duration time.Duration) int64 {
}
func IsExpired(expirationTime time.Time) bool {
// baseTime := time.Now()
// log.Debugf("basetime : %s", baseTime)
log.Debugf("expirationTime : %s", expirationTime)
// elapsed := time.Since(expirationTime)
// log.Debugf("elapsed : %s", elapsed)
after := time.Now().After(expirationTime)
log.Debugf("after : %t", after)
return after

Voir le fichier

@ -8,15 +8,19 @@ import (
"io/ioutil"
)
func UnZlib(description []byte) string {
func UnZlib(description []byte) (string, error) {
if len(description) > 0 {
b := bytes.NewReader(description)
z, err := zlib.NewReader(b)
log.CheckError(err)
if !log.CheckError(err) {
return "", err
}
defer z.Close()
p, err := ioutil.ReadAll(z)
log.CheckError(err)
return string(p)
if !log.CheckError(err) {
return "", err
}
return string(p), nil
}
return ""
}
return "", nil
}