code.gitea.io/gitea@v1.22.3/modules/web/middleware/cookie.go (about)

     1  // Copyright 2020 The Macaron Authors
     2  // Copyright 2020 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package middleware
     6  
     7  import (
     8  	"net/http"
     9  	"net/url"
    10  	"strings"
    11  
    12  	"code.gitea.io/gitea/modules/session"
    13  	"code.gitea.io/gitea/modules/setting"
    14  )
    15  
    16  // SetRedirectToCookie convenience function to set the RedirectTo cookie consistently
    17  func SetRedirectToCookie(resp http.ResponseWriter, value string) {
    18  	SetSiteCookie(resp, "redirect_to", value, 0)
    19  }
    20  
    21  // DeleteRedirectToCookie convenience function to delete most cookies consistently
    22  func DeleteRedirectToCookie(resp http.ResponseWriter) {
    23  	SetSiteCookie(resp, "redirect_to", "", -1)
    24  }
    25  
    26  // GetSiteCookie returns given cookie value from request header.
    27  func GetSiteCookie(req *http.Request, name string) string {
    28  	cookie, err := req.Cookie(name)
    29  	if err != nil {
    30  		return ""
    31  	}
    32  	val, _ := url.QueryUnescape(cookie.Value)
    33  	return val
    34  }
    35  
    36  // SetSiteCookie returns given cookie value from request header.
    37  func SetSiteCookie(resp http.ResponseWriter, name, value string, maxAge int) {
    38  	// Previous versions would use a cookie path with a trailing /.
    39  	// These are more specific than cookies without a trailing /, so
    40  	// we need to delete these if they exist.
    41  	deleteLegacySiteCookie(resp, name)
    42  	cookie := &http.Cookie{
    43  		Name:     name,
    44  		Value:    url.QueryEscape(value),
    45  		MaxAge:   maxAge,
    46  		Path:     setting.SessionConfig.CookiePath,
    47  		Domain:   setting.SessionConfig.Domain,
    48  		Secure:   setting.SessionConfig.Secure,
    49  		HttpOnly: true,
    50  		SameSite: setting.SessionConfig.SameSite,
    51  	}
    52  	resp.Header().Add("Set-Cookie", cookie.String())
    53  }
    54  
    55  // deleteLegacySiteCookie deletes the cookie with the given name at the cookie
    56  // path with a trailing /, which would unintentionally override the cookie.
    57  func deleteLegacySiteCookie(resp http.ResponseWriter, name string) {
    58  	if setting.SessionConfig.CookiePath == "" || strings.HasSuffix(setting.SessionConfig.CookiePath, "/") {
    59  		// If the cookie path ends with /, no legacy cookies will take
    60  		// precedence, so do nothing.  The exception is that cookies with no
    61  		// path could override other cookies, but it's complicated and we don't
    62  		// currently handle that.
    63  		return
    64  	}
    65  
    66  	cookie := &http.Cookie{
    67  		Name:     name,
    68  		Value:    "",
    69  		MaxAge:   -1,
    70  		Path:     setting.SessionConfig.CookiePath + "/",
    71  		Domain:   setting.SessionConfig.Domain,
    72  		Secure:   setting.SessionConfig.Secure,
    73  		HttpOnly: true,
    74  		SameSite: setting.SessionConfig.SameSite,
    75  	}
    76  	resp.Header().Add("Set-Cookie", cookie.String())
    77  }
    78  
    79  func init() {
    80  	session.BeforeRegenerateSession = append(session.BeforeRegenerateSession, func(resp http.ResponseWriter, _ *http.Request) {
    81  		// Ensure that a cookie with a trailing slash does not take precedence over
    82  		// the cookie written by the middleware.
    83  		deleteLegacySiteCookie(resp, setting.SessionConfig.CookieName)
    84  	})
    85  }