Compare commits
17 Commits
release/v1
...
gitroast
Author | SHA1 | Date |
---|---|---|
AJ ONeal | 76fbfde40c | |
AJ ONeal | 20717e6139 | |
AJ ONeal | fa737a887b | |
AJ ONeal | e09a6248f1 | |
AJ ONeal | 1ff523881d | |
AJ ONeal | 0ae89454e1 | |
AJ ONeal | ce1739bd16 | |
AJ ONeal | 4c7727c3ed | |
AJ ONeal | 8718156545 | |
AJ ONeal | eda51c2079 | |
AJ ONeal | e64ff60c13 | |
AJ ONeal | ee0fa3e58f | |
AJ ONeal | 5a42829dbd | |
AJ ONeal | 996c9cbab3 | |
AJ ONeal | 95df7779ef | |
AJ ONeal | 20eec9abd3 | |
AJ ONeal | fa7fc43a13 |
|
@ -74,8 +74,9 @@ func (f *InstallForm) Validate(ctx *macaron.Context, errs binding.Errors) bindin
|
|||
type RegisterForm struct {
|
||||
UserName string `binding:"Required;AlphaDashDot;MaxSize(35)"`
|
||||
Email string `binding:"Required;Email;MaxSize(254)"`
|
||||
Password string `binding:"Required;MaxSize(255)"`
|
||||
Password string `binding:"MaxSize(255)"`
|
||||
Retype string
|
||||
Remember bool
|
||||
}
|
||||
|
||||
// Validate valideates the fields
|
||||
|
@ -86,6 +87,7 @@ func (f *RegisterForm) Validate(ctx *macaron.Context, errs binding.Errors) bindi
|
|||
// SignInForm form for signing in with user/password
|
||||
type SignInForm struct {
|
||||
UserName string `binding:"Required;MaxSize(254)"`
|
||||
// TODO remove required from password for SecondFactorAuthentication
|
||||
Password string `binding:"Required;MaxSize(255)"`
|
||||
Remember bool
|
||||
}
|
||||
|
|
|
@ -88,6 +88,9 @@ var (
|
|||
AppDataPath string
|
||||
AppWorkPath string
|
||||
|
||||
// User settings
|
||||
GoogleAnalyticsID string
|
||||
|
||||
// Server settings
|
||||
Protocol Scheme
|
||||
Domain string
|
||||
|
@ -695,6 +698,7 @@ func NewContext() {
|
|||
|
||||
sec := Cfg.Section("server")
|
||||
AppName = Cfg.Section("").Key("APP_NAME").MustString("Gitea: Git with a cup of tea")
|
||||
GoogleAnalyticsID = Cfg.Section("").Key("GOOGLE_ANALYTICS_ID").String()
|
||||
|
||||
Protocol = HTTP
|
||||
if sec.Key("PROTOCOL").String() == "https" {
|
||||
|
@ -1165,6 +1169,8 @@ var Service struct {
|
|||
EnableReverseProxyAuth bool
|
||||
EnableReverseProxyAutoRegister bool
|
||||
EnableCaptcha bool
|
||||
RequireExternalRegistrationCaptcha bool
|
||||
RequireExternalRegistrationPassword bool
|
||||
DefaultKeepEmailPrivate bool
|
||||
DefaultAllowCreateOrganization bool
|
||||
EnableTimetracking bool
|
||||
|
@ -1190,6 +1196,8 @@ func newService() {
|
|||
Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
|
||||
Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
|
||||
Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool()
|
||||
Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool()
|
||||
Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool()
|
||||
Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool()
|
||||
Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true)
|
||||
Service.EnableTimetracking = sec.Key("ENABLE_TIMETRACKING").MustBool(true)
|
||||
|
|
|
@ -61,6 +61,9 @@ func NewFuncMap() []template.FuncMap {
|
|||
"DisableGravatar": func() bool {
|
||||
return setting.DisableGravatar
|
||||
},
|
||||
"GoogleAnalyticsID": func() string {
|
||||
return setting.GoogleAnalyticsID
|
||||
},
|
||||
"ShowFooterTemplateLoadTime": func() bool {
|
||||
return setting.ShowFooterTemplateLoadTime
|
||||
},
|
||||
|
|
|
@ -9,7 +9,6 @@ sign_in_with = Sign In With
|
|||
sign_out = Sign Out
|
||||
sign_up = Register
|
||||
link_account = Link Account
|
||||
link_account_signin_or_signup = Sign in with existing credentials to link your existing account to this account. Or register a new one.
|
||||
register = Register
|
||||
website = Website
|
||||
version = Version
|
||||
|
@ -223,6 +222,12 @@ twofa_passcode_incorrect = Your passcode is incorrect. If you misplaced your dev
|
|||
twofa_scratch_token_incorrect = Your scratch code is incorrect.
|
||||
login_userpass = Sign In
|
||||
login_openid = OpenID
|
||||
oauth_signup_tab = Register New Account
|
||||
oauth_signup_title = Add Account Recovery Info
|
||||
oauth_signup_submit = Complete Account
|
||||
oauth_signin_tab = Link to Existing Account
|
||||
oauth_signin_title = Sign In to Authorize Linked Account
|
||||
oauth_signin_submit = Link Account
|
||||
openid_connect_submit = Connect
|
||||
openid_connect_title = Connect to an existing account
|
||||
openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new account here.
|
||||
|
|
|
@ -184,6 +184,10 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
|
||||
|
||||
// ***** START: User *****
|
||||
m.Group("/user", func() {
|
||||
m.Get("/reset_password", user.ResetPasswd)
|
||||
m.Post("/reset_password", user.ResetPasswdPost)
|
||||
})
|
||||
m.Group("/user", func() {
|
||||
m.Get("/login", user.SignIn)
|
||||
m.Post("/login", bindIgnErr(auth.SignInForm{}), user.SignInPost)
|
||||
|
@ -204,8 +208,6 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||
}, openIDSignInEnabled)
|
||||
m.Get("/sign_up", user.SignUp)
|
||||
m.Post("/sign_up", bindIgnErr(auth.RegisterForm{}), user.SignUpPost)
|
||||
m.Get("/reset_password", user.ResetPasswd)
|
||||
m.Post("/reset_password", user.ResetPasswdPost)
|
||||
m.Group("/oauth2", func() {
|
||||
m.Get("/:provider", user.SignInOAuth)
|
||||
m.Get("/:provider/callback", user.SignInOAuthCallback)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
@ -123,6 +125,7 @@ func SignIn(ctx *context.Context) {
|
|||
ctx.Data["OAuth2Providers"] = oauth2Providers
|
||||
ctx.Data["Title"] = ctx.Tr("sign_in")
|
||||
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
|
||||
ctx.Data["AllowPassword"] = true
|
||||
ctx.Data["PageIsSignIn"] = true
|
||||
ctx.Data["PageIsLogin"] = true
|
||||
|
||||
|
@ -142,6 +145,7 @@ func SignInPost(ctx *context.Context, form auth.SignInForm) {
|
|||
ctx.Data["OAuth2Providers"] = oauth2Providers
|
||||
ctx.Data["Title"] = ctx.Tr("sign_in")
|
||||
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login"
|
||||
ctx.Data["AllowPassword"] = true
|
||||
ctx.Data["PageIsSignIn"] = true
|
||||
ctx.Data["PageIsLogin"] = true
|
||||
|
||||
|
@ -490,6 +494,36 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
|
|||
return setting.AppSubURL + "/"
|
||||
}
|
||||
|
||||
func handleRegister(ctx *context.Context, u *models.User, remember bool, obeyRedirect bool) {
|
||||
// Auto-set admin for the only user.
|
||||
if models.CountUsers() == 1 {
|
||||
u.IsAdmin = true
|
||||
u.IsActive = true
|
||||
u.SetLastLogin()
|
||||
if err := models.UpdateUserCols(u, "is_admin", "is_active", "last_login_unix"); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Send confirmation email
|
||||
if setting.Service.RegisterEmailConfirm && u.ID > 1 {
|
||||
models.SendActivateAccountMail(ctx.Context, u)
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.HTML(200, TplActivate)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
log.Error(4, "Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Complete the signin without logging in again
|
||||
handleSignInFull(ctx, u, remember, true)
|
||||
}
|
||||
|
||||
// SignInOAuth handles the OAuth2 login buttons
|
||||
func SignInOAuth(ctx *context.Context) {
|
||||
provider := ctx.Params(":provider")
|
||||
|
@ -641,7 +675,8 @@ func oAuth2UserLoginCallback(loginSource *models.LoginSource, request *http.Requ
|
|||
func LinkAccount(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("link_account")
|
||||
ctx.Data["LinkAccountMode"] = true
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.RequireExternalRegistrationCaptcha //&& setting.Service.EnableCaptcha
|
||||
ctx.Data["AllowPassword"] = setting.Service.RequireExternalRegistrationPassword && !setting.Service.AllowOnlyExternalRegistration
|
||||
ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration
|
||||
ctx.Data["ShowRegistrationButton"] = false
|
||||
|
||||
|
@ -655,8 +690,30 @@ func LinkAccount(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
ctx.Data["user_name"] = gothUser.(goth.User).NickName
|
||||
ctx.Data["email"] = gothUser.(goth.User).Email
|
||||
uname := gothUser.(goth.User).NickName
|
||||
email := gothUser.(goth.User).Email
|
||||
ctx.Data["user_name"] = uname
|
||||
ctx.Data["email"] = email
|
||||
|
||||
if len(email) != 0 {
|
||||
u, err := models.GetUserByEmail(email)
|
||||
if err != nil && !models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("UserSignIn", err)
|
||||
return
|
||||
}
|
||||
if u != nil {
|
||||
ctx.Data["user_exists"] = true
|
||||
}
|
||||
} else if len(uname) != 0 {
|
||||
u, err := models.GetUserByName(uname)
|
||||
if err != nil && !models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("UserSignIn", err)
|
||||
return
|
||||
}
|
||||
if u != nil {
|
||||
ctx.Data["user_exists"] = true
|
||||
}
|
||||
}
|
||||
|
||||
ctx.HTML(200, tplLinkAccount)
|
||||
}
|
||||
|
@ -666,7 +723,9 @@ func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) {
|
|||
ctx.Data["Title"] = ctx.Tr("link_account")
|
||||
ctx.Data["LinkAccountMode"] = true
|
||||
ctx.Data["LinkAccountModeSignIn"] = true
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.RequireExternalRegistrationCaptcha //&& setting.Service.EnableCaptcha
|
||||
// Only allow a password if local login is enabled (TODO) except if SecondFactorAuthentication is enabled
|
||||
ctx.Data["AllowPassword"] = !setting.Service.AllowOnlyExternalRegistration
|
||||
ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration
|
||||
ctx.Data["ShowRegistrationButton"] = false
|
||||
|
||||
|
@ -732,7 +791,9 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
|
|||
ctx.Data["Title"] = ctx.Tr("link_account")
|
||||
ctx.Data["LinkAccountMode"] = true
|
||||
ctx.Data["LinkAccountModeRegister"] = true
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.RequireExternalRegistrationCaptcha //&& setting.Service.EnableCaptcha
|
||||
// TODO implement the same for local accounts, once email-based Second Factor Auth is available
|
||||
ctx.Data["AllowPassword"] = setting.Service.RequireExternalRegistrationPassword && !setting.Service.AllowOnlyExternalRegistration
|
||||
ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration
|
||||
ctx.Data["ShowRegistrationButton"] = false
|
||||
|
||||
|
@ -756,21 +817,35 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
|
|||
return
|
||||
}
|
||||
|
||||
if setting.Service.EnableCaptcha && !cpt.VerifyReq(ctx.Req) {
|
||||
if setting.Service.RequireExternalRegistrationCaptcha && !cpt.VerifyReq(ctx.Req) {
|
||||
ctx.Data["Err_Captcha"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplLinkAccount, &form)
|
||||
return
|
||||
}
|
||||
|
||||
if (len(strings.TrimSpace(form.Password)) > 0 || len(strings.TrimSpace(form.Retype)) > 0) && form.Password != form.Retype {
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplLinkAccount, &form)
|
||||
return
|
||||
}
|
||||
if len(strings.TrimSpace(form.Password)) > 0 && len(form.Password) < setting.MinPasswordLength {
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form)
|
||||
return
|
||||
if setting.Service.AllowOnlyExternalRegistration || !setting.Service.RequireExternalRegistrationPassword {
|
||||
// Generating a random password a stop-gap shim to get around the password requirement
|
||||
// Eventually the database should be changed to indicate "Second Factor" enabled accounts
|
||||
// that do not introduce the security vulnerabilities of a password
|
||||
bytes := make([]byte, 16)
|
||||
_, err := rand.Read(bytes)
|
||||
if nil != err {
|
||||
ctx.ServerError("CreateUser", err)
|
||||
return
|
||||
}
|
||||
form.Password = hex.EncodeToString(bytes)
|
||||
} else {
|
||||
// TODO Retype password should move to frontend JavaScript, not be required by server
|
||||
if (len(strings.TrimSpace(form.Password)) > 0 || len(strings.TrimSpace(form.Retype)) > 0) && form.Password != form.Retype {
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplLinkAccount, &form)
|
||||
return
|
||||
}
|
||||
if len(strings.TrimSpace(form.Password)) > 0 && len(form.Password) < setting.MinPasswordLength {
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
loginSource, err := models.GetActiveOAuth2LoginSourceByName(gothUser.(goth.User).Provider)
|
||||
|
@ -778,14 +853,20 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
|
|||
ctx.ServerError("CreateUser", err)
|
||||
}
|
||||
|
||||
// TODO LoginName should come from form.UserName... shouldn't it?
|
||||
u := &models.User{
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
IsActive: !setting.Service.RegisterEmailConfirm,
|
||||
LoginType: models.LoginOAuth2,
|
||||
LoginSource: loginSource.ID,
|
||||
LoginName: gothUser.(goth.User).UserID,
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
IsActive: !setting.Service.RegisterEmailConfirm,
|
||||
}
|
||||
|
||||
// This will link the account in such a way that it cannot be removed
|
||||
// TODO why is this different from normal linking?
|
||||
if setting.Service.AllowOnlyExternalRegistration {
|
||||
u.LoginType = models.LoginOAuth2
|
||||
u.LoginSource = loginSource.ID
|
||||
u.LoginName = gothUser.(goth.User).UserID
|
||||
}
|
||||
|
||||
if err := models.CreateUser(u); err != nil {
|
||||
|
@ -809,36 +890,19 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
|
|||
}
|
||||
log.Trace("Account created: %s", u.Name)
|
||||
|
||||
// Auto-set admin for the only user.
|
||||
if models.CountUsers() == 1 {
|
||||
u.IsAdmin = true
|
||||
u.IsActive = true
|
||||
u.SetLastLogin()
|
||||
if err := models.UpdateUserCols(u, "is_admin", "is_active", "last_login_unix"); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
// This will link the account in such a way that it can be removed
|
||||
if !setting.Service.AllowOnlyExternalRegistration {
|
||||
err = models.LinkAccountToUser(u, gothUser.(goth.User))
|
||||
if err != nil {
|
||||
ctx.ServerError("UserLinkAccount", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Send confirmation email
|
||||
if setting.Service.RegisterEmailConfirm && u.ID > 1 {
|
||||
models.SendActivateAccountMail(ctx.Context, u)
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.HTML(200, TplActivate)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
log.Error(4, "Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
handleRegister(ctx, u, form.Remember, true)
|
||||
}
|
||||
|
||||
// SignOut sign out from login status
|
||||
func SignOut(ctx *context.Context) {
|
||||
func handleSignOut(ctx *context.Context) {
|
||||
ctx.Session.Delete("uid")
|
||||
ctx.Session.Delete("uname")
|
||||
ctx.Session.Delete("socialId")
|
||||
|
@ -848,6 +912,11 @@ func SignOut(ctx *context.Context) {
|
|||
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie("lang", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) // Setting the lang cookie will trigger the middleware to reset the language ot previous state.
|
||||
}
|
||||
|
||||
// SignOut sign out from login status
|
||||
func SignOut(ctx *context.Context) {
|
||||
handleSignOut(ctx)
|
||||
ctx.Redirect(setting.AppSubURL + "/")
|
||||
}
|
||||
|
||||
|
@ -859,6 +928,8 @@ func SignUp(ctx *context.Context) {
|
|||
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
|
||||
|
||||
ctx.Data["AllowPassword"] = true
|
||||
|
||||
ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration
|
||||
|
||||
ctx.HTML(200, tplSignUp)
|
||||
|
@ -872,6 +943,8 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
|
|||
|
||||
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
|
||||
|
||||
ctx.Data["AllowPassword"] = true
|
||||
|
||||
//Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true
|
||||
if !setting.Service.ShowRegistrationButton {
|
||||
ctx.Error(403)
|
||||
|
@ -927,32 +1000,7 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
|
|||
}
|
||||
log.Trace("Account created: %s", u.Name)
|
||||
|
||||
// Auto-set admin for the only user.
|
||||
if models.CountUsers() == 1 {
|
||||
u.IsAdmin = true
|
||||
u.IsActive = true
|
||||
u.SetLastLogin()
|
||||
if err := models.UpdateUserCols(u, "is_admin", "is_active", "last_login_unix"); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Send confirmation email, no need for social account.
|
||||
if setting.Service.RegisterEmailConfirm && u.ID > 1 {
|
||||
models.SendActivateAccountMail(ctx.Context, u)
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.HTML(200, TplActivate)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
log.Error(4, "Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
handleRegister(ctx, u, form.Remember, true)
|
||||
}
|
||||
|
||||
// Activate render activate user page
|
||||
|
@ -1100,6 +1148,8 @@ func ForgotPasswdPost(ctx *context.Context) {
|
|||
func ResetPasswd(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
|
||||
|
||||
// TODO for security and convenience, show the username / email here
|
||||
|
||||
code := ctx.Query("code")
|
||||
if len(code) == 0 {
|
||||
ctx.Error(404)
|
||||
|
@ -1140,6 +1190,10 @@ func ResetPasswdPost(ctx *context.Context) {
|
|||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Just in case the user is signed in to another account
|
||||
handleSignOut(ctx)
|
||||
|
||||
u.HashPassword(passwd)
|
||||
if err := models.UpdateUserCols(u, "passwd", "rands", "salt"); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
|
@ -1147,6 +1201,9 @@ func ResetPasswdPost(ctx *context.Context) {
|
|||
}
|
||||
|
||||
log.Trace("User password reset: %s", u.Name)
|
||||
|
||||
// TODO change the former form to have password retype and remember me,
|
||||
// then sign in here instead of redirecting
|
||||
ctx.Redirect(setting.AppSubURL + "/user/login")
|
||||
return
|
||||
}
|
||||
|
|
|
@ -105,6 +105,17 @@
|
|||
|
||||
<script src="{{AppSubUrl}}/vendor/plugins/cssrelpreload/loadCSS.min.js"></script>
|
||||
<script src="{{AppSubUrl}}/vendor/plugins/cssrelpreload/cssrelpreload.min.js"></script>
|
||||
{{if .GoogleAnalyticsID}}
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{.GoogleAnalyticsID}}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '{{GoogleAnalyticsID}}');
|
||||
</script>
|
||||
{{end}}
|
||||
{{if .PageIsUserProfile}}
|
||||
<meta property="og:title" content="{{.Owner.Name}}" />
|
||||
<meta property="og:type" content="profile" />
|
||||
|
@ -265,6 +276,9 @@
|
|||
<a class="item{{if .PageIsSignIn}} active{{end}}" href="{{AppSubUrl}}/user/login?redirect_to={{.Link}}">
|
||||
<i class="octicon octicon-sign-in"></i> {{.i18n.Tr "sign_in"}}
|
||||
</a>
|
||||
<a class="item" href="{{AppSubUrl}}/user/oauth2/GitHub?redirect_to={{.Link}}">
|
||||
{{.i18n.Tr "sign_in_with"}} <i class="octicon octicon-mark-github"></i>
|
||||
</a>
|
||||
</div><!-- end anonymous right menu -->
|
||||
|
||||
{{end}}
|
||||
|
|
|
@ -1,15 +1,33 @@
|
|||
{{template "base/head" .}}
|
||||
|
||||
<div class="user link-account">
|
||||
<div class="ui middle very relaxed page grid">
|
||||
<div class="column">
|
||||
<p class="large center">
|
||||
{{.i18n.Tr "link_account_signin_or_signup"}}
|
||||
</p>
|
||||
|
||||
<div class="ui tabular menu">
|
||||
<!-- TODO handle .ShowRegistrationButton once other login bugs are fixed -->
|
||||
<div class="item {{if not .user_exists}}active{{end}}"
|
||||
data-tab="auth-link-signup-tab">
|
||||
{{.i18n.Tr "auth.oauth_signup_tab"}}
|
||||
</div>
|
||||
<div class="item {{if .user_exists}}active{{end}}"
|
||||
data-tab="auth-link-signin-tab">
|
||||
{{.i18n.Tr "auth.oauth_signin_tab"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui tab {{if not .user_exists}}active{{end}}"
|
||||
data-tab="auth-link-signup-tab">
|
||||
{{template "user/auth/signup_inner" .}}
|
||||
</div>
|
||||
<div class="ui tab {{if .user_exists}}active{{end}}"
|
||||
data-tab="auth-link-signin-tab">
|
||||
<div class="ui user signin container icon">
|
||||
{{template "user/auth/signin_inner" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui user signin container icon">
|
||||
{{template "user/auth/signin_inner" .}}
|
||||
</div>
|
||||
{{template "user/auth/signup_inner" .}}
|
||||
|
||||
{{template "base/footer" .}}
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
{{template "base/alert" .}}
|
||||
{{end}}
|
||||
<h4 class="ui top attached header center">
|
||||
{{.i18n.Tr "auth.login_userpass"}}
|
||||
{{if .LinkAccountMode}}
|
||||
{{.i18n.Tr "auth.oauth_signin_title"}}
|
||||
{{else}}
|
||||
{{.i18n.Tr "auth.login_userpass"}}
|
||||
{{end}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<form class="ui form" action="{{.SignInLink}}" method="post">
|
||||
|
@ -11,10 +15,12 @@
|
|||
<label for="user_name">{{.i18n.Tr "home.uname_holder"}}</label>
|
||||
<input id="user_name" name="user_name" value="{{.user_name}}" autofocus required>
|
||||
</div>
|
||||
{{if .AllowPassword}}
|
||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
|
||||
<label for="password">{{.i18n.Tr "password"}}</label>
|
||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" required>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .LinkAccountMode}}
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
|
@ -27,7 +33,13 @@
|
|||
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
<button class="ui green button">{{.i18n.Tr "sign_in"}}</button>
|
||||
<button class="ui green button">
|
||||
{{if .LinkAccountMode}}
|
||||
{{.i18n.Tr "auth.oauth_signin_submit"}}
|
||||
{{else}}
|
||||
{{.i18n.Tr "sign_in"}}
|
||||
{{end}}
|
||||
</button>
|
||||
<a href="{{AppSubUrl}}/user/forgot_password">{{.i18n.Tr "auth.forgot_password"}}</a>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
<form class="ui form" action="{{.SignUpLink}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<h3 class="ui top attached header">
|
||||
{{.i18n.Tr "sign_up"}}
|
||||
{{if .LinkAccountMode}}
|
||||
{{.i18n.Tr "auth.oauth_signup_title"}}
|
||||
{{else}}
|
||||
{{.i18n.Tr "sign_up"}}
|
||||
{{end}}
|
||||
</h3>
|
||||
<div class="ui attached segment">
|
||||
{{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister)}}
|
||||
|
@ -21,14 +25,16 @@
|
|||
<label for="email">{{.i18n.Tr "email"}}</label>
|
||||
<input id="email" name="email" type="email" value="{{.email}}" required>
|
||||
</div>
|
||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||
<label for="password">{{.i18n.Tr "password"}}</label>
|
||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" required>
|
||||
</div>
|
||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||
<label for="retype">{{.i18n.Tr "re_type"}}</label>
|
||||
<input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="off" required>
|
||||
</div>
|
||||
{{if .AllowPassword}}
|
||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||
<label for="password">{{.i18n.Tr "password"}}</label>
|
||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" required>
|
||||
</div>
|
||||
<div class="required inline field {{if and (.Err_Password) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeRegister))}}error{{end}}">
|
||||
<label for="retype">{{.i18n.Tr "re_type"}}</label>
|
||||
<input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="off" required>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .EnableCaptcha}}
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
|
@ -42,7 +48,20 @@
|
|||
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
<button class="ui green button">{{.i18n.Tr "auth.create_new_account"}}</button>
|
||||
<div class="ui checkbox">
|
||||
<label>{{.i18n.Tr "auth.remember_me"}}</label>
|
||||
<input name="remember" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<label></label>
|
||||
<button class="ui green button">
|
||||
{{if .LinkAccountMode}}
|
||||
{{.i18n.Tr "auth.oauth_signup_submit"}}
|
||||
{{else}}
|
||||
{{.i18n.Tr "auth.create_new_account"}}
|
||||
{{end}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{if not .LinkAccountMode}}
|
||||
|
|
Loading…
Reference in New Issue