Skip to content

Commit dac3a02

Browse files
authored
Merge branch 'master' into fix-migrate-context-data
2 parents 1438875 + 9b261f5 commit dac3a02

File tree

394 files changed

+12849
-46459
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

394 files changed

+12849
-46459
lines changed

custom/conf/app.example.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,8 @@ COOKIE_SECURE = false
794794
GC_INTERVAL_TIME = 86400
795795
; Session life time in seconds, default is 86400 (1 day)
796796
SESSION_LIFE_TIME = 86400
797+
; SameSite settings. Either "none", "lax", or "strict"
798+
SAME_SITE=lax
797799

798800
[picture]
799801
AVATAR_UPLOAD_PATH = data/avatars

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,8 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
557557
- `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID.
558558
- `GC_INTERVAL_TIME`: **86400**: GC interval in seconds.
559559
- `SESSION_LIFE_TIME`: **86400**: Session life time in seconds, default is 86400 (1 day)
560+
- `DOMAIN`: **\<empty\>**: Sets the cookie Domain
561+
- `SAME_SITE`: **lax** \[strict, lax, none\]: Set the SameSite setting for the cookie.
560562

561563
## Picture (`picture`)
562564

models/issue.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1724,10 +1724,19 @@ func SearchIssueIDsByKeyword(kw string, repoIDs []int64, limit, start int) (int6
17241724
)
17251725

17261726
var ids = make([]int64, 0, limit)
1727-
err := x.Distinct("id").Table("issue").Where(cond).OrderBy("`updated_unix` DESC").Limit(limit, start).Find(&ids)
1727+
var res = make([]struct {
1728+
ID int64
1729+
UpdatedUnix int64
1730+
}, 0, limit)
1731+
err := x.Distinct("id", "updated_unix").Table("issue").Where(cond).
1732+
OrderBy("`updated_unix` DESC").Limit(limit, start).
1733+
Find(&res)
17281734
if err != nil {
17291735
return 0, nil, err
17301736
}
1737+
for _, r := range res {
1738+
ids = append(ids, r.ID)
1739+
}
17311740

17321741
total, err := x.Distinct("id").Table("issue").Where(cond).Count()
17331742
if err != nil {

modules/auth/sso/sso.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313

1414
"code.gitea.io/gitea/models"
1515
"code.gitea.io/gitea/modules/log"
16-
"code.gitea.io/gitea/modules/setting"
1716
"code.gitea.io/gitea/modules/web/middleware"
1817
)
1918

@@ -129,8 +128,8 @@ func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore
129128
}
130129
}
131130

132-
middleware.SetCookie(resp, "lang", user.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
131+
middleware.SetLocaleCookie(resp, user.Language, 0)
133132

134133
// Clear whatever CSRF has right now, force to generate a new one
135-
middleware.SetCookie(resp, setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
134+
middleware.DeleteCSRFCookie(resp)
136135
}

modules/context/auth.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"code.gitea.io/gitea/models"
1010
"code.gitea.io/gitea/modules/log"
1111
"code.gitea.io/gitea/modules/setting"
12+
"code.gitea.io/gitea/modules/web/middleware"
1213
)
1314

1415
// ToggleOptions contains required or check options
@@ -41,7 +42,7 @@ func Toggle(options *ToggleOptions) func(ctx *Context) {
4142
ctx.Data["Title"] = ctx.Tr("auth.must_change_password")
4243
ctx.Data["ChangePasscodeLink"] = setting.AppSubURL + "/user/change_password"
4344
if ctx.Req.URL.Path != "/user/events" {
44-
ctx.SetCookie("redirect_to", setting.AppSubURL+ctx.Req.URL.RequestURI(), 0, setting.AppSubURL)
45+
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
4546
}
4647
ctx.Redirect(setting.AppSubURL + "/user/settings/change_password")
4748
return
@@ -69,7 +70,7 @@ func Toggle(options *ToggleOptions) func(ctx *Context) {
6970
if options.SignInRequired {
7071
if !ctx.IsSigned {
7172
if ctx.Req.URL.Path != "/user/events" {
72-
ctx.SetCookie("redirect_to", setting.AppSubURL+ctx.Req.URL.RequestURI(), 0, setting.AppSubURL)
73+
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
7374
}
7475
ctx.Redirect(setting.AppSubURL + "/user/login")
7576
return
@@ -84,7 +85,7 @@ func Toggle(options *ToggleOptions) func(ctx *Context) {
8485
if !options.SignOutRequired && !ctx.IsSigned &&
8586
len(ctx.GetCookie(setting.CookieUserName)) > 0 {
8687
if ctx.Req.URL.Path != "/user/events" {
87-
ctx.SetCookie("redirect_to", setting.AppSubURL+ctx.Req.URL.RequestURI(), 0, setting.AppSubURL)
88+
middleware.SetRedirectToCookie(ctx.Resp, setting.AppSubURL+ctx.Req.URL.RequestURI())
8889
}
8990
ctx.Redirect(setting.AppSubURL + "/user/login")
9091
return

modules/context/context.go

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,28 @@ func (ctx *Context) Redirect(location string, status ...int) {
386386
http.Redirect(ctx.Resp, ctx.Req, location, code)
387387
}
388388

389-
// SetCookie set cookies to web browser
390-
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
391-
middleware.SetCookie(ctx.Resp, name, value, others...)
389+
// SetCookie convenience function to set most cookies consistently
390+
// CSRF and a few others are the exception here
391+
func (ctx *Context) SetCookie(name, value string, expiry int) {
392+
middleware.SetCookie(ctx.Resp, name, value,
393+
expiry,
394+
setting.AppSubURL,
395+
setting.SessionConfig.Domain,
396+
setting.SessionConfig.Secure,
397+
true,
398+
middleware.SameSite(setting.SessionConfig.SameSite))
399+
}
400+
401+
// DeleteCookie convenience function to delete most cookies consistently
402+
// CSRF and a few others are the exception here
403+
func (ctx *Context) DeleteCookie(name string) {
404+
middleware.SetCookie(ctx.Resp, name, "",
405+
-1,
406+
setting.AppSubURL,
407+
setting.SessionConfig.Domain,
408+
setting.SessionConfig.Secure,
409+
true,
410+
middleware.SameSite(setting.SessionConfig.SameSite))
392411
}
393412

394413
// GetCookie returns given cookie value from request header.
@@ -399,6 +418,11 @@ func (ctx *Context) GetCookie(name string) string {
399418
// GetSuperSecureCookie returns given cookie value from request header with secret string.
400419
func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) {
401420
val := ctx.GetCookie(name)
421+
return ctx.CookieDecrypt(secret, val)
422+
}
423+
424+
// CookieDecrypt returns given value from with secret string.
425+
func (ctx *Context) CookieDecrypt(secret, val string) (string, bool) {
402426
if val == "" {
403427
return "", false
404428
}
@@ -414,14 +438,21 @@ func (ctx *Context) GetSuperSecureCookie(secret, name string) (string, bool) {
414438
}
415439

416440
// SetSuperSecureCookie sets given cookie value to response header with secret string.
417-
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, others ...interface{}) {
441+
func (ctx *Context) SetSuperSecureCookie(secret, name, value string, expiry int) {
442+
text := ctx.CookieEncrypt(secret, value)
443+
444+
ctx.SetCookie(name, text, expiry)
445+
}
446+
447+
// CookieEncrypt encrypts a given value using the provided secret
448+
func (ctx *Context) CookieEncrypt(secret, value string) string {
418449
key := pbkdf2.Key([]byte(secret), []byte(secret), 1000, 16, sha256.New)
419450
text, err := com.AESGCMEncrypt(key, []byte(value))
420451
if err != nil {
421452
panic("error encrypting cookie: " + err.Error())
422453
}
423454

424-
ctx.SetCookie(name, hex.EncodeToString(text), others...)
455+
return hex.EncodeToString(text)
425456
}
426457

427458
// GetCookieInt returns cookie result in int type.
@@ -533,6 +564,7 @@ func getCsrfOpts() CsrfOptions {
533564
Header: "X-Csrf-Token",
534565
CookieDomain: setting.SessionConfig.Domain,
535566
CookiePath: setting.SessionConfig.CookiePath,
567+
SameSite: setting.SessionConfig.SameSite,
536568
}
537569
}
538570

@@ -597,17 +629,17 @@ func Contexter() func(next http.Handler) http.Handler {
597629
middleware.Domain(setting.SessionConfig.Domain),
598630
middleware.HTTPOnly(true),
599631
middleware.Secure(setting.SessionConfig.Secure),
600-
//middlewares.SameSite(opt.SameSite), FIXME: we need a samesite config
632+
middleware.SameSite(setting.SessionConfig.SameSite),
601633
)
602634
return
603635
}
604636

605-
ctx.SetCookie("macaron_flash", "", -1,
637+
middleware.SetCookie(ctx.Resp, "macaron_flash", "", -1,
606638
setting.SessionConfig.CookiePath,
607639
middleware.Domain(setting.SessionConfig.Domain),
608640
middleware.HTTPOnly(true),
609641
middleware.Secure(setting.SessionConfig.Secure),
610-
//middleware.SameSite(), FIXME: we need a samesite config
642+
middleware.SameSite(setting.SessionConfig.SameSite),
611643
)
612644
})
613645

modules/context/csrf.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
"net/http"
2323
"time"
2424

25+
"code.gitea.io/gitea/modules/web/middleware"
26+
2527
"github.com/unknwon/com"
2628
)
2729

@@ -37,6 +39,8 @@ type CSRF interface {
3739
GetCookiePath() string
3840
// Return the flag value used for the csrf token.
3941
GetCookieHTTPOnly() bool
42+
// Return cookie domain
43+
GetCookieDomain() string
4044
// Return the token.
4145
GetToken() string
4246
// Validate by token.
@@ -93,6 +97,11 @@ func (c *csrf) GetCookieHTTPOnly() bool {
9397
return c.CookieHTTPOnly
9498
}
9599

100+
// GetCookieDomain returns the flag value used for the csrf token.
101+
func (c *csrf) GetCookieDomain() string {
102+
return c.CookieDomain
103+
}
104+
96105
// GetToken returns the current token. This is typically used
97106
// to populate a hidden form in an HTML template.
98107
func (c *csrf) GetToken() string {
@@ -227,10 +236,14 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF {
227236
if opt.CookieLifeTime == 0 {
228237
expires = time.Now().AddDate(0, 0, 1)
229238
}
230-
ctx.SetCookie(opt.Cookie, x.Token, opt.CookieLifeTime, opt.CookiePath, opt.CookieDomain, opt.Secure, opt.CookieHTTPOnly, expires,
231-
func(c *http.Cookie) {
232-
c.SameSite = opt.SameSite
233-
},
239+
middleware.SetCookie(ctx.Resp, opt.Cookie, x.Token,
240+
opt.CookieLifeTime,
241+
opt.CookiePath,
242+
opt.CookieDomain,
243+
opt.Secure,
244+
opt.CookieHTTPOnly,
245+
expires,
246+
middleware.SameSite(opt.SameSite),
234247
)
235248
}
236249
}
@@ -248,14 +261,22 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF {
248261
func Validate(ctx *Context, x CSRF) {
249262
if token := ctx.Req.Header.Get(x.GetHeaderName()); len(token) > 0 {
250263
if !x.ValidToken(token) {
251-
ctx.SetCookie(x.GetCookieName(), "", -1, x.GetCookiePath())
264+
// Delete the cookie
265+
middleware.SetCookie(ctx.Resp, x.GetCookieName(), "",
266+
-1,
267+
x.GetCookiePath(),
268+
x.GetCookieDomain()) // FIXME: Do we need to set the Secure, httpOnly and SameSite values too?
252269
x.Error(ctx.Resp)
253270
}
254271
return
255272
}
256273
if token := ctx.Req.FormValue(x.GetFormName()); len(token) > 0 {
257274
if !x.ValidToken(token) {
258-
ctx.SetCookie(x.GetCookieName(), "", -1, x.GetCookiePath())
275+
// Delete the cookie
276+
middleware.SetCookie(ctx.Resp, x.GetCookieName(), "",
277+
-1,
278+
x.GetCookiePath(),
279+
x.GetCookieDomain()) // FIXME: Do we need to set the Secure, httpOnly and SameSite values too?
259280
x.Error(ctx.Resp)
260281
}
261282
return

modules/lfs/content_store.go

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"encoding/hex"
1010
"errors"
1111
"fmt"
12+
"hash"
1213
"io"
1314
"os"
1415

@@ -66,30 +67,27 @@ func (s *ContentStore) Get(meta *models.LFSMetaObject, fromByte int64) (io.ReadC
6667

6768
// Put takes a Meta object and an io.Reader and writes the content to the store.
6869
func (s *ContentStore) Put(meta *models.LFSMetaObject, r io.Reader) error {
69-
hash := sha256.New()
70-
rd := io.TeeReader(r, hash)
7170
p := meta.RelativePath()
72-
written, err := s.Save(p, rd)
71+
72+
// Wrap the provided reader with an inline hashing and size checker
73+
wrappedRd := newHashingReader(meta.Size, meta.Oid, r)
74+
75+
// now pass the wrapped reader to Save - if there is a size mismatch or hash mismatch then
76+
// the errors returned by the newHashingReader should percolate up to here
77+
written, err := s.Save(p, wrappedRd)
7378
if err != nil {
7479
log.Error("Whilst putting LFS OID[%s]: Failed to copy to tmpPath: %s Error: %v", meta.Oid, p, err)
7580
return err
7681
}
7782

83+
// This shouldn't happen but it is sensible to test
7884
if written != meta.Size {
7985
if err := s.Delete(p); err != nil {
8086
log.Error("Cleaning the LFS OID[%s] failed: %v", meta.Oid, err)
8187
}
8288
return errSizeMismatch
8389
}
8490

85-
shaStr := hex.EncodeToString(hash.Sum(nil))
86-
if shaStr != meta.Oid {
87-
if err := s.Delete(p); err != nil {
88-
log.Error("Cleaning the LFS OID[%s] failed: %v", meta.Oid, err)
89-
}
90-
return errHashMismatch
91-
}
92-
9391
return nil
9492
}
9593

@@ -118,3 +116,45 @@ func (s *ContentStore) Verify(meta *models.LFSMetaObject) (bool, error) {
118116

119117
return true, nil
120118
}
119+
120+
type hashingReader struct {
121+
internal io.Reader
122+
currentSize int64
123+
expectedSize int64
124+
hash hash.Hash
125+
expectedHash string
126+
}
127+
128+
func (r *hashingReader) Read(b []byte) (int, error) {
129+
n, err := r.internal.Read(b)
130+
131+
if n > 0 {
132+
r.currentSize += int64(n)
133+
wn, werr := r.hash.Write(b[:n])
134+
if wn != n || werr != nil {
135+
return n, werr
136+
}
137+
}
138+
139+
if err != nil && err == io.EOF {
140+
if r.currentSize != r.expectedSize {
141+
return n, errSizeMismatch
142+
}
143+
144+
shaStr := hex.EncodeToString(r.hash.Sum(nil))
145+
if shaStr != r.expectedHash {
146+
return n, errHashMismatch
147+
}
148+
}
149+
150+
return n, err
151+
}
152+
153+
func newHashingReader(expectedSize int64, expectedHash string, reader io.Reader) *hashingReader {
154+
return &hashingReader{
155+
internal: reader,
156+
expectedSize: expectedSize,
157+
expectedHash: expectedHash,
158+
hash: sha256.New(),
159+
}
160+
}

modules/setting/session.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package setting
66

77
import (
8+
"net/http"
89
"path"
910
"path/filepath"
1011
"strings"
@@ -31,10 +32,13 @@ var (
3132
Secure bool
3233
// Cookie domain name. Default is empty.
3334
Domain string
35+
// SameSite declares if your cookie should be restricted to a first-party or same-site context. Valid strings are "none", "lax", "strict". Default is "lax"
36+
SameSite http.SameSite
3437
}{
3538
CookieName: "i_like_gitea",
3639
Gclifetime: 86400,
3740
Maxlifetime: 86400,
41+
SameSite: http.SameSiteLaxMode,
3842
}
3943
)
4044

@@ -52,6 +56,15 @@ func newSessionService() {
5256
SessionConfig.Gclifetime = sec.Key("GC_INTERVAL_TIME").MustInt64(86400)
5357
SessionConfig.Maxlifetime = sec.Key("SESSION_LIFE_TIME").MustInt64(86400)
5458
SessionConfig.Domain = sec.Key("DOMAIN").String()
59+
samesiteString := sec.Key("SAME_SITE").In("lax", []string{"none", "lax", "strict"})
60+
switch strings.ToLower(samesiteString) {
61+
case "none":
62+
SessionConfig.SameSite = http.SameSiteNoneMode
63+
case "strict":
64+
SessionConfig.SameSite = http.SameSiteStrictMode
65+
default:
66+
SessionConfig.SameSite = http.SameSiteLaxMode
67+
}
5568

5669
json := jsoniter.ConfigCompatibleWithStandardLibrary
5770
shadowConfig, err := json.Marshal(SessionConfig)

0 commit comments

Comments
 (0)