diff --git a/config/trackers.go b/config/trackers.go
index 4f38177f..8fdbb9b7 100644
--- a/config/trackers.go
+++ b/config/trackers.go
@@ -10,5 +10,6 @@ var Trackers = []string{
"udp://explodie.org:6969",
"udp://tracker.opentrackr.org:1337",
"udp://tracker.internetwarriors.net:1337/announce",
+ "udp://eddie4.nl:6969/announce",
"http://mgtracker.org:6969/announce",
"http://tracker.baka-sub.cf/announce"}
diff --git a/model/user.go b/model/user.go
index bf1fd654..1e1e3ca7 100644
--- a/model/user.go
+++ b/model/user.go
@@ -12,9 +12,8 @@ type User struct {
Status int `gorm:"column:status"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
- // Currently unused (auth is stateless now)
- /*Token string `gorm:"column:api_token"`
- TokenExpiration time.Time `gorm:"column:api_token_expiry"`*/
+ Token string `gorm:"column:api_token"`
+ TokenExpiration time.Time `gorm:"column:api_token_expiry"`
Language string `gorm:"column:language"`
// TODO: move this to PublicUser
@@ -43,7 +42,7 @@ func (u User) Size() (s int) {
4*3 + //time.Time
3*2 + // arrays
// string arrays
- len(u.Username) + len(u.Password) + len(u.Email) + len(u.MD5) + len(u.Language)
+ len(u.Username) + len(u.Password) + len(u.Email) + len(u.Token) + len(u.MD5) + len(u.Language)
s *= 8
// Ignoring foreign key users. Fuck them.
diff --git a/public/css/style.css b/public/css/style.css
index 753cb47b..9a96e38d 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -186,6 +186,10 @@ div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-typ
.navbar {
border-radius: 0px;
}
+/* the logo needs some space */
+.navbar-logo {
+ margin-right: 10px;
+}
:target {
background-color: #e5eecc;
diff --git a/public/img/logo.png b/public/img/logo.png
new file mode 100644
index 00000000..0967da8c
Binary files /dev/null and b/public/img/logo.png differ
diff --git a/service/user/cookieHelper.go b/service/user/cookieHelper.go
index 940d5b3d..b28e5a98 100644
--- a/service/user/cookieHelper.go
+++ b/service/user/cookieHelper.go
@@ -5,98 +5,96 @@ import (
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
formStruct "github.com/ewhal/nyaa/service/user/form"
+ "github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/util/modelHelper"
- "github.com/ewhal/nyaa/util/timeHelper"
"github.com/gorilla/securecookie"
"golang.org/x/crypto/bcrypt"
"net/http"
- "strconv"
- "time"
)
-const CookieName = "session"
-
-// If you want to keep login cookies between restarts you need to make these permanent
var cookieHandler = securecookie.New(
securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32))
-// Encoding & Decoding of the cookie value
-func DecodeCookie(cookie_value string) (uint, error) {
- value := make(map[string]string)
- err := cookieHandler.Decode(CookieName, cookie_value, &value)
+func Token(r *http.Request) (string, error) {
+ var token string
+ cookie, err := r.Cookie("session")
if err != nil {
- return 0, err
+ return token, err
}
- time_int, _ := strconv.ParseInt(value["t"], 10, 0)
- if timeHelper.IsExpired(time.Unix(time_int, 0)) {
- return 0, errors.New("Cookie is expired")
+ cookieValue := make(map[string]string)
+ err = cookieHandler.Decode("session", cookie.Value, &cookieValue)
+ if err != nil {
+ return token, err
}
- ret, err := strconv.ParseUint(value["u"], 10, 0)
- return uint(ret), err
+ token = cookieValue["token"]
+ if len(token) == 0 {
+ return token, errors.New("token is empty")
+ }
+ return token, nil
}
-func EncodeCookie(user_id uint) (string, error) {
- validUntil := timeHelper.FewDaysLater(7) // 1 week
+// SetCookie sets a cookie.
+func SetCookie(w http.ResponseWriter, token string) (int, error) {
value := map[string]string{
- "u": strconv.FormatUint(uint64(user_id), 10),
- "t": strconv.FormatInt(validUntil.Unix(), 10),
+ "token": token,
}
- return cookieHandler.Encode(CookieName, value)
+ encoded, err := cookieHandler.Encode("session", value)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
+ cookie := &http.Cookie{
+ Name: "session",
+ Value: encoded,
+ Path: "/",
+ }
+ http.SetCookie(w, cookie)
+ return http.StatusOK, nil
}
+// ClearCookie clears a cookie.
func ClearCookie(w http.ResponseWriter) (int, error) {
cookie := &http.Cookie{
- Name: CookieName,
+ Name: "session",
Value: "",
Path: "/",
- HttpOnly: true,
MaxAge: -1,
}
http.SetCookie(w, cookie)
return http.StatusOK, nil
}
-// SetCookieHandler sets the authentication cookie
+// SetCookieHandler sets a cookie with email and password.
func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, error) {
- if email == "" || pass == "" {
- return http.StatusNotFound, errors.New("No username/password entered")
- }
-
- var user model.User
- // search by email or username
- isValidEmail, _ := formStruct.EmailValidation(email, formStruct.NewErrors())
- if isValidEmail {
- if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() {
- return http.StatusNotFound, errors.New("User not found")
+ if email != "" && pass != "" {
+ var user model.User
+ isValidEmail, _ := formStruct.EmailValidation(email, formStruct.NewErrors())
+ if isValidEmail {
+ log.Debug("User entered valid email.")
+ if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() {
+ 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 not found")
+ }
}
- } else {
- if db.ORM.Where("username = ?", email).First(&user).RecordNotFound() {
- 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")
}
+ if user.Status == -1 {
+ return http.StatusUnauthorized, errors.New("Account banned")
+ }
+ status, err := SetCookie(w, user.Token)
+ if err != nil {
+ return status, err
+ }
+ w.Header().Set("X-Auth-Token", user.Token)
+ return http.StatusOK, nil
}
- err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(pass))
- if err != nil {
- return http.StatusUnauthorized, errors.New("Password incorrect")
- }
- if user.Status == -1 {
- return http.StatusUnauthorized, errors.New("Account banned")
- }
-
- encoded, err := EncodeCookie(user.ID)
- if err != nil {
- return http.StatusInternalServerError, err
- }
- cookie := &http.Cookie{
- Name: CookieName,
- Value: encoded,
- Path: "/",
- HttpOnly: true,
- }
- http.SetCookie(w, cookie)
- // also set response header for convenience
- w.Header().Set("X-Auth-Token", encoded)
- return http.StatusOK, nil
+ return http.StatusNotFound, errors.New("user not found")
}
// RegisterHanderFromForm sets cookie from a RegistrationForm.
@@ -113,31 +111,24 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) (int, error) {
return RegisterHanderFromForm(w, registrationForm)
}
-// CurrentUser determines the current user from the request
+// CurrentUser get a current user.
func CurrentUser(r *http.Request) (model.User, error) {
var user model.User
- var encoded string
-
- encoded = r.Header.Get("X-Auth-Token")
- if len(encoded) == 0 {
- // check cookie instead
- cookie, err := r.Cookie(CookieName)
+ var token string
+ var err error
+ token = r.Header.Get("X-Auth-Token")
+ if len(token) > 0 {
+ log.Debug("header token exists")
+ } else {
+ token, err = Token(r)
+ log.Debug("header token does not exist")
if err != nil {
return user, err
}
- encoded = cookie.Value
}
- user_id, err := DecodeCookie(encoded)
- if err != nil {
- return user, err
+ if db.ORM.Where("api_token = ?", token).First(&user).RecordNotFound() {
+ return user, errors.New("user not found")
}
- if db.ORM.Where("user_id = ?", user_id).First(&user).RecordNotFound() {
- return user, errors.New("User not found")
- }
-
- if user.Status == -1 {
- // recheck as user might've been banned in the meantime
- return user, errors.New("Account banned")
- }
- return user, nil
+ err = db.ORM.Model(&user).Error
+ return user, err
}
diff --git a/service/user/user.go b/service/user/user.go
index 27100c40..88b2ada6 100644
--- a/service/user/user.go
+++ b/service/user/user.go
@@ -7,6 +7,7 @@ import (
"strconv"
"time"
+ "github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
formStruct "github.com/ewhal/nyaa/service/user/form"
@@ -14,6 +15,7 @@ import (
"github.com/ewhal/nyaa/util/crypto"
"github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/util/modelHelper"
+ "github.com/ewhal/nyaa/util/timeHelper"
"golang.org/x/crypto/bcrypt"
)
@@ -67,8 +69,15 @@ func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.Use
return user, err
}
}
+ token, err := crypto.GenerateRandomToken32()
+ if err != nil {
+ return user, errors.New("token not generated")
+ }
user.Email = "" // unset email because it will be verified later
+ 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 not created")
}
@@ -148,13 +157,17 @@ func UpdateUserCore(user *model.User) (int, error) {
}
}
- user.UpdatedAt = time.Now()
- err := db.ORM.Save(user).Error
+ token, err := crypto.GenerateRandomToken32()
if err != nil {
return http.StatusInternalServerError, err
}
+ user.Token = token
+ user.TokenExpiration = timeHelper.FewDaysLater(config.AuthTokenExpirationDay)
+ if db.ORM.Save(user).Error != nil {
+ return http.StatusInternalServerError, err
+ }
-
+ user.UpdatedAt = time.Now()
return http.StatusOK, nil
}
@@ -184,13 +197,18 @@ func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *m
form.Username = user.Username
}
if (form.Email != user.Email) {
- // send verification to new email and keep old
SendVerificationToUser(user, form.Email)
form.Email = user.Email
}
log.Debugf("form %+v\n", form)
modelHelper.AssignValue(&user, form)
status, err := UpdateUserCore(&user)
+ if err != nil {
+ return user, status, err
+ }
+ if userPermission.CurrentUserIdentical(currentUser, user.ID) {
+ status, err = SetCookie(w, user.Token)
+ }
return user, status, err
}
diff --git a/templates/FAQ.html b/templates/FAQ.html
index f511f968..b0a58191 100644
--- a/templates/FAQ.html
+++ b/templates/FAQ.html
@@ -45,6 +45,7 @@ udp://tracker.leechers-paradise.org:6969
udp://explodie.org:6969
udp://tracker.opentrackr.org:1337
udp://tracker.internetwarriors.net:1337/announce
+udp://eddie4.nl:6969/announce
http://mgtracker.org:6969/announce
http://tracker.baka-sub.cf/announce
diff --git a/templates/index.html b/templates/index.html
index 3b5708fe..2477c7ae 100755
--- a/templates/index.html
+++ b/templates/index.html
@@ -42,7 +42,7 @@
- Nyaa Pantsu
+