mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Implement ghost comment mitigation (#14349)
* Implement ghost comment mitigation Adds a config option USER_DELETE_WITH_COMMENTS_MAX_DAYS to the [service] section. See https://codeberg.org/Codeberg/Discussion/issues/24 for the underlying issue. * cleanup * use setting module correctly * add to docs Co-authored-by: Moritz Marquardt <git@momar.de>
This commit is contained in:
		@@ -688,6 +688,9 @@ AUTO_WATCH_NEW_REPOS = true
 | 
				
			|||||||
; Default value for AutoWatchOnChanges
 | 
					; Default value for AutoWatchOnChanges
 | 
				
			||||||
; Make the user watch a repository When they commit for the first time
 | 
					; Make the user watch a repository When they commit for the first time
 | 
				
			||||||
AUTO_WATCH_ON_CHANGES = false
 | 
					AUTO_WATCH_ON_CHANGES = false
 | 
				
			||||||
 | 
					; Default value for the minimum age a user has to exist before deletion to keep issue comments.
 | 
				
			||||||
 | 
					; If a user deletes his account before that amount of days, his comments will be deleted as well.
 | 
				
			||||||
 | 
					USER_DELETE_WITH_COMMENTS_MAX_DAYS = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[webhook]
 | 
					[webhook]
 | 
				
			||||||
; Hook task queue length, increase if webhook shooting starts hanging
 | 
					; Hook task queue length, increase if webhook shooting starts hanging
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -474,6 +474,7 @@ relation to port exhaustion.
 | 
				
			|||||||
- `ALLOW_ONLY_EXTERNAL_REGISTRATION`: **false** Set to true to force registration only using third-party services.
 | 
					- `ALLOW_ONLY_EXTERNAL_REGISTRATION`: **false** Set to true to force registration only using third-party services.
 | 
				
			||||||
- `NO_REPLY_ADDRESS`: **DOMAIN** Default value for the domain part of the user's email address in the git log if he has set KeepEmailPrivate to true.
 | 
					- `NO_REPLY_ADDRESS`: **DOMAIN** Default value for the domain part of the user's email address in the git log if he has set KeepEmailPrivate to true.
 | 
				
			||||||
  The user's email will be replaced with a concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS.
 | 
					  The user's email will be replaced with a concatenation of the user name in lower case, "@" and NO_REPLY_ADDRESS.
 | 
				
			||||||
 | 
					- `USER_DELETE_WITH_COMMENTS_MAX_DAYS`: **0** If a user deletes his account before that amount of days, his comments will be deleted as well.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## SSH Minimum Key Sizes (`ssh.minimum_key_sizes`)
 | 
					## SSH Minimum Key Sizes (`ssh.minimum_key_sizes`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1151,6 +1151,15 @@ func deleteUser(e *xorm.Session, u *User) error {
 | 
				
			|||||||
		return fmt.Errorf("deleteBeans: %v", err)
 | 
							return fmt.Errorf("deleteBeans: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if setting.Service.UserDeleteWithCommentsMaxDays != 0 &&
 | 
				
			||||||
 | 
							u.CreatedUnix.AsTime().Add(time.Duration(setting.Service.UserDeleteWithCommentsMaxDays)*24*time.Hour).After(time.Now()) {
 | 
				
			||||||
 | 
							if err = deleteBeans(e,
 | 
				
			||||||
 | 
								&Comment{PosterID: u.ID},
 | 
				
			||||||
 | 
							); err != nil {
 | 
				
			||||||
 | 
								return fmt.Errorf("deleteBeans: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ***** START: PublicKey *****
 | 
						// ***** START: PublicKey *****
 | 
				
			||||||
	if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil {
 | 
						if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil {
 | 
				
			||||||
		return fmt.Errorf("deletePublicKeys: %v", err)
 | 
							return fmt.Errorf("deletePublicKeys: %v", err)
 | 
				
			||||||
@@ -1205,7 +1214,8 @@ func deleteUser(e *xorm.Session, u *User) error {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DeleteUser completely and permanently deletes everything of a user,
 | 
					// DeleteUser completely and permanently deletes everything of a user,
 | 
				
			||||||
// but issues/comments/pulls will be kept and shown as someone has been deleted.
 | 
					// but issues/comments/pulls will be kept and shown as someone has been deleted,
 | 
				
			||||||
 | 
					// unless the user is younger than USER_DELETE_WITH_COMMENTS_MAX_DAYS.
 | 
				
			||||||
func DeleteUser(u *User) (err error) {
 | 
					func DeleteUser(u *User) (err error) {
 | 
				
			||||||
	if u.IsOrganization() {
 | 
						if u.IsOrganization() {
 | 
				
			||||||
		return fmt.Errorf("%s is an organization not a user", u.Name)
 | 
							return fmt.Errorf("%s is an organization not a user", u.Name)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,7 @@ var Service struct {
 | 
				
			|||||||
	AutoWatchNewRepos                       bool
 | 
						AutoWatchNewRepos                       bool
 | 
				
			||||||
	AutoWatchOnChanges                      bool
 | 
						AutoWatchOnChanges                      bool
 | 
				
			||||||
	DefaultOrgMemberVisible                 bool
 | 
						DefaultOrgMemberVisible                 bool
 | 
				
			||||||
 | 
						UserDeleteWithCommentsMaxDays           int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// OpenID settings
 | 
						// OpenID settings
 | 
				
			||||||
	EnableOpenIDSignIn bool
 | 
						EnableOpenIDSignIn bool
 | 
				
			||||||
@@ -102,6 +103,7 @@ func newService() {
 | 
				
			|||||||
	Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes))
 | 
						Service.DefaultOrgVisibility = sec.Key("DEFAULT_ORG_VISIBILITY").In("public", structs.ExtractKeysFromMapString(structs.VisibilityModes))
 | 
				
			||||||
	Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility]
 | 
						Service.DefaultOrgVisibilityMode = structs.VisibilityModes[Service.DefaultOrgVisibility]
 | 
				
			||||||
	Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool()
 | 
						Service.DefaultOrgMemberVisible = sec.Key("DEFAULT_ORG_MEMBER_VISIBLE").MustBool()
 | 
				
			||||||
 | 
						Service.UserDeleteWithCommentsMaxDays = sec.Key("USER_DELETE_WITH_COMMENTS_MAX_DAYS").MustInt(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sec = Cfg.Section("openid")
 | 
						sec = Cfg.Section("openid")
 | 
				
			||||||
	Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock)
 | 
						Service.EnableOpenIDSignIn = sec.Key("ENABLE_OPENID_SIGNIN").MustBool(!InstallLock)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -646,6 +646,7 @@ repos_none = You do not own any repositories
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
delete_account = Delete Your Account
 | 
					delete_account = Delete Your Account
 | 
				
			||||||
delete_prompt = This operation will permanently delete your user account. It <strong>CAN NOT</strong> be undone.
 | 
					delete_prompt = This operation will permanently delete your user account. It <strong>CAN NOT</strong> be undone.
 | 
				
			||||||
 | 
					delete_with_all_comments = Your account is younger than %d days. To avoid ghost comments, all issue/PR comments will be deleted with it.
 | 
				
			||||||
confirm_delete_account = Confirm Deletion
 | 
					confirm_delete_account = Confirm Deletion
 | 
				
			||||||
delete_account_title = Delete User Account
 | 
					delete_account_title = Delete User Account
 | 
				
			||||||
delete_account_desc = Are you sure you want to permanently delete this user account?
 | 
					delete_account_desc = Are you sure you want to permanently delete this user account?
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ package setting
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/auth"
 | 
						"code.gitea.io/gitea/modules/auth"
 | 
				
			||||||
@@ -300,4 +301,9 @@ func loadAccountData(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["EmailNotificationsPreference"] = ctx.User.EmailNotifications()
 | 
						ctx.Data["EmailNotificationsPreference"] = ctx.User.EmailNotifications()
 | 
				
			||||||
	ctx.Data["ActivationsPending"] = pendingActivation
 | 
						ctx.Data["ActivationsPending"] = pendingActivation
 | 
				
			||||||
	ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
 | 
						ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if setting.Service.UserDeleteWithCommentsMaxDays != 0 {
 | 
				
			||||||
 | 
							ctx.Data["UserDeleteWithCommentsMaxDays"] = setting.Service.UserDeleteWithCommentsMaxDays
 | 
				
			||||||
 | 
							ctx.Data["UserDeleteWithComments"] = ctx.User.CreatedUnix.AsTime().Add(time.Duration(setting.Service.UserDeleteWithCommentsMaxDays) * 24 * time.Hour).After(time.Now())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -173,6 +173,9 @@
 | 
				
			|||||||
		<div class="ui attached error segment">
 | 
							<div class="ui attached error segment">
 | 
				
			||||||
			<div class="ui red message">
 | 
								<div class="ui red message">
 | 
				
			||||||
				<p class="text left">{{svg "octicon-alert"}} {{.i18n.Tr "settings.delete_prompt" | Str2html}}</p>
 | 
									<p class="text left">{{svg "octicon-alert"}} {{.i18n.Tr "settings.delete_prompt" | Str2html}}</p>
 | 
				
			||||||
 | 
									{{ if .UserDeleteWithComments }}
 | 
				
			||||||
 | 
									<p class="text left" style="font-weight: bold;">{{.i18n.Tr "settings.delete_with_all_comments" .UserDeleteWithCommentsMaxDays | Str2html}}</p>
 | 
				
			||||||
 | 
									{{ end }}
 | 
				
			||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			<form class="ui form ignore-dirty" id="delete-form" action="{{AppSubUrl}}/user/settings/account/delete" method="post">
 | 
								<form class="ui form ignore-dirty" id="delete-form" action="{{AppSubUrl}}/user/settings/account/delete" method="post">
 | 
				
			||||||
				{{.CsrfTokenHtml}}
 | 
									{{.CsrfTokenHtml}}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user