From 91b21473a6964dd1ab5f8b7ae969d9fb1adbe6e1 Mon Sep 17 00:00:00 2001
From: Gusted <williamzijl7@hotmail.com>
Date: Tue, 28 Jun 2022 01:45:50 +0200
Subject: [PATCH] Add username check to doctor (#20140)

* Add username check to doctor

- Add a new breaking change detector to Gitea's doctor, which checks if
all users still have a valid username according to Gitea. Given from
time-to-time we need to make changes, either due to new routes or due to
security, it's for a instance's admin to check if all users still have a
valid username.

* Fix extra argument

* Apply suggestions from code review

Co-authored-by: Jimmy Praet <jimmy.praet@telenet.be>

* Apply suggestions from code review

Co-authored-by: delvh <dev.lh@web.de>

Co-authored-by: Jimmy Praet <jimmy.praet@telenet.be>
Co-authored-by: John Olheiser <john.olheiser@gmail.com>
Co-authored-by: techknowlogick <matti@mdranta.net>
Co-authored-by: delvh <dev.lh@web.de>
---
 modules/doctor/breaking.go | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/modules/doctor/breaking.go b/modules/doctor/breaking.go
index c4b58d20fb..3e01d97d7c 100644
--- a/modules/doctor/breaking.go
+++ b/modules/doctor/breaking.go
@@ -58,6 +58,29 @@ func checkUserEmail(ctx context.Context, logger log.Logger, _ bool) error {
 	return nil
 }
 
+// From time to time Gitea makes changes to the reserved usernames and which symbols
+// are allowed for various reasons. This check helps with detecting users that, according
+// to our reserved names, don't have a valid username.
+func checkUserName(ctx context.Context, logger log.Logger, _ bool) error {
+	var invalidUserCount int64
+	if err := iterateUserAccounts(ctx, func(u *user.User) error {
+		if err := user.IsUsableUsername(u.Name); err != nil {
+			invalidUserCount++
+			logger.Warn("User[id=%d] does not have a valid username: %v", u.ID, err)
+		}
+		return nil
+	}); err != nil {
+		return fmt.Errorf("iterateUserAccounts: %v", err)
+	}
+
+	if invalidUserCount == 0 {
+		logger.Info("All users have a valid username.")
+	} else {
+		logger.Warn("%d user(s) have a non-valid username.", invalidUserCount)
+	}
+	return nil
+}
+
 func init() {
 	Register(&Check{
 		Title:     "Check if users has an valid email address",
@@ -66,4 +89,11 @@ func init() {
 		Run:       checkUserEmail,
 		Priority:  9,
 	})
+	Register(&Check{
+		Title:     "Check if users have a valid username",
+		Name:      "check-user-names",
+		IsDefault: false,
+		Run:       checkUserName,
+		Priority:  9,
+	})
 }