Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0

Revert "Stateless cookies (#372)"

This reverts commit 2f06fb8fa1.
Cette révision appartient à :
Eliot Whalan 2017-05-12 16:42:15 +10:00
Parent bd7933536f
révision bcaac0961f
6 fichiers modifiés avec 100 ajouts et 90 suppressions

Voir le fichier

@ -10,5 +10,6 @@ var Trackers = []string{
"udp://explodie.org:6969", "udp://explodie.org:6969",
"udp://tracker.opentrackr.org:1337", "udp://tracker.opentrackr.org:1337",
"udp://tracker.internetwarriors.net:1337/announce", "udp://tracker.internetwarriors.net:1337/announce",
"udp://eddie4.nl:6969/announce",
"http://mgtracker.org:6969/announce", "http://mgtracker.org:6969/announce",
"http://tracker.baka-sub.cf/announce"} "http://tracker.baka-sub.cf/announce"}

Voir le fichier

@ -12,9 +12,8 @@ type User struct {
Status int `gorm:"column:status"` Status int `gorm:"column:status"`
CreatedAt time.Time `gorm:"column:created_at"` CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"` UpdatedAt time.Time `gorm:"column:updated_at"`
// Currently unused (auth is stateless now) Token string `gorm:"column:api_token"`
/*Token string `gorm:"column:api_token"` TokenExpiration time.Time `gorm:"column:api_token_expiry"`
TokenExpiration time.Time `gorm:"column:api_token_expiry"`*/
Language string `gorm:"column:language"` Language string `gorm:"column:language"`
// TODO: move this to PublicUser // TODO: move this to PublicUser
@ -43,7 +42,7 @@ func (u User) Size() (s int) {
4*3 + //time.Time 4*3 + //time.Time
3*2 + // arrays 3*2 + // arrays
// string 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 s *= 8
// Ignoring foreign key users. Fuck them. // Ignoring foreign key users. Fuck them.

Voir le fichier

@ -5,98 +5,96 @@ import (
"github.com/ewhal/nyaa/db" "github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model" "github.com/ewhal/nyaa/model"
formStruct "github.com/ewhal/nyaa/service/user/form" 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/modelHelper"
"github.com/ewhal/nyaa/util/timeHelper"
"github.com/gorilla/securecookie" "github.com/gorilla/securecookie"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"net/http" "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( var cookieHandler = securecookie.New(
securecookie.GenerateRandomKey(64), securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32)) securecookie.GenerateRandomKey(32))
// Encoding & Decoding of the cookie value func Token(r *http.Request) (string, error) {
func DecodeCookie(cookie_value string) (uint, error) { var token string
value := make(map[string]string) cookie, err := r.Cookie("session")
err := cookieHandler.Decode(CookieName, cookie_value, &value)
if err != nil { if err != nil {
return 0, err return token, err
} }
time_int, _ := strconv.ParseInt(value["t"], 10, 0) cookieValue := make(map[string]string)
if timeHelper.IsExpired(time.Unix(time_int, 0)) { err = cookieHandler.Decode("session", cookie.Value, &cookieValue)
return 0, errors.New("Cookie is expired") if err != nil {
return token, err
} }
ret, err := strconv.ParseUint(value["u"], 10, 0) token = cookieValue["token"]
return uint(ret), err if len(token) == 0 {
return token, errors.New("token is empty")
}
return token, nil
} }
func EncodeCookie(user_id uint) (string, error) { // SetCookie sets a cookie.
validUntil := timeHelper.FewDaysLater(7) // 1 week func SetCookie(w http.ResponseWriter, token string) (int, error) {
value := map[string]string{ value := map[string]string{
"u": strconv.FormatUint(uint64(user_id), 10), "token": token,
"t": strconv.FormatInt(validUntil.Unix(), 10),
} }
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) { func ClearCookie(w http.ResponseWriter) (int, error) {
cookie := &http.Cookie{ cookie := &http.Cookie{
Name: CookieName, Name: "session",
Value: "", Value: "",
Path: "/", Path: "/",
HttpOnly: true,
MaxAge: -1, MaxAge: -1,
} }
http.SetCookie(w, cookie) http.SetCookie(w, cookie)
return http.StatusOK, nil 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) { func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, error) {
if email == "" || pass == "" { if email != "" && pass != "" {
return http.StatusNotFound, errors.New("No username/password entered") var user model.User
} isValidEmail, _ := formStruct.EmailValidation(email, formStruct.NewErrors())
if isValidEmail {
var user model.User log.Debug("User entered valid email.")
// search by email or username if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() {
isValidEmail, _ := formStruct.EmailValidation(email, formStruct.NewErrors()) return http.StatusNotFound, errors.New("User not found")
if isValidEmail { }
if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() { } else {
return http.StatusNotFound, errors.New("User not found") log.Debug("User entered username.")
if db.ORM.Where("username = ?", email).First(&user).RecordNotFound() {
return http.StatusNotFound, errors.New("User not found")
}
} }
} else { err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(pass))
if db.ORM.Where("username = ?", email).First(&user).RecordNotFound() { if err != nil {
return http.StatusNotFound, errors.New("User not found") 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)) return http.StatusNotFound, errors.New("user not found")
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
} }
// RegisterHanderFromForm sets cookie from a RegistrationForm. // RegisterHanderFromForm sets cookie from a RegistrationForm.
@ -113,31 +111,24 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) (int, error) {
return RegisterHanderFromForm(w, registrationForm) 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) { func CurrentUser(r *http.Request) (model.User, error) {
var user model.User var user model.User
var encoded string var token string
var err error
encoded = r.Header.Get("X-Auth-Token") token = r.Header.Get("X-Auth-Token")
if len(encoded) == 0 { if len(token) > 0 {
// check cookie instead log.Debug("header token exists")
cookie, err := r.Cookie(CookieName) } else {
token, err = Token(r)
log.Debug("header token does not exist")
if err != nil { if err != nil {
return user, err return user, err
} }
encoded = cookie.Value
} }
user_id, err := DecodeCookie(encoded) if db.ORM.Where("api_token = ?", token).First(&user).RecordNotFound() {
if err != nil { return user, errors.New("user not found")
return user, err
} }
if db.ORM.Where("user_id = ?", user_id).First(&user).RecordNotFound() { err = db.ORM.Model(&user).Error
return user, errors.New("User not found") return user, err
}
if user.Status == -1 {
// recheck as user might've been banned in the meantime
return user, errors.New("Account banned")
}
return user, nil
} }

Voir le fichier

@ -7,6 +7,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/db" "github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model" "github.com/ewhal/nyaa/model"
formStruct "github.com/ewhal/nyaa/service/user/form" formStruct "github.com/ewhal/nyaa/service/user/form"
@ -14,6 +15,7 @@ import (
"github.com/ewhal/nyaa/util/crypto" "github.com/ewhal/nyaa/util/crypto"
"github.com/ewhal/nyaa/util/log" "github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/util/modelHelper" "github.com/ewhal/nyaa/util/modelHelper"
"github.com/ewhal/nyaa/util/timeHelper"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@ -67,8 +69,15 @@ func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.Use
return user, err 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.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 { if db.ORM.Create(&user).Error != nil {
return user, errors.New("user not created") return user, errors.New("user not created")
} }
@ -148,13 +157,17 @@ func UpdateUserCore(user *model.User) (int, error) {
} }
} }
user.UpdatedAt = time.Now() token, err := crypto.GenerateRandomToken32()
err := db.ORM.Save(user).Error
if err != nil { if err != nil {
return http.StatusInternalServerError, err 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 return http.StatusOK, nil
} }
@ -184,13 +197,18 @@ func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *m
form.Username = user.Username form.Username = user.Username
} }
if (form.Email != user.Email) { if (form.Email != user.Email) {
// send verification to new email and keep old
SendVerificationToUser(user, form.Email) SendVerificationToUser(user, form.Email)
form.Email = user.Email form.Email = user.Email
} }
log.Debugf("form %+v\n", form) log.Debugf("form %+v\n", form)
modelHelper.AssignValue(&user, form) modelHelper.AssignValue(&user, form)
status, err := UpdateUserCore(&user) 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 return user, status, err
} }

Voir le fichier

@ -45,6 +45,7 @@ udp://tracker.leechers-paradise.org:6969
udp://explodie.org:6969 udp://explodie.org:6969
udp://tracker.opentrackr.org:1337 udp://tracker.opentrackr.org:1337
udp://tracker.internetwarriors.net:1337/announce udp://tracker.internetwarriors.net:1337/announce
udp://eddie4.nl:6969/announce
http://mgtracker.org:6969/announce http://mgtracker.org:6969/announce
http://tracker.baka-sub.cf/announce</pre> http://tracker.baka-sub.cf/announce</pre>

Voir le fichier

@ -1,4 +1,4 @@
{{define "title"}}{{ T "sign_in_title" }}{{end}} {{define "title"}}{{ T "sign_in_title" }}{{end}}
{{define "contclass"}}cont-view{{end}} {{define "contclass"}}cont-view{{end}}
{{define "content"}} {{define "content"}}
<div class="blockBody"> <div class="blockBody">
@ -24,8 +24,8 @@
{{end}} {{end}}
</div> </div>
<span class="button-checkbox"> <span class="button-checkbox">
<!-- <button type="button" class="btn hidden" data-color="info">{{ T "remember_me"}}</button> <button type="button" class="btn hidden" data-color="info">{{ T "remember_me"}}</button>
<input type="checkbox" name="remember_me" id="remember_me" checked="checked"> --> <input type="checkbox" name="remember_me" id="remember_me" checked="checked">
<a href="" class="btn btn-link pull-right">{{ T "forgot_password"}}</a> <a href="" class="btn btn-link pull-right">{{ T "forgot_password"}}</a>
</span> </span>
<hr class="colorgraph"> <hr class="colorgraph">