You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

users.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2020 The Gitea Authors.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package admin
  6. import (
  7. "fmt"
  8. "net/http"
  9. "strconv"
  10. "strings"
  11. "code.gitea.io/gitea/models"
  12. "code.gitea.io/gitea/modules/base"
  13. "code.gitea.io/gitea/modules/context"
  14. auth "code.gitea.io/gitea/modules/forms"
  15. "code.gitea.io/gitea/modules/log"
  16. "code.gitea.io/gitea/modules/password"
  17. "code.gitea.io/gitea/modules/setting"
  18. "code.gitea.io/gitea/modules/web"
  19. "code.gitea.io/gitea/routers"
  20. router_user_setting "code.gitea.io/gitea/routers/user/setting"
  21. "code.gitea.io/gitea/services/mailer"
  22. )
  23. const (
  24. tplUsers base.TplName = "admin/user/list"
  25. tplUserNew base.TplName = "admin/user/new"
  26. tplUserEdit base.TplName = "admin/user/edit"
  27. )
  28. // Users show all the users
  29. func Users(ctx *context.Context) {
  30. ctx.Data["Title"] = ctx.Tr("admin.users")
  31. ctx.Data["PageIsAdmin"] = true
  32. ctx.Data["PageIsAdminUsers"] = true
  33. routers.RenderUserSearch(ctx, &models.SearchUserOptions{
  34. Type: models.UserTypeIndividual,
  35. ListOptions: models.ListOptions{
  36. PageSize: setting.UI.Admin.UserPagingNum,
  37. },
  38. SearchByEmail: true,
  39. }, tplUsers)
  40. }
  41. // NewUser render adding a new user page
  42. func NewUser(ctx *context.Context) {
  43. ctx.Data["Title"] = ctx.Tr("admin.users.new_account")
  44. ctx.Data["PageIsAdmin"] = true
  45. ctx.Data["PageIsAdminUsers"] = true
  46. ctx.Data["login_type"] = "0-0"
  47. sources, err := models.LoginSources()
  48. if err != nil {
  49. ctx.ServerError("LoginSources", err)
  50. return
  51. }
  52. ctx.Data["Sources"] = sources
  53. ctx.Data["CanSendEmail"] = setting.MailService != nil
  54. ctx.HTML(http.StatusOK, tplUserNew)
  55. }
  56. // NewUserPost response for adding a new user
  57. func NewUserPost(ctx *context.Context) {
  58. form := web.GetForm(ctx).(*auth.AdminCreateUserForm)
  59. ctx.Data["Title"] = ctx.Tr("admin.users.new_account")
  60. ctx.Data["PageIsAdmin"] = true
  61. ctx.Data["PageIsAdminUsers"] = true
  62. sources, err := models.LoginSources()
  63. if err != nil {
  64. ctx.ServerError("LoginSources", err)
  65. return
  66. }
  67. ctx.Data["Sources"] = sources
  68. ctx.Data["CanSendEmail"] = setting.MailService != nil
  69. if ctx.HasError() {
  70. ctx.HTML(http.StatusOK, tplUserNew)
  71. return
  72. }
  73. u := &models.User{
  74. Name: form.UserName,
  75. Email: form.Email,
  76. Passwd: form.Password,
  77. IsActive: true,
  78. LoginType: models.LoginPlain,
  79. }
  80. if len(form.LoginType) > 0 {
  81. fields := strings.Split(form.LoginType, "-")
  82. if len(fields) == 2 {
  83. lType, _ := strconv.ParseInt(fields[0], 10, 0)
  84. u.LoginType = models.LoginType(lType)
  85. u.LoginSource, _ = strconv.ParseInt(fields[1], 10, 64)
  86. u.LoginName = form.LoginName
  87. }
  88. }
  89. if u.LoginType == models.LoginNoType || u.LoginType == models.LoginPlain {
  90. if len(form.Password) < setting.MinPasswordLength {
  91. ctx.Data["Err_Password"] = true
  92. ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserNew, &form)
  93. return
  94. }
  95. if !password.IsComplexEnough(form.Password) {
  96. ctx.Data["Err_Password"] = true
  97. ctx.RenderWithErr(password.BuildComplexityError(ctx), tplUserNew, &form)
  98. return
  99. }
  100. pwned, err := password.IsPwned(ctx.Req.Context(), form.Password)
  101. if pwned {
  102. ctx.Data["Err_Password"] = true
  103. errMsg := ctx.Tr("auth.password_pwned")
  104. if err != nil {
  105. log.Error(err.Error())
  106. errMsg = ctx.Tr("auth.password_pwned_err")
  107. }
  108. ctx.RenderWithErr(errMsg, tplUserNew, &form)
  109. return
  110. }
  111. u.MustChangePassword = form.MustChangePassword
  112. }
  113. if err := models.CreateUser(u); err != nil {
  114. switch {
  115. case models.IsErrUserAlreadyExist(err):
  116. ctx.Data["Err_UserName"] = true
  117. ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplUserNew, &form)
  118. case models.IsErrEmailAlreadyUsed(err):
  119. ctx.Data["Err_Email"] = true
  120. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form)
  121. case models.IsErrEmailInvalid(err):
  122. ctx.Data["Err_Email"] = true
  123. ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
  124. case models.IsErrNameReserved(err):
  125. ctx.Data["Err_UserName"] = true
  126. ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), tplUserNew, &form)
  127. case models.IsErrNamePatternNotAllowed(err):
  128. ctx.Data["Err_UserName"] = true
  129. ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tplUserNew, &form)
  130. case models.IsErrNameCharsNotAllowed(err):
  131. ctx.Data["Err_UserName"] = true
  132. ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(models.ErrNameCharsNotAllowed).Name), tplUserNew, &form)
  133. default:
  134. ctx.ServerError("CreateUser", err)
  135. }
  136. return
  137. }
  138. log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)
  139. // Send email notification.
  140. if form.SendNotify {
  141. mailer.SendRegisterNotifyMail(u)
  142. }
  143. ctx.Flash.Success(ctx.Tr("admin.users.new_success", u.Name))
  144. ctx.Redirect(setting.AppSubURL + "/admin/users/" + fmt.Sprint(u.ID))
  145. }
  146. func prepareUserInfo(ctx *context.Context) *models.User {
  147. u, err := models.GetUserByID(ctx.ParamsInt64(":userid"))
  148. if err != nil {
  149. ctx.ServerError("GetUserByID", err)
  150. return nil
  151. }
  152. ctx.Data["User"] = u
  153. if u.LoginSource > 0 {
  154. ctx.Data["LoginSource"], err = models.GetLoginSourceByID(u.LoginSource)
  155. if err != nil {
  156. ctx.ServerError("GetLoginSourceByID", err)
  157. return nil
  158. }
  159. } else {
  160. ctx.Data["LoginSource"] = &models.LoginSource{}
  161. }
  162. sources, err := models.LoginSources()
  163. if err != nil {
  164. ctx.ServerError("LoginSources", err)
  165. return nil
  166. }
  167. ctx.Data["Sources"] = sources
  168. ctx.Data["TwoFactorEnabled"] = true
  169. _, err = models.GetTwoFactorByUID(u.ID)
  170. if err != nil {
  171. if !models.IsErrTwoFactorNotEnrolled(err) {
  172. ctx.ServerError("IsErrTwoFactorNotEnrolled", err)
  173. return nil
  174. }
  175. ctx.Data["TwoFactorEnabled"] = false
  176. }
  177. return u
  178. }
  179. // EditUser show editting user page
  180. func EditUser(ctx *context.Context) {
  181. ctx.Data["Title"] = ctx.Tr("admin.users.edit_account")
  182. ctx.Data["PageIsAdmin"] = true
  183. ctx.Data["PageIsAdminUsers"] = true
  184. ctx.Data["DisableRegularOrgCreation"] = setting.Admin.DisableRegularOrgCreation
  185. ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
  186. prepareUserInfo(ctx)
  187. if ctx.Written() {
  188. return
  189. }
  190. ctx.HTML(http.StatusOK, tplUserEdit)
  191. }
  192. // EditUserPost response for editting user
  193. func EditUserPost(ctx *context.Context) {
  194. form := web.GetForm(ctx).(*auth.AdminEditUserForm)
  195. ctx.Data["Title"] = ctx.Tr("admin.users.edit_account")
  196. ctx.Data["PageIsAdmin"] = true
  197. ctx.Data["PageIsAdminUsers"] = true
  198. ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
  199. u := prepareUserInfo(ctx)
  200. if ctx.Written() {
  201. return
  202. }
  203. if ctx.HasError() {
  204. ctx.HTML(http.StatusOK, tplUserEdit)
  205. return
  206. }
  207. fields := strings.Split(form.LoginType, "-")
  208. if len(fields) == 2 {
  209. loginType, _ := strconv.ParseInt(fields[0], 10, 0)
  210. loginSource, _ := strconv.ParseInt(fields[1], 10, 64)
  211. if u.LoginSource != loginSource {
  212. u.LoginSource = loginSource
  213. u.LoginType = models.LoginType(loginType)
  214. }
  215. }
  216. if len(form.Password) > 0 && (u.IsLocal() || u.IsOAuth2()) {
  217. var err error
  218. if len(form.Password) < setting.MinPasswordLength {
  219. ctx.Data["Err_Password"] = true
  220. ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserEdit, &form)
  221. return
  222. }
  223. if !password.IsComplexEnough(form.Password) {
  224. ctx.RenderWithErr(password.BuildComplexityError(ctx), tplUserEdit, &form)
  225. return
  226. }
  227. pwned, err := password.IsPwned(ctx.Req.Context(), form.Password)
  228. if pwned {
  229. ctx.Data["Err_Password"] = true
  230. errMsg := ctx.Tr("auth.password_pwned")
  231. if err != nil {
  232. log.Error(err.Error())
  233. errMsg = ctx.Tr("auth.password_pwned_err")
  234. }
  235. ctx.RenderWithErr(errMsg, tplUserNew, &form)
  236. return
  237. }
  238. if u.Salt, err = models.GetUserSalt(); err != nil {
  239. ctx.ServerError("UpdateUser", err)
  240. return
  241. }
  242. if err = u.SetPassword(form.Password); err != nil {
  243. ctx.ServerError("SetPassword", err)
  244. return
  245. }
  246. }
  247. if len(form.UserName) != 0 && u.Name != form.UserName {
  248. if err := router_user_setting.HandleUsernameChange(ctx, u, form.UserName); err != nil {
  249. ctx.Redirect(setting.AppSubURL + "/admin/users")
  250. return
  251. }
  252. u.Name = form.UserName
  253. u.LowerName = strings.ToLower(form.UserName)
  254. }
  255. if form.Reset2FA {
  256. tf, err := models.GetTwoFactorByUID(u.ID)
  257. if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
  258. ctx.ServerError("GetTwoFactorByUID", err)
  259. return
  260. }
  261. if err = models.DeleteTwoFactorByID(tf.ID, u.ID); err != nil {
  262. ctx.ServerError("DeleteTwoFactorByID", err)
  263. return
  264. }
  265. }
  266. u.LoginName = form.LoginName
  267. u.FullName = form.FullName
  268. u.Email = form.Email
  269. u.Website = form.Website
  270. u.Location = form.Location
  271. u.MaxRepoCreation = form.MaxRepoCreation
  272. u.IsActive = form.Active
  273. u.IsAdmin = form.Admin
  274. u.IsRestricted = form.Restricted
  275. u.AllowGitHook = form.AllowGitHook
  276. u.AllowImportLocal = form.AllowImportLocal
  277. u.AllowCreateOrganization = form.AllowCreateOrganization
  278. // skip self Prohibit Login
  279. if ctx.User.ID == u.ID {
  280. u.ProhibitLogin = false
  281. } else {
  282. u.ProhibitLogin = form.ProhibitLogin
  283. }
  284. if err := models.UpdateUser(u); err != nil {
  285. if models.IsErrEmailAlreadyUsed(err) {
  286. ctx.Data["Err_Email"] = true
  287. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
  288. } else if models.IsErrEmailInvalid(err) {
  289. ctx.Data["Err_Email"] = true
  290. ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
  291. } else {
  292. ctx.ServerError("UpdateUser", err)
  293. }
  294. return
  295. }
  296. log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
  297. ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success"))
  298. ctx.Redirect(setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"))
  299. }
  300. // DeleteUser response for deleting a user
  301. func DeleteUser(ctx *context.Context) {
  302. u, err := models.GetUserByID(ctx.ParamsInt64(":userid"))
  303. if err != nil {
  304. ctx.ServerError("GetUserByID", err)
  305. return
  306. }
  307. if err = models.DeleteUser(u); err != nil {
  308. switch {
  309. case models.IsErrUserOwnRepos(err):
  310. ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo"))
  311. ctx.JSON(http.StatusOK, map[string]interface{}{
  312. "redirect": setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"),
  313. })
  314. case models.IsErrUserHasOrgs(err):
  315. ctx.Flash.Error(ctx.Tr("admin.users.still_has_org"))
  316. ctx.JSON(http.StatusOK, map[string]interface{}{
  317. "redirect": setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"),
  318. })
  319. default:
  320. ctx.ServerError("DeleteUser", err)
  321. }
  322. return
  323. }
  324. log.Trace("Account deleted by admin (%s): %s", ctx.User.Name, u.Name)
  325. ctx.Flash.Success(ctx.Tr("admin.users.deletion_success"))
  326. ctx.JSON(http.StatusOK, map[string]interface{}{
  327. "redirect": setting.AppSubURL + "/admin/users",
  328. })
  329. }