2014-07-26 08:24:27 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package user
import (
"net/url"
"strings"
2014-08-01 01:25:34 +04:00
"github.com/macaron-contrib/captcha"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
"github.com/gogits/gogs/modules/base"
"github.com/gogits/gogs/modules/log"
2014-08-10 04:25:02 +04:00
"github.com/gogits/gogs/modules/mailer"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/modules/middleware"
"github.com/gogits/gogs/modules/setting"
)
const (
2014-08-16 12:21:17 +04:00
SIGNIN base . TplName = "user/auth/signin"
SIGNUP base . TplName = "user/auth/signup"
ACTIVATE base . TplName = "user/auth/activate"
FORGOT_PASSWORD base . TplName = "user/auth/forgot_passwd"
RESET_PASSWORD base . TplName = "user/auth/reset_passwd"
2014-07-26 08:24:27 +04:00
)
func SignIn ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "sign_in" )
2014-08-07 14:40:05 +04:00
if _ , ok := ctx . Session . Get ( "socialId" ) . ( int64 ) ; ok {
ctx . Data [ "IsSocialLogin" ] = true
ctx . HTML ( 200 , SIGNIN )
return
}
2014-07-26 08:24:27 +04:00
2014-08-07 14:40:05 +04:00
if setting . OauthService != nil {
ctx . Data [ "OauthEnabled" ] = true
ctx . Data [ "OauthService" ] = setting . OauthService
}
2014-07-26 08:24:27 +04:00
// Check auto-login.
2015-08-13 21:43:40 +03:00
isSucceed , err := middleware . AutoSignIn ( ctx )
2014-07-26 08:24:27 +04:00
if err != nil {
2015-08-13 21:43:40 +03:00
ctx . Handle ( 500 , "AutoSignIn" , err )
2014-07-26 08:24:27 +04:00
return
}
2015-08-13 21:43:40 +03:00
if isSucceed {
if redirectTo , _ := url . QueryUnescape ( ctx . GetCookie ( "redirect_to" ) ) ; len ( redirectTo ) > 0 {
ctx . SetCookie ( "redirect_to" , "" , - 1 , setting . AppSubUrl )
ctx . Redirect ( redirectTo )
}
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-07-26 08:24:27 +04:00
return
}
2015-08-13 21:43:40 +03:00
ctx . HTML ( 200 , SIGNIN )
2014-07-26 08:24:27 +04:00
}
func SignInPost ( ctx * middleware . Context , form auth . SignInForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "sign_in" )
2014-08-07 14:40:05 +04:00
sid , isOauth := ctx . Session . Get ( "socialId" ) . ( int64 )
if isOauth {
ctx . Data [ "IsSocialLogin" ] = true
} else if setting . OauthService != nil {
ctx . Data [ "OauthEnabled" ] = true
ctx . Data [ "OauthService" ] = setting . OauthService
}
2014-07-26 08:24:27 +04:00
if ctx . HasError ( ) {
ctx . HTML ( 200 , SIGNIN )
return
}
u , err := models . UserSignIn ( form . UserName , form . Password )
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2014-07-26 08:24:27 +04:00
ctx . RenderWithErr ( ctx . Tr ( "form.username_password_incorrect" ) , SIGNIN , & form )
2014-08-10 08:02:00 +04:00
} else {
ctx . Handle ( 500 , "UserSignIn" , err )
2014-07-26 08:24:27 +04:00
}
return
}
if form . Remember {
days := 86400 * setting . LogInRememberDays
2014-09-21 16:07:00 +04:00
ctx . SetCookie ( setting . CookieUserName , u . Name , days , setting . AppSubUrl )
2014-07-26 08:24:27 +04:00
ctx . SetSuperSecureCookie ( base . EncodeMd5 ( u . Rands + u . Passwd ) ,
2014-09-21 16:07:00 +04:00
setting . CookieRememberName , u . Name , days , setting . AppSubUrl )
2014-07-26 08:24:27 +04:00
}
// Bind with social account.
2014-08-07 14:40:05 +04:00
if isOauth {
if err = models . BindUserOauth2 ( u . Id , sid ) ; err != nil {
if err == models . ErrOauth2RecordNotExist {
ctx . Handle ( 404 , "GetOauth2ById" , err )
} else {
ctx . Handle ( 500 , "GetOauth2ById" , err )
}
return
}
ctx . Session . Delete ( "socialId" )
log . Trace ( "%s OAuth binded: %s -> %d" , ctx . Req . RequestURI , form . UserName , sid )
}
2014-07-26 08:24:27 +04:00
ctx . Session . Set ( "uid" , u . Id )
ctx . Session . Set ( "uname" , u . Name )
if redirectTo , _ := url . QueryUnescape ( ctx . GetCookie ( "redirect_to" ) ) ; len ( redirectTo ) > 0 {
2014-09-21 16:07:00 +04:00
ctx . SetCookie ( "redirect_to" , "" , - 1 , setting . AppSubUrl )
2014-07-26 08:24:27 +04:00
ctx . Redirect ( redirectTo )
return
}
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-07-26 08:24:27 +04:00
}
func SignOut ( ctx * middleware . Context ) {
ctx . Session . Delete ( "uid" )
ctx . Session . Delete ( "uname" )
2014-08-07 14:40:05 +04:00
ctx . Session . Delete ( "socialId" )
ctx . Session . Delete ( "socialName" )
ctx . Session . Delete ( "socialEmail" )
2014-09-21 16:07:00 +04:00
ctx . SetCookie ( setting . CookieUserName , "" , - 1 , setting . AppSubUrl )
ctx . SetCookie ( setting . CookieRememberName , "" , - 1 , setting . AppSubUrl )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-07-26 08:24:27 +04:00
}
2014-08-07 14:40:05 +04:00
func oauthSignUp ( ctx * middleware . Context , sid int64 ) {
2014-08-10 04:25:02 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "sign_up" )
2014-08-07 14:40:05 +04:00
2014-08-10 04:25:02 +04:00
if _ , err := models . GetOauth2ById ( sid ) ; err != nil {
if err == models . ErrOauth2RecordNotExist {
ctx . Handle ( 404 , "GetOauth2ById" , err )
} else {
ctx . Handle ( 500 , "GetOauth2ById" , err )
}
return
}
2014-08-07 14:40:05 +04:00
2014-08-10 04:25:02 +04:00
ctx . Data [ "IsSocialLogin" ] = true
ctx . Data [ "uname" ] = strings . Replace ( ctx . Session . Get ( "socialName" ) . ( string ) , " " , "" , - 1 )
ctx . Data [ "email" ] = ctx . Session . Get ( "socialEmail" )
log . Trace ( "social ID: %v" , ctx . Session . Get ( "socialId" ) )
ctx . HTML ( 200 , SIGNUP )
2014-08-07 14:40:05 +04:00
}
2014-07-26 08:24:27 +04:00
func SignUp ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "sign_up" )
2015-09-13 18:07:21 +03:00
ctx . Data [ "EnableCaptcha" ] = setting . Service . EnableCaptcha
2015-09-13 16:51:51 +03:00
2014-07-26 08:24:27 +04:00
if setting . Service . DisableRegistration {
ctx . Data [ "DisableRegistration" ] = true
ctx . HTML ( 200 , SIGNUP )
return
}
2014-08-07 14:40:05 +04:00
if sid , ok := ctx . Session . Get ( "socialId" ) . ( int64 ) ; ok {
oauthSignUp ( ctx , sid )
return
}
2014-07-26 08:24:27 +04:00
ctx . HTML ( 200 , SIGNUP )
}
func SignUpPost ( ctx * middleware . Context , cpt * captcha . Captcha , form auth . RegisterForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "sign_up" )
2015-09-13 18:07:21 +03:00
ctx . Data [ "EnableCaptcha" ] = setting . Service . EnableCaptcha
2015-09-13 16:51:51 +03:00
2014-07-26 08:24:27 +04:00
if setting . Service . DisableRegistration {
ctx . Error ( 403 )
return
}
isOauth := false
2014-08-10 04:25:02 +04:00
sid , isOauth := ctx . Session . Get ( "socialId" ) . ( int64 )
if isOauth {
ctx . Data [ "IsSocialLogin" ] = true
}
2014-07-26 08:24:27 +04:00
if ctx . HasError ( ) {
ctx . HTML ( 200 , SIGNUP )
return
}
2015-09-13 18:07:21 +03:00
if setting . Service . EnableCaptcha && ! cpt . VerifyReq ( ctx . Req ) {
2014-07-26 08:24:27 +04:00
ctx . Data [ "Err_Captcha" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.captcha_incorrect" ) , SIGNUP , & form )
return
2015-09-13 16:51:51 +03:00
}
if form . Password != form . Retype {
2014-07-26 08:24:27 +04:00
ctx . Data [ "Err_Password" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.password_not_match" ) , SIGNUP , & form )
return
}
u := & models . User {
Name : form . UserName ,
Email : form . Email ,
Passwd : form . Password ,
IsActive : ! setting . Service . RegisterEmailConfirm || isOauth ,
}
if err := models . CreateUser ( u ) ; err != nil {
2015-03-27 00:11:47 +03:00
switch {
case models . IsErrUserAlreadyExist ( err ) :
2014-07-26 08:24:27 +04:00
ctx . Data [ "Err_UserName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.username_been_taken" ) , SIGNUP , & form )
2015-03-27 00:11:47 +03:00
case models . IsErrEmailAlreadyUsed ( err ) :
2014-07-26 08:24:27 +04:00
ctx . Data [ "Err_Email" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.email_been_used" ) , SIGNUP , & form )
2015-03-27 00:11:47 +03:00
case models . IsErrNameReserved ( err ) :
2014-07-26 08:24:27 +04:00
ctx . Data [ "Err_UserName" ] = true
2015-03-27 00:11:47 +03:00
ctx . RenderWithErr ( ctx . Tr ( "user.form.name_reserved" , err . ( models . ErrNameReserved ) . Name ) , SIGNUP , & form )
case models . IsErrNamePatternNotAllowed ( err ) :
ctx . Data [ "Err_UserName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "user.form.name_pattern_not_allowed" , err . ( models . ErrNamePatternNotAllowed ) . Pattern ) , SIGNUP , & form )
2014-07-26 08:24:27 +04:00
default :
ctx . Handle ( 500 , "CreateUser" , err )
}
return
}
log . Trace ( "Account created: %s" , u . Name )
2015-08-18 23:58:45 +03:00
// Auto-set admin for the only user.
if models . CountUsers ( ) == 1 {
u . IsAdmin = true
u . IsActive = true
if err := models . UpdateUser ( u ) ; err != nil {
ctx . Handle ( 500 , "UpdateUser" , err )
return
}
}
2014-07-26 08:24:27 +04:00
// Bind social account.
2014-08-10 04:25:02 +04:00
if isOauth {
if err := models . BindUserOauth2 ( u . Id , sid ) ; err != nil {
ctx . Handle ( 500 , "BindUserOauth2" , err )
return
}
ctx . Session . Delete ( "socialId" )
log . Trace ( "%s OAuth binded: %s -> %d" , ctx . Req . RequestURI , form . UserName , sid )
}
2014-07-26 08:24:27 +04:00
// Send confirmation e-mail, no need for social account.
2014-08-10 04:25:02 +04:00
if ! isOauth && setting . Service . RegisterEmailConfirm && u . Id > 1 {
2015-09-17 08:54:12 +03:00
mailer . SendActivateAccountMail ( ctx . Context , u )
2014-08-10 04:25:02 +04:00
ctx . Data [ "IsSendRegisterMail" ] = true
ctx . Data [ "Email" ] = u . Email
ctx . Data [ "Hours" ] = setting . Service . ActiveCodeLives / 60
2014-09-15 17:56:12 +04:00
ctx . HTML ( 200 , ACTIVATE )
2014-08-10 04:25:02 +04:00
if err := ctx . Cache . Put ( "MailResendLimit_" + u . LowerName , u . LowerName , 180 ) ; err != nil {
log . Error ( 4 , "Set cache(MailResendLimit) fail: %v" , err )
}
return
}
2014-07-26 08:24:27 +04:00
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/login" )
2014-07-26 08:24:27 +04:00
}
func Activate ( ctx * middleware . Context ) {
2014-08-10 08:02:00 +04:00
code := ctx . Query ( "code" )
if len ( code ) == 0 {
ctx . Data [ "IsActivatePage" ] = true
if ctx . User . IsActive {
ctx . Error ( 404 )
return
}
// Resend confirmation e-mail.
if setting . Service . RegisterEmailConfirm {
if ctx . Cache . IsExist ( "MailResendLimit_" + ctx . User . LowerName ) {
ctx . Data [ "ResendLimited" ] = true
} else {
ctx . Data [ "Hours" ] = setting . Service . ActiveCodeLives / 60
2015-09-17 08:54:12 +03:00
mailer . SendActivateAccountMail ( ctx . Context , ctx . User )
2014-08-10 08:02:00 +04:00
if err := ctx . Cache . Put ( "MailResendLimit_" + ctx . User . LowerName , ctx . User . LowerName , 180 ) ; err != nil {
log . Error ( 4 , "Set cache(MailResendLimit) fail: %v" , err )
}
}
} else {
ctx . Data [ "ServiceNotEnabled" ] = true
}
ctx . HTML ( 200 , ACTIVATE )
return
}
// Verify code.
if user := models . VerifyUserActiveCode ( code ) ; user != nil {
user . IsActive = true
user . Rands = models . GetUserSalt ( )
if err := models . UpdateUser ( user ) ; err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2014-08-10 08:02:00 +04:00
ctx . Error ( 404 )
} else {
ctx . Handle ( 500 , "UpdateUser" , err )
}
return
}
log . Trace ( "User activated: %s" , user . Name )
ctx . Session . Set ( "uid" , user . Id )
ctx . Session . Set ( "uname" , user . Name )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-08-10 08:02:00 +04:00
return
}
ctx . Data [ "IsActivateFailed" ] = true
ctx . HTML ( 200 , ACTIVATE )
2014-07-26 08:24:27 +04:00
}
2014-12-17 18:41:49 +03:00
func ActivateEmail ( ctx * middleware . Context ) {
code := ctx . Query ( "code" )
email_string := ctx . Query ( "email" )
// Verify code.
if email := models . VerifyActiveEmailCode ( code , email_string ) ; email != nil {
2015-02-22 06:13:47 +03:00
if err := email . Activate ( ) ; err != nil {
2014-12-17 18:41:49 +03:00
ctx . Handle ( 500 , "ActivateEmail" , err )
}
log . Trace ( "Email activated: %s" , email . Email )
2015-09-17 21:57:24 +03:00
ctx . Flash . Success ( ctx . Tr ( "settings.add_email_successs" ) )
2014-12-17 18:41:49 +03:00
}
ctx . Redirect ( setting . AppSubUrl + "/user/settings/email" )
return
}
2014-07-26 08:24:27 +04:00
func ForgotPasswd ( ctx * middleware . Context ) {
2014-08-10 08:02:00 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "auth.forgot_password" )
2014-07-26 08:24:27 +04:00
if setting . MailService == nil {
ctx . Data [ "IsResetDisable" ] = true
ctx . HTML ( 200 , FORGOT_PASSWORD )
return
}
ctx . Data [ "IsResetRequest" ] = true
ctx . HTML ( 200 , FORGOT_PASSWORD )
}
func ForgotPasswdPost ( ctx * middleware . Context ) {
2014-08-10 08:02:00 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "auth.forgot_password" )
if setting . MailService == nil {
2015-09-17 21:57:24 +03:00
ctx . Handle ( 403 , "ForgotPasswdPost" , nil )
2014-08-10 08:02:00 +04:00
return
}
ctx . Data [ "IsResetRequest" ] = true
email := ctx . Query ( "email" )
2015-09-17 21:57:24 +03:00
ctx . Data [ "Email" ] = email
2014-08-10 08:02:00 +04:00
u , err := models . GetUserByEmail ( email )
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2014-08-10 08:02:00 +04:00
ctx . Data [ "Err_Email" ] = true
ctx . RenderWithErr ( ctx . Tr ( "auth.email_not_associate" ) , FORGOT_PASSWORD , nil )
} else {
ctx . Handle ( 500 , "user.ResetPasswd(check existence)" , err )
}
return
}
if ctx . Cache . IsExist ( "MailResendLimit_" + u . LowerName ) {
ctx . Data [ "ResendLimited" ] = true
ctx . HTML ( 200 , FORGOT_PASSWORD )
return
}
2015-09-17 21:57:24 +03:00
mailer . SendResetPasswordMail ( ctx . Context , u )
2014-08-10 08:02:00 +04:00
if err = ctx . Cache . Put ( "MailResendLimit_" + u . LowerName , u . LowerName , 180 ) ; err != nil {
log . Error ( 4 , "Set cache(MailResendLimit) fail: %v" , err )
}
ctx . Data [ "Hours" ] = setting . Service . ActiveCodeLives / 60
ctx . Data [ "IsResetSent" ] = true
ctx . HTML ( 200 , FORGOT_PASSWORD )
2014-07-26 08:24:27 +04:00
}
func ResetPasswd ( ctx * middleware . Context ) {
2014-08-10 08:02:00 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "auth.reset_password" )
2014-07-26 08:24:27 +04:00
code := ctx . Query ( "code" )
if len ( code ) == 0 {
ctx . Error ( 404 )
return
}
ctx . Data [ "Code" ] = code
ctx . Data [ "IsResetForm" ] = true
ctx . HTML ( 200 , RESET_PASSWORD )
}
func ResetPasswdPost ( ctx * middleware . Context ) {
2014-08-10 08:02:00 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "auth.reset_password" )
code := ctx . Query ( "code" )
if len ( code ) == 0 {
ctx . Error ( 404 )
return
}
ctx . Data [ "Code" ] = code
if u := models . VerifyUserActiveCode ( code ) ; u != nil {
// Validate password length.
passwd := ctx . Query ( "password" )
if len ( passwd ) < 6 {
ctx . Data [ "IsResetForm" ] = true
ctx . Data [ "Err_Password" ] = true
ctx . RenderWithErr ( ctx . Tr ( "auth.password_too_short" ) , RESET_PASSWORD , nil )
return
}
u . Passwd = passwd
u . Rands = models . GetUserSalt ( )
u . Salt = models . GetUserSalt ( )
u . EncodePasswd ( )
if err := models . UpdateUser ( u ) ; err != nil {
ctx . Handle ( 500 , "UpdateUser" , err )
return
}
log . Trace ( "User password reset: %s" , u . Name )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/login" )
2014-08-10 08:02:00 +04:00
return
}
ctx . Data [ "IsResetFailed" ] = true
ctx . HTML ( 200 , RESET_PASSWORD )
2014-07-26 08:24:27 +04:00
}