diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000..1ce2a87611e81 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,114 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# IntelliJ +.idea +# Goland's output filename can not be set manually +/go_build_* + +# MS VSCode +.vscode +__debug_bin + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +*coverage.out +coverage.all +cpu.out + +/modules/migration/bindata.go +/modules/migration/bindata.go.hash +/modules/options/bindata.go +/modules/options/bindata.go.hash +/modules/public/bindata.go +/modules/public/bindata.go.hash +/modules/templates/bindata.go +/modules/templates/bindata.go.hash + +*.db +*.log + +/gitea +/gitea-vet +/debug +/integrations.test + +/bin +/dist +/custom/* +!/custom/conf +/custom/conf/* +!/custom/conf/app.example.ini +/data +/indexers +/log +/public/img/avatar +/tests/integration/gitea-integration-* +/tests/integration/indexers-* +/tests/e2e/gitea-e2e-* +/tests/e2e/indexers-* +/tests/e2e/reports +/tests/e2e/test-artifacts +/tests/e2e/test-snapshots +/tests/*.ini +/node_modules +/yarn.lock +/yarn-error.log +/npm-debug.log* +/public/js +/public/serviceworker.js +/public/css +/public/fonts +/public/img/webpack +/vendor +/web_src/fomantic/node_modules +/web_src/fomantic/build/* +!/web_src/fomantic/build/semantic.js +!/web_src/fomantic/build/semantic.css +!/web_src/fomantic/build/themes +/web_src/fomantic/build/themes/* +!/web_src/fomantic/build/themes/default +/web_src/fomantic/build/themes/default/assets/* +!/web_src/fomantic/build/themes/default/assets/fonts +/web_src/fomantic/build/themes/default/assets/fonts/* +!/web_src/fomantic/build/themes/default/assets/fonts/icons.woff2 +!/web_src/fomantic/build/themes/default/assets/fonts/outline-icons.woff2 +/VERSION +/.air +/.go-licenses + +# Snapcraft +snap/.snapcraft/ +parts/ +stage/ +prime/ +*.snap +*.snap-build +*_source.tar.bz2 +.DS_Store + +# Make evidence files +/.make_evidence + +# Manpage +/man diff --git a/cmd/admin.go b/cmd/admin.go index 525bc2cfcdbef..d33d17a53ddf0 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -413,9 +413,9 @@ var ( Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN", }, cli.StringFlag{ - Name: "addr", + Name: "host", Value: "", - Usage: "SMTP Addr", + Usage: "SMTP Host", }, cli.IntFlag{ Name: "port", @@ -955,8 +955,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error { } conf.Auth = c.String("auth-type") } - if c.IsSet("addr") { - conf.Addr = c.String("addr") + if c.IsSet("host") { + conf.Host = c.String("host") } if c.IsSet("port") { conf.Port = c.Int("port") diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go index 418e9b9ccc6db..ec3b611312a9a 100644 --- a/models/avatars/avatar.go +++ b/models/avatars/avatar.go @@ -150,10 +150,11 @@ func generateEmailAvatarLink(email string, size int, final bool) string { return DefaultAvatarLink() } - enableFederatedAvatar, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar) + enableFederatedAvatarSetting, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar) + enableFederatedAvatar := enableFederatedAvatarSetting.GetValueBool() var err error - if enableFederatedAvatar != nil && enableFederatedAvatar.GetValueBool() && system_model.LibravatarService != nil { + if enableFederatedAvatar && system_model.LibravatarService != nil { emailHash := saveEmailHash(email) if final { // for final link, we can spend more time on slow external query @@ -171,8 +172,10 @@ func generateEmailAvatarLink(email string, size int, final bool) string { return urlStr } - disableGravatar, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) - if disableGravatar != nil && !disableGravatar.GetValueBool() { + disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) + + disableGravatar := disableGravatarSetting.GetValueBool() + if !disableGravatar { // copy GravatarSourceURL, because we will modify its Path. avatarURLCopy := *system_model.GravatarSourceURL avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email)) diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 5f5ec8fdd7136..6ef4ef561794a 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -6,6 +6,7 @@ package migrations import ( + "context" "fmt" "os" @@ -23,6 +24,7 @@ import ( "code.gitea.io/gitea/models/migrations/v1_7" "code.gitea.io/gitea/models/migrations/v1_8" "code.gitea.io/gitea/models/migrations/v1_9" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -527,6 +529,13 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t return nil } + // Some migration tasks depend on the git command + if git.DefaultContext == nil { + if err = git.InitSimple(context.Background()); err != nil { + return err + } + } + // Migrate for i, m := range migrations[v-minDBVersion:] { log.Info("Migration[%d]: %s", v+int64(i), m.Description()) diff --git a/models/system/setting.go b/models/system/setting.go index 9711d38f3b23e..b4011b1b3ed62 100644 --- a/models/system/setting.go +++ b/models/system/setting.go @@ -12,6 +12,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -35,6 +36,10 @@ func (s *Setting) TableName() string { } func (s *Setting) GetValueBool() bool { + if s == nil { + return false + } + b, _ := strconv.ParseBool(s.SettingValue) return b } @@ -75,8 +80,8 @@ func IsErrDataExpired(err error) bool { return ok } -// GetSetting returns specific setting -func GetSetting(key string) (*Setting, error) { +// GetSettingNoCache returns specific setting without using the cache +func GetSettingNoCache(key string) (*Setting, error) { v, err := GetSettings([]string{key}) if err != nil { return nil, err @@ -87,6 +92,24 @@ func GetSetting(key string) (*Setting, error) { return v[key], nil } +// GetSetting returns the setting value via the key +func GetSetting(key string) (*Setting, error) { + return cache.Get(genSettingCacheKey(key), func() (*Setting, error) { + res, err := GetSettingNoCache(key) + if err != nil { + return nil, err + } + return res, nil + }) +} + +// GetSettingBool return bool value of setting, +// none existing keys and errors are ignored and result in false +func GetSettingBool(key string) bool { + s, _ := GetSetting(key) + return s.GetValueBool() +} + // GetSettings returns specific settings func GetSettings(keys []string) (map[string]*Setting, error) { for i := 0; i < len(keys); i++ { @@ -139,12 +162,13 @@ func GetAllSettings() (AllSettings, error) { // DeleteSetting deletes a specific setting for a user func DeleteSetting(setting *Setting) error { + cache.Remove(genSettingCacheKey(setting.SettingKey)) _, err := db.GetEngine(db.DefaultContext).Delete(setting) return err } func SetSettingNoVersion(key, value string) error { - s, err := GetSetting(key) + s, err := GetSettingNoCache(key) if IsErrSettingIsNotExist(err) { return SetSetting(&Setting{ SettingKey: key, @@ -160,9 +184,13 @@ func SetSettingNoVersion(key, value string) error { // SetSetting updates a users' setting for a specific key func SetSetting(setting *Setting) error { - if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil { + _, err := cache.Set(genSettingCacheKey(setting.SettingKey), func() (*Setting, error) { + return setting, upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version) + }) + if err != nil { return err } + setting.Version++ return nil } @@ -213,7 +241,7 @@ var ( func Init() error { var disableGravatar bool - disableGravatarSetting, err := GetSetting(KeyPictureDisableGravatar) + disableGravatarSetting, err := GetSettingNoCache(KeyPictureDisableGravatar) if IsErrSettingIsNotExist(err) { disableGravatar = setting.GetDefaultDisableGravatar() disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)} @@ -224,7 +252,7 @@ func Init() error { } var enableFederatedAvatar bool - enableFederatedAvatarSetting, err := GetSetting(KeyPictureEnableFederatedAvatar) + enableFederatedAvatarSetting, err := GetSettingNoCache(KeyPictureEnableFederatedAvatar) if IsErrSettingIsNotExist(err) { enableFederatedAvatar = setting.GetDefaultEnableFederatedAvatar(disableGravatar) enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)} diff --git a/models/system/setting_key.go b/models/system/setting_key.go index 5a6ea6ed722fd..14105b89d0d3b 100644 --- a/models/system/setting_key.go +++ b/models/system/setting_key.go @@ -9,3 +9,8 @@ const ( KeyPictureDisableGravatar = "picture.disable_gravatar" KeyPictureEnableFederatedAvatar = "picture.enable_federated_avatar" ) + +// genSettingCacheKey returns the cache key for some configuration +func genSettingCacheKey(key string) string { + return "system.setting." + key +} diff --git a/models/user/avatar.go b/models/user/avatar.go index f73ac56c5e4ce..102206f3a208e 100644 --- a/models/user/avatar.go +++ b/models/user/avatar.go @@ -68,11 +68,9 @@ func (u *User) AvatarLinkWithSize(size int) string { useLocalAvatar := false autoGenerateAvatar := false - var disableGravatar bool disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) - if disableGravatarSetting != nil { - disableGravatar = disableGravatarSetting.GetValueBool() - } + + disableGravatar := disableGravatarSetting.GetValueBool() switch { case u.UseCustomAvatar: diff --git a/models/user/setting.go b/models/user/setting.go index 5fe7c2ec23249..896f3c8da12d0 100644 --- a/models/user/setting.go +++ b/models/user/setting.go @@ -10,6 +10,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/cache" "xorm.io/builder" ) @@ -47,9 +48,25 @@ func IsErrUserSettingIsNotExist(err error) bool { return ok } -// GetSetting returns specific setting +// genSettingCacheKey returns the cache key for some configuration +func genSettingCacheKey(userID int64, key string) string { + return fmt.Sprintf("user_%d.setting.%s", userID, key) +} + +// GetSetting returns the setting value via the key func GetSetting(uid int64, key string) (*Setting, error) { - v, err := GetUserSettings(uid, []string{key}) + return cache.Get(genSettingCacheKey(uid, key), func() (*Setting, error) { + res, err := GetSettingNoCache(uid, key) + if err != nil { + return nil, err + } + return res, nil + }) +} + +// GetSettingNoCache returns specific setting without using the cache +func GetSettingNoCache(uid int64, key string) (*Setting, error) { + v, err := GetSettings(uid, []string{key}) if err != nil { return nil, err } @@ -59,8 +76,8 @@ func GetSetting(uid int64, key string) (*Setting, error) { return v[key], nil } -// GetUserSettings returns specific settings from user -func GetUserSettings(uid int64, keys []string) (map[string]*Setting, error) { +// GetSettings returns specific settings from user +func GetSettings(uid int64, keys []string) (map[string]*Setting, error) { settings := make([]*Setting, 0, len(keys)) if err := db.GetEngine(db.DefaultContext). Where("user_id=?", uid). @@ -105,6 +122,7 @@ func GetUserSetting(userID int64, key string, def ...string) (string, error) { if err := validateUserSettingKey(key); err != nil { return "", err } + setting := &Setting{UserID: userID, SettingKey: key} has, err := db.GetEngine(db.DefaultContext).Get(setting) if err != nil { @@ -124,7 +142,10 @@ func DeleteUserSetting(userID int64, key string) error { if err := validateUserSettingKey(key); err != nil { return err } + + cache.Remove(genSettingCacheKey(userID, key)) _, err := db.GetEngine(db.DefaultContext).Delete(&Setting{UserID: userID, SettingKey: key}) + return err } @@ -133,7 +154,12 @@ func SetUserSetting(userID int64, key, value string) error { if err := validateUserSettingKey(key); err != nil { return err } - return upsertUserSettingValue(userID, key, value) + + _, err := cache.Set(genSettingCacheKey(userID, key), func() (string, error) { + return value, upsertUserSettingValue(userID, key, value) + }) + + return err } func upsertUserSettingValue(userID int64, key, value string) error { diff --git a/models/user/setting_test.go b/models/user/setting_test.go index f0083038df0f1..5a772a8ce7cf7 100644 --- a/models/user/setting_test.go +++ b/models/user/setting_test.go @@ -27,7 +27,7 @@ func TestSettings(t *testing.T) { assert.NoError(t, err) // get specific setting - settings, err := user_model.GetUserSettings(99, []string{keyName}) + settings, err := user_model.GetSettings(99, []string{keyName}) assert.NoError(t, err) assert.Len(t, settings, 1) assert.EqualValues(t, newSetting.SettingValue, settings[keyName].SettingValue) diff --git a/modules/activitypub/user_settings.go b/modules/activitypub/user_settings.go index fc9775b0f0cfa..d192b9cdb2771 100644 --- a/modules/activitypub/user_settings.go +++ b/modules/activitypub/user_settings.go @@ -11,7 +11,7 @@ import ( // GetKeyPair function returns a user's private and public keys func GetKeyPair(user *user_model.User) (pub, priv string, err error) { var settings map[string]*user_model.Setting - settings, err = user_model.GetUserSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) + settings, err = user_model.GetSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) if err != nil { return } else if len(settings) == 0 { diff --git a/modules/cache/cache.go b/modules/cache/cache.go index 21d0cd0a04996..d98b0a0cec3b6 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -46,32 +46,64 @@ func GetCache() mc.Cache { return conn } +// Get returns the key value from cache with callback when no key exists in cache +func Get[V interface{}](key string, getFunc func() (V, error)) (V, error) { + if conn == nil || setting.CacheService.TTL == 0 { + return getFunc() + } + + cached := conn.Get(key) + if value, ok := cached.(V); ok { + return value, nil + } + + value, err := getFunc() + if err != nil { + return value, err + } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) +} + +// Set updates and returns the key value in the cache with callback. The old value is only removed if the updateFunc() is successful +func Set[V interface{}](key string, valueFunc func() (V, error)) (V, error) { + if conn == nil || setting.CacheService.TTL == 0 { + return valueFunc() + } + + value, err := valueFunc() + if err != nil { + return value, err + } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) +} + // GetString returns the key value from cache with callback when no key exists in cache func GetString(key string, getFunc func() (string, error)) (string, error) { if conn == nil || setting.CacheService.TTL == 0 { return getFunc() } - if !conn.IsExist(key) { - var ( - value string - err error - ) - if value, err = getFunc(); err != nil { - return value, err - } - err = conn.Put(key, value, setting.CacheService.TTLSeconds()) + + cached := conn.Get(key) + + if cached == nil { + value, err := getFunc() if err != nil { - return "", err + return value, err } + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } - value := conn.Get(key) - if v, ok := value.(string); ok { - return v, nil + + if value, ok := cached.(string); ok { + return value, nil } - if v, ok := value.(fmt.Stringer); ok { - return v.String(), nil + + if stringer, ok := cached.(fmt.Stringer); ok { + return stringer.String(), nil } - return fmt.Sprintf("%s", conn.Get(key)), nil + + return fmt.Sprintf("%s", cached), nil } // GetInt returns key value from cache with callback when no key exists in cache @@ -79,30 +111,33 @@ func GetInt(key string, getFunc func() (int, error)) (int, error) { if conn == nil || setting.CacheService.TTL == 0 { return getFunc() } - if !conn.IsExist(key) { - var ( - value int - err error - ) - if value, err = getFunc(); err != nil { - return value, err - } - err = conn.Put(key, value, setting.CacheService.TTLSeconds()) + + cached := conn.Get(key) + + if cached == nil { + value, err := getFunc() if err != nil { - return 0, err + return value, err } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } - switch value := conn.Get(key).(type) { + + switch v := cached.(type) { case int: - return value, nil + return v, nil case string: - v, err := strconv.Atoi(value) + value, err := strconv.Atoi(v) if err != nil { return 0, err } - return v, nil + return value, nil default: - return 0, fmt.Errorf("Unsupported cached value type: %v", value) + value, err := getFunc() + if err != nil { + return value, err + } + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } } @@ -111,30 +146,34 @@ func GetInt64(key string, getFunc func() (int64, error)) (int64, error) { if conn == nil || setting.CacheService.TTL == 0 { return getFunc() } - if !conn.IsExist(key) { - var ( - value int64 - err error - ) - if value, err = getFunc(); err != nil { - return value, err - } - err = conn.Put(key, value, setting.CacheService.TTLSeconds()) + + cached := conn.Get(key) + + if cached == nil { + value, err := getFunc() if err != nil { - return 0, err + return value, err } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } - switch value := conn.Get(key).(type) { + + switch v := conn.Get(key).(type) { case int64: - return value, nil + return v, nil case string: - v, err := strconv.ParseInt(value, 10, 64) + value, err := strconv.ParseInt(v, 10, 64) if err != nil { return 0, err } - return v, nil + return value, nil default: - return 0, fmt.Errorf("Unsupported cached value type: %v", value) + value, err := getFunc() + if err != nil { + return value, err + } + + return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) } } diff --git a/modules/system/setting.go b/modules/system/setting.go deleted file mode 100644 index aebf24a501949..0000000000000 --- a/modules/system/setting.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2021 The Gitea 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 system - -import ( - "strconv" - - "code.gitea.io/gitea/models/system" - "code.gitea.io/gitea/modules/cache" -) - -func genKey(key string) string { - return "system.setting." + key -} - -// GetSetting returns the setting value via the key -func GetSetting(key string) (string, error) { - return cache.GetString(genKey(key), func() (string, error) { - res, err := system.GetSetting(key) - if err != nil { - return "", err - } - return res.SettingValue, nil - }) -} - -// GetSettingBool return bool value of setting, -// none existing keys and errors are ignored and result in false -func GetSettingBool(key string) bool { - s, _ := GetSetting(key) - b, _ := strconv.ParseBool(s) - return b -} - -// SetSetting sets the setting value -func SetSetting(key, value string, version int) error { - cache.Remove(genKey(key)) - - return system.SetSetting(&system.Setting{ - SettingKey: key, - SettingValue: value, - Version: version, - }) -} diff --git a/modules/system/user_setting.go b/modules/system/user_setting.go deleted file mode 100644 index eaf146c08dd6e..0000000000000 --- a/modules/system/user_setting.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2021 The Gitea 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 system - -import ( - "fmt" - - "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/cache" -) - -func genUserKey(userID int64, key string) string { - return fmt.Sprintf("user_%d.setting.%s", userID, key) -} - -// GetUserSetting returns the user setting value via the key -func GetUserSetting(userID int64, key string) (string, error) { - return cache.GetString(genUserKey(userID, key), func() (string, error) { - res, err := user.GetSetting(userID, key) - if err != nil { - return "", err - } - return res.SettingValue, nil - }) -} - -// SetUserSetting sets the user setting value -func SetUserSetting(userID int64, key, value string) error { - cache.Remove(genUserKey(userID, key)) - - return user.SetUserSetting(userID, key, value) -} diff --git a/modules/templates/helper.go b/modules/templates/helper.go index c5434b7c632ed..d0866d3e2c46f 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -43,7 +43,6 @@ import ( "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/svg" - system_module "code.gitea.io/gitea/modules/system" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/gitdiff" @@ -88,7 +87,7 @@ func NewFuncMap() []template.FuncMap { return setting.AssetVersion }, "DisableGravatar": func() bool { - return system_module.GetSettingBool(system_model.KeyPictureDisableGravatar) + return system_model.GetSettingBool(system_model.KeyPictureDisableGravatar) }, "DefaultShowFullName": func() bool { return setting.UI.DefaultShowFullName diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index b79b317555966..7ea8a52809e60 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -159,7 +159,7 @@ func parseLDAPConfig(form forms.AuthenticationForm) *ldap.Source { func parseSMTPConfig(form forms.AuthenticationForm) *smtp.Source { return &smtp.Source{ Auth: form.SMTPAuth, - Addr: form.SMTPAddr, + Host: form.SMTPHost, Port: form.SMTPPort, AllowedDomains: form.AllowedDomains, ForceSMTPS: form.ForceSMTPS, diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 614d3d4f662bb..792eec8d5680c 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" - system_module "code.gitea.io/gitea/modules/system" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/mailer" @@ -203,7 +202,11 @@ func ChangeConfig(ctx *context.Context) { value := ctx.FormString("value") version := ctx.FormInt("version") - if err := system_module.SetSetting(key, value, version); err != nil { + if err := system_model.SetSetting(&system_model.Setting{ + SettingKey: key, + SettingValue: value, + Version: version, + }); err != nil { log.Error("set setting failed: %v", err) ctx.JSON(http.StatusOK, map[string]string{ "err": ctx.Tr("admin.config.set_setting_failed", key), diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 0f8128946c940..2919fd351366d 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -82,19 +82,12 @@ func AutoSignIn(ctx *context.Context) (bool, error) { isSucceed = true - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - return false, fmt.Errorf("unable to RegenerateSession: Error: %w", err) - } - - // Set session IDs - if err := ctx.Session.Set("uid", u.ID); err != nil { - return false, err - } - if err := ctx.Session.Set("uname", u.Name); err != nil { - return false, err - } - if err := ctx.Session.Release(); err != nil { - return false, err + if err := updateSession(ctx, nil, map[string]interface{}{ + // Set session IDs + "uid": u.ID, + "uname": u.Name, + }); err != nil { + return false, fmt.Errorf("unable to updateSession: %w", err) } if err := resetLocale(ctx, u); err != nil { @@ -252,32 +245,17 @@ func SignInPost(ctx *context.Context) { return } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("UserSignIn: Unable to set regenerate session", err) - return - } - - // User will need to use 2FA TOTP or WebAuthn, save data - if err := ctx.Session.Set("twofaUid", u.ID); err != nil { - ctx.ServerError("UserSignIn: Unable to set twofaUid in session", err) - return - } - - if err := ctx.Session.Set("twofaRemember", form.Remember); err != nil { - ctx.ServerError("UserSignIn: Unable to set twofaRemember in session", err) - return + updates := map[string]interface{}{ + // User will need to use 2FA TOTP or WebAuthn, save data + "twofaUid": u.ID, + "twofaRemember": form.Remember, } - if hasTOTPtwofa { // User will need to use WebAuthn, save data - if err := ctx.Session.Set("totpEnrolled", u.ID); err != nil { - ctx.ServerError("UserSignIn: Unable to set WebAuthn Enrolled in session", err) - return - } + updates["totpEnrolled"] = u.ID } - - if err := ctx.Session.Release(); err != nil { - ctx.ServerError("UserSignIn: Unable to save session", err) + if err := updateSession(ctx, nil, updates); err != nil { + ctx.ServerError("UserSignIn: Unable to update session", err) return } @@ -308,29 +286,23 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe setting.CookieRememberName, u.Name, days) } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + if err := updateSession(ctx, []string{ + // Delete the openid, 2fa and linkaccount data + "openid_verified_uri", + "openid_signin_remember", + "openid_determined_email", + "openid_determined_username", + "twofaUid", + "twofaRemember", + "linkAccount", + }, map[string]interface{}{ + "uid": u.ID, + "uname": u.Name, + }); err != nil { ctx.ServerError("RegenerateSession", err) return setting.AppSubURL + "/" } - // Delete the openid, 2fa and linkaccount data - _ = ctx.Session.Delete("openid_verified_uri") - _ = ctx.Session.Delete("openid_signin_remember") - _ = ctx.Session.Delete("openid_determined_email") - _ = ctx.Session.Delete("openid_determined_username") - _ = ctx.Session.Delete("twofaUid") - _ = ctx.Session.Delete("twofaRemember") - _ = ctx.Session.Delete("linkAccount") - if err := ctx.Session.Set("uid", u.ID); err != nil { - log.Error("Error setting uid %d in session: %v", u.ID, err) - } - if err := ctx.Session.Set("uname", u.Name); err != nil { - log.Error("Error setting uname %s session: %v", u.Name, err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Unable to store session: %v", err) - } - // Language setting of the user overwrites the one previously set // If the user does not have a locale set, we save the current one. if len(u.Language) == 0 { @@ -762,22 +734,15 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) { log.Trace("User activated: %s", user.Name) - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + if err := updateSession(ctx, nil, map[string]interface{}{ + "uid": user.ID, + "uname": user.Name, + }); err != nil { log.Error("Unable to regenerate session for user: %-v with email: %s: %v", user, user.Email, err) ctx.ServerError("ActivateUserEmail", err) return } - if err := ctx.Session.Set("uid", user.ID); err != nil { - log.Error("Error setting uid in session[%s]: %v", ctx.Session.ID(), err) - } - if err := ctx.Session.Set("uname", user.Name); err != nil { - log.Error("Error setting uname in session[%s]: %v", ctx.Session.ID(), err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session[%s]: %v", ctx.Session.ID(), err) - } - if err := resetLocale(ctx, user); err != nil { ctx.ServerError("resetLocale", err) return @@ -821,3 +786,25 @@ func ActivateEmail(ctx *context.Context) { // Should users be logged in automatically here? (consider 2FA requirements, etc.) ctx.Redirect(setting.AppSubURL + "/user/settings/account") } + +func updateSession(ctx *context.Context, deletes []string, updates map[string]interface{}) error { + if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + return fmt.Errorf("regenerate session: %w", err) + } + sess := ctx.Session + sessID := sess.ID() + for _, k := range deletes { + if err := sess.Delete(k); err != nil { + return fmt.Errorf("delete %v in session[%s]: %w", k, sessID, err) + } + } + for k, v := range updates { + if err := sess.Set(k, v); err != nil { + return fmt.Errorf("set %v in session[%s]: %w", k, sessID, err) + } + } + if err := sess.Release(); err != nil { + return fmt.Errorf("store session[%s]: %w", sessID, err) + } + return nil +} diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 4f3f2062b6896..d3211eaa5c70a 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -18,7 +18,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/recaptcha" - "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" auth_service "code.gitea.io/gitea/services/auth" @@ -156,25 +155,16 @@ func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, r return } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { + if err := updateSession(ctx, nil, map[string]interface{}{ + // User needs to use 2FA, save data and redirect to 2FA page. + "twofaUid": u.ID, + "twofaRemember": remember, + "linkAccount": true, + }); err != nil { ctx.ServerError("RegenerateSession", err) return } - // User needs to use 2FA, save data and redirect to 2FA page. - if err := ctx.Session.Set("twofaUid", u.ID); err != nil { - log.Error("Error setting twofaUid in session: %v", err) - } - if err := ctx.Session.Set("twofaRemember", remember); err != nil { - log.Error("Error setting twofaRemember in session: %v", err) - } - if err := ctx.Session.Set("linkAccount", true); err != nil { - log.Error("Error setting linkAccount in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } - // If WebAuthn is enrolled -> Redirect to WebAuthn instead regs, err := auth.GetWebAuthnCredentialsByUID(u.ID) if err == nil && len(regs) > 0 { diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 4fba8d8e8c31a..d845f21a33012 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -22,7 +22,6 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -1027,17 +1026,12 @@ func setUserGroupClaims(loginSource *auth.Source, u *user_model.User, gothUser * } func showLinkingLogin(ctx *context.Context, gothUser goth.User) { - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + "linkAccountGothUser": gothUser, + }); err != nil { + ctx.ServerError("updateSession", err) return } - - if err := ctx.Session.Set("linkAccountGothUser", gothUser); err != nil { - log.Error("Error setting linkAccountGothUser in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } ctx.Redirect(setting.AppSubURL + "/user/link_account") } @@ -1075,21 +1069,14 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model // If this user is enrolled in 2FA and this source doesn't override it, // we can't sign the user in just yet. Instead, redirect them to the 2FA authentication page. if !needs2FA { - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + "uid": u.ID, + "uname": u.Name, + }); err != nil { + ctx.ServerError("updateSession", err) return } - if err := ctx.Session.Set("uid", u.ID); err != nil { - log.Error("Error setting uid in session: %v", err) - } - if err := ctx.Session.Set("uname", u.Name); err != nil { - log.Error("Error setting uname in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } - // Clear whatever CSRF cookie has right now, force to generate a new one middleware.DeleteCSRFCookie(ctx.Resp) @@ -1138,22 +1125,15 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model } } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + // User needs to use 2FA, save data and redirect to 2FA page. + "twofaUid": u.ID, + "twofaRemember": false, + }); err != nil { + ctx.ServerError("updateSession", err) return } - // User needs to use 2FA, save data and redirect to 2FA page. - if err := ctx.Session.Set("twofaUid", u.ID); err != nil { - log.Error("Error setting twofaUid in session: %v", err) - } - if err := ctx.Session.Set("twofaRemember", false); err != nil { - log.Error("Error setting twofaRemember in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("Error storing session: %v", err) - } - // If WebAuthn is enrolled -> Redirect to WebAuthn instead regs, err := auth.GetWebAuthnCredentialsByUID(u.ID) if err == nil && len(regs) > 0 { diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 3b1065189d9dc..d34f4db7c0144 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/recaptcha" - "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -232,27 +231,16 @@ func signInOpenIDVerify(ctx *context.Context) { } } - if _, err := session.RegenerateSession(ctx.Resp, ctx.Req); err != nil { - ctx.ServerError("RegenerateSession", err) - return - } - - if err := ctx.Session.Set("openid_verified_uri", id); err != nil { - log.Error("signInOpenIDVerify: Could not set openid_verified_uri in session: %v", err) - } - if err := ctx.Session.Set("openid_determined_email", email); err != nil { - log.Error("signInOpenIDVerify: Could not set openid_determined_email in session: %v", err) - } - if u != nil { nickname = u.LowerName } - - if err := ctx.Session.Set("openid_determined_username", nickname); err != nil { - log.Error("signInOpenIDVerify: Could not set openid_determined_username in session: %v", err) - } - if err := ctx.Session.Release(); err != nil { - log.Error("signInOpenIDVerify: Unable to save changes to the session: %v", err) + if err := updateSession(ctx, nil, map[string]interface{}{ + "openid_verified_uri": id, + "openid_determined_email": email, + "openid_determined_username": nickname, + }); err != nil { + ctx.ServerError("updateSession", err) + return } if u != nil || !setting.Service.EnableOpenIDSignUp || setting.Service.AllowOnlyInternalRegistration { diff --git a/services/auth/source/smtp/auth.go b/services/auth/source/smtp/auth.go index 487c049722e37..e8453fde69051 100644 --- a/services/auth/source/smtp/auth.go +++ b/services/auth/source/smtp/auth.go @@ -58,10 +58,10 @@ var ErrUnsupportedLoginType = errors.New("Login source is unknown") func Authenticate(a smtp.Auth, source *Source) error { tlsConfig := &tls.Config{ InsecureSkipVerify: source.SkipVerify, - ServerName: source.Addr, + ServerName: source.Host, } - conn, err := net.Dial("tcp", net.JoinHostPort(source.Addr, strconv.Itoa(source.Port))) + conn, err := net.Dial("tcp", net.JoinHostPort(source.Host, strconv.Itoa(source.Port))) if err != nil { return err } @@ -71,7 +71,7 @@ func Authenticate(a smtp.Auth, source *Source) error { conn = tls.Client(conn, tlsConfig) } - client, err := smtp.NewClient(conn, source.Addr) + client, err := smtp.NewClient(conn, source.Host) if err != nil { return fmt.Errorf("failed to create NewClient: %w", err) } diff --git a/services/auth/source/smtp/source.go b/services/auth/source/smtp/source.go index b2286d42a0ff7..5e69f912da35b 100644 --- a/services/auth/source/smtp/source.go +++ b/services/auth/source/smtp/source.go @@ -19,7 +19,7 @@ import ( // Source holds configuration for the SMTP login source. type Source struct { Auth string - Addr string + Host string Port int AllowedDomains string `xorm:"TEXT"` ForceSMTPS bool diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go index 63fd3e55110b7..dff24d494ee0f 100644 --- a/services/auth/source/smtp/source_authenticate.go +++ b/services/auth/source/smtp/source_authenticate.go @@ -32,7 +32,7 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str var auth smtp.Auth switch source.Auth { case PlainAuthentication: - auth = smtp.PlainAuth("", userName, password, source.Addr) + auth = smtp.PlainAuth("", userName, password, source.Host) case LoginAuthentication: auth = &loginAuthenticator{userName, password} case CRAMMD5Authentication: diff --git a/services/forms/auth_form.go b/services/forms/auth_form.go index 9064be2cca38e..7e7c75675299b 100644 --- a/services/forms/auth_form.go +++ b/services/forms/auth_form.go @@ -45,7 +45,7 @@ type AuthenticationForm struct { IsActive bool IsSyncEnabled bool SMTPAuth string - SMTPAddr string + SMTPHost string SMTPPort int AllowedDomains string SecurityProtocol int `binding:"Range(0,2)"`