Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion modules/markup/html_link.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ func createDescriptionLink(href, content string) *html.Node {
Attr: []html.Attribute{
{Key: "href", Val: href},
{Key: "target", Val: "_blank"},
{Key: "rel", Val: "noopener noreferrer"},
},
}
textNode.Parent = linkNode
Expand Down
2 changes: 1 addition & 1 deletion modules/markup/sanitizer_description_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestDescriptionSanitizer(t *testing.T) {
`<span class="emoji" aria-label="thumbs up">THUMBS UP</span>`, `<span class="emoji" aria-label="thumbs up">THUMBS UP</span>`,
`<span style="color: red">Hello World</span>`, `<span>Hello World</span>`,
`<br>`, ``,
`<a href="https://example.com" target="_blank" rel="noopener noreferrer">https://example.com</a>`, `<a href="https://example.com" target="_blank" rel="noopener noreferrer nofollow">https://example.com</a>`,
`<a href="https://example.com" target="_blank">https://example.com</a>`, `<a href="https://example.com" target="_blank" rel="nofollow noopener">https://example.com</a>`,
`<a href="data:1234">data</a>`, `data`,
`<mark>Important!</mark>`, `Important!`,
`<details>Click me! <summary>Nothing to see here.</summary></details>`, `Click me! Nothing to see here.`,
Expand Down
14 changes: 12 additions & 2 deletions modules/web/middleware/cookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,24 @@ import (
"code.gitea.io/gitea/modules/util"
)

const cookieRedirectTo = "redirect_to"

func GetRedirectToCookie(req *http.Request) string {
return GetSiteCookie(req, cookieRedirectTo)
}

// SetRedirectToCookie convenience function to set the RedirectTo cookie consistently
func SetRedirectToCookie(resp http.ResponseWriter, value string) {
SetSiteCookie(resp, "redirect_to", value, 0)
SetSiteCookie(resp, cookieRedirectTo, value, 0)
}

// DeleteRedirectToCookie convenience function to delete most cookies consistently
func DeleteRedirectToCookie(resp http.ResponseWriter) {
SetSiteCookie(resp, "redirect_to", "", -1)
SetSiteCookie(resp, cookieRedirectTo, "", -1)
}

func RedirectLinkUserLogin(req *http.Request) string {
return setting.AppSubURL + "/user/login?redirect_to=" + url.QueryEscape(setting.AppSubURL+req.URL.RequestURI())
}

// GetSiteCookie returns given cookie value from request header.
Expand Down
2 changes: 1 addition & 1 deletion routers/common/blockexpensive.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func BlockExpensive() func(next http.Handler) http.Handler {
ret := determineRequestPriority(reqctx.FromContext(req.Context()))
if !ret.SignedIn {
if ret.Expensive || ret.LongPolling {
http.Redirect(w, req, setting.AppSubURL+"/user/login", http.StatusSeeOther)
http.Redirect(w, req, middleware.RedirectLinkUserLogin(req), http.StatusSeeOther)
return
}
}
Expand Down
6 changes: 3 additions & 3 deletions routers/web/auth/2fa.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var (
func TwoFactor(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("twofa")

if CheckAutoLogin(ctx) {
if performAutoLogin(ctx) {
return
}

Expand Down Expand Up @@ -99,7 +99,7 @@ func TwoFactorPost(ctx *context.Context) {
func TwoFactorScratch(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("twofa_scratch")

if CheckAutoLogin(ctx) {
if performAutoLogin(ctx) {
return
}

Expand Down Expand Up @@ -151,7 +151,7 @@ func TwoFactorScratchPost(ctx *context.Context) {
return
}

handleSignInFull(ctx, u, remember, false)
handleSignInFull(ctx, u, remember)
if ctx.Written() {
return
}
Expand Down
93 changes: 47 additions & 46 deletions routers/web/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"html/template"
"net/http"
"net/url"
"strings"

"code.gitea.io/gitea/models/auth"
Expand Down Expand Up @@ -126,20 +127,47 @@ func resetLocale(ctx *context.Context, u *user_model.User) error {
return nil
}

func RedirectAfterLogin(ctx *context.Context) {
func rememberAuthRedirectLink(ctx *context.Context) {
redirectTo := ctx.FormString("redirect_to")
if redirectTo == "" {
redirectTo = ctx.GetSiteCookie("redirect_to")
if ref, err := url.Parse(ctx.Req.Referer()); err == nil && httplib.IsCurrentGiteaSiteURL(ctx, ctx.Req.Referer()) {
// the request paths starting with "/user/" are either:
// * auth related pages: don't redirect back to them
// * user settings pages: they have "require sign-in" protection already, no "referer redirect" would happen
skipRefererRedirect := strings.HasPrefix(ref.Path, setting.AppSubURL+"/user/")
if !skipRefererRedirect {
redirectTo = ref.RequestURI()
}
}
}
if redirectTo != "" {
middleware.SetRedirectToCookie(ctx.Resp, redirectTo)
}
}

func consumeAuthRedirectLink(ctx *context.Context) string {
redirects := []string{ctx.FormString("redirect_to"), middleware.GetRedirectToCookie(ctx.Req)}
middleware.DeleteRedirectToCookie(ctx.Resp)
nextRedirectTo := setting.AppSubURL + string(setting.LandingPageURL)
if setting.LandingPageURL == setting.LandingPageLogin {
nextRedirectTo = setting.AppSubURL + "/" // do not cycle-redirect to the login page
redirects = append(redirects, setting.AppSubURL+"/") // do not cycle-redirect to the login page
} else {
redirects = append(redirects, setting.AppSubURL+string(setting.LandingPageURL))
}
for _, link := range redirects {
if link != "" && httplib.IsCurrentGiteaSiteURL(ctx, link) {
return link
}
}
ctx.RedirectToCurrentSite(redirectTo, nextRedirectTo)
return setting.AppSubURL + "/"
}

func CheckAutoLogin(ctx *context.Context) bool {
func redirectAfterAuth(ctx *context.Context) {
ctx.RedirectToCurrentSite(consumeAuthRedirectLink(ctx))
}

func performAutoLogin(ctx *context.Context) bool {
rememberAuthRedirectLink(ctx)

isSucceed, err := autoSignIn(ctx) // try to auto-login
if err != nil {
if errors.Is(err, auth_service.ErrAuthTokenInvalidHash) {
Expand All @@ -150,13 +178,8 @@ func CheckAutoLogin(ctx *context.Context) bool {
return true
}

redirectTo := ctx.FormString("redirect_to")
if len(redirectTo) > 0 {
middleware.SetRedirectToCookie(ctx.Resp, redirectTo)
}

if isSucceed {
RedirectAfterLogin(ctx)
redirectAfterAuth(ctx)
return true
}

Expand All @@ -181,11 +204,11 @@ func prepareSignInPageData(ctx *context.Context) {

// SignIn render sign in page
func SignIn(ctx *context.Context) {
if CheckAutoLogin(ctx) {
if performAutoLogin(ctx) {
return
}
if ctx.IsSigned {
RedirectAfterLogin(ctx)
redirectAfterAuth(ctx)
return
}
prepareSignInPageData(ctx)
Expand Down Expand Up @@ -295,19 +318,19 @@ func SignInPost(ctx *context.Context) {

// This handles the final part of the sign-in process of the user.
func handleSignIn(ctx *context.Context, u *user_model.User, remember bool) {
redirect := handleSignInFull(ctx, u, remember, true)
handleSignInFull(ctx, u, remember)
if ctx.Written() {
return
}
ctx.Redirect(redirect)
redirectAfterAuth(ctx)
}

func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRedirect bool) string {
func handleSignInFull(ctx *context.Context, u *user_model.User, remember bool) {
if remember {
nt, token, err := auth_service.CreateAuthTokenForUserID(ctx, u.ID)
if err != nil {
ctx.ServerError("CreateAuthTokenForUserID", err)
return setting.AppSubURL + "/"
return
}

ctx.SetSiteCookie(setting.CookieRememberName, nt.ID+":"+token, setting.LogInRememberDays*timeutil.Day)
Expand All @@ -316,7 +339,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
userHasTwoFactorAuth, err := auth.HasTwoFactorOrWebAuthn(ctx, u.ID)
if err != nil {
ctx.ServerError("HasTwoFactorOrWebAuthn", err)
return setting.AppSubURL + "/"
return
}

if err := updateSession(ctx, []string{
Expand All @@ -335,7 +358,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
session.KeyUserHasTwoFactorAuth: userHasTwoFactorAuth,
}); err != nil {
ctx.ServerError("RegenerateSession", err)
return setting.AppSubURL + "/"
return
}

// Language setting of the user overwrites the one previously set
Expand All @@ -346,7 +369,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
}
if err := user_service.UpdateUser(ctx, u, opts); err != nil {
ctx.ServerError("UpdateUser Language", fmt.Errorf("Error updating user language [user: %d, locale: %s]", u.ID, ctx.Locale.Language()))
return setting.AppSubURL + "/"
return
}
}

Expand All @@ -359,21 +382,8 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
// Register last login
if err := user_service.UpdateUser(ctx, u, &user_service.UpdateOptions{SetLastLogin: true}); err != nil {
ctx.ServerError("UpdateUser", err)
return setting.AppSubURL + "/"
}

if redirectTo := ctx.GetSiteCookie("redirect_to"); redirectTo != "" && httplib.IsCurrentGiteaSiteURL(ctx, redirectTo) {
middleware.DeleteRedirectToCookie(ctx.Resp)
if obeyRedirect {
ctx.RedirectToCurrentSite(redirectTo)
}
return redirectTo
}

if obeyRedirect {
ctx.Redirect(setting.AppSubURL + "/")
return
}
return setting.AppSubURL + "/"
}

// extractUserNameFromOAuth2 tries to extract a normalized username from the given OAuth2 user.
Expand Down Expand Up @@ -436,10 +446,7 @@ func SignUp(ctx *context.Context) {
// Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true
ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration

redirectTo := ctx.FormString("redirect_to")
if len(redirectTo) > 0 {
middleware.SetRedirectToCookie(ctx.Resp, redirectTo)
}
rememberAuthRedirectLink(ctx)

ctx.HTML(http.StatusOK, tplSignUp)
}
Expand Down Expand Up @@ -817,13 +824,7 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) {
}

ctx.Flash.Success(ctx.Tr("auth.account_activated"))
if redirectTo := ctx.GetSiteCookie("redirect_to"); len(redirectTo) > 0 {
middleware.DeleteRedirectToCookie(ctx.Resp)
ctx.RedirectToCurrentSite(redirectTo)
return
}

ctx.Redirect(setting.AppSubURL + "/")
redirectAfterAuth(ctx)
}

// ActivateEmail render the activate email page
Expand Down
14 changes: 2 additions & 12 deletions routers/web/auth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web/middleware"
source_service "code.gitea.io/gitea/services/auth/source"
"code.gitea.io/gitea/services/auth/source/oauth2"
"code.gitea.io/gitea/services/context"
Expand All @@ -42,10 +41,7 @@ func SignInOAuth(ctx *context.Context) {
return
}

redirectTo := ctx.FormString("redirect_to")
if len(redirectTo) > 0 {
middleware.SetRedirectToCookie(ctx.Resp, redirectTo)
}
rememberAuthRedirectLink(ctx)

// try to do a direct callback flow, so we don't authenticate the user again but use the valid accesstoken to get the user
user, gothUser, err := oAuth2UserLoginCallback(ctx, authSource, ctx.Req, ctx.Resp)
Expand Down Expand Up @@ -398,13 +394,7 @@ func handleOAuth2SignIn(ctx *context.Context, authSource *auth.Source, u *user_m
return
}

if redirectTo := ctx.GetSiteCookie("redirect_to"); len(redirectTo) > 0 {
middleware.DeleteRedirectToCookie(ctx.Resp)
ctx.RedirectToCurrentSite(redirectTo)
return
}

ctx.Redirect(setting.AppSubURL + "/")
redirectAfterAuth(ctx)
return
}

Expand Down
2 changes: 1 addition & 1 deletion routers/web/auth/openid.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func SignInOpenID(ctx *context.Context) {
return
}

if CheckAutoLogin(ctx) {
if performAutoLogin(ctx) {
return
}

Expand Down
11 changes: 2 additions & 9 deletions routers/web/auth/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
"code.gitea.io/gitea/services/mailer"
Expand Down Expand Up @@ -236,7 +235,7 @@ func ResetPasswdPost(ctx *context.Context) {
return
}

handleSignInFull(ctx, u, remember, false)
handleSignInFull(ctx, u, remember)
if ctx.Written() {
return
}
Expand Down Expand Up @@ -308,11 +307,5 @@ func MustChangePasswordPost(ctx *context.Context) {

log.Trace("User updated password: %s", ctx.Doer.Name)

if redirectTo := ctx.GetSiteCookie("redirect_to"); redirectTo != "" {
middleware.DeleteRedirectToCookie(ctx.Resp)
ctx.RedirectToCurrentSite(redirectTo)
return
}

ctx.Redirect(setting.AppSubURL + "/")
redirectAfterAuth(ctx)
}
18 changes: 5 additions & 13 deletions routers/web/auth/webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var tplWebAuthn templates.TplName = "user/auth/webauthn"
func WebAuthn(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("twofa")

if CheckAutoLogin(ctx) {
if performAutoLogin(ctx) {
return
}

Expand Down Expand Up @@ -156,12 +156,8 @@ func WebAuthnPasskeyLogin(ctx *context.Context) {
}

remember := false // TODO: implement remember me
redirect := handleSignInFull(ctx, user, remember, false)
if redirect == "" {
redirect = setting.AppSubURL + "/"
}

ctx.JSONRedirect(redirect)
handleSignInFull(ctx, user, remember)
ctx.JSONRedirect(consumeAuthRedirectLink(ctx))
}

// WebAuthnLoginAssertion submits a WebAuthn challenge to the browser
Expand Down Expand Up @@ -274,11 +270,7 @@ func WebAuthnLoginAssertionPost(ctx *context.Context) {
}

remember := ctx.Session.Get("twofaRemember").(bool)
redirect := handleSignInFull(ctx, user, remember, false)
if redirect == "" {
redirect = setting.AppSubURL + "/"
}
handleSignInFull(ctx, user, remember)
_ = ctx.Session.Delete("twofaUid")

ctx.JSONRedirect(redirect)
ctx.JSONRedirect(consumeAuthRedirectLink(ctx))
}
Loading