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.

setting.go 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package user
  5. import (
  6. "bytes"
  7. "errors"
  8. "fmt"
  9. "io/ioutil"
  10. "strings"
  11. "github.com/Unknwon/com"
  12. "github.com/pquerna/otp"
  13. "github.com/pquerna/otp/totp"
  14. "encoding/base64"
  15. "html/template"
  16. "image/png"
  17. "code.gitea.io/gitea/models"
  18. "code.gitea.io/gitea/modules/auth"
  19. "code.gitea.io/gitea/modules/base"
  20. "code.gitea.io/gitea/modules/context"
  21. "code.gitea.io/gitea/modules/log"
  22. "code.gitea.io/gitea/modules/setting"
  23. )
  24. const (
  25. tplSettingsProfile base.TplName = "user/settings/profile"
  26. tplSettingsAvatar base.TplName = "user/settings/avatar"
  27. tplSettingsPassword base.TplName = "user/settings/password"
  28. tplSettingsEmails base.TplName = "user/settings/email"
  29. tplSettingsKeys base.TplName = "user/settings/keys"
  30. tplSettingsSocial base.TplName = "user/settings/social"
  31. tplSettingsApplications base.TplName = "user/settings/applications"
  32. tplSettingsTwofa base.TplName = "user/settings/twofa"
  33. tplSettingsTwofaEnroll base.TplName = "user/settings/twofa_enroll"
  34. tplSettingsAccountLink base.TplName = "user/settings/account_link"
  35. tplSettingsOrganization base.TplName = "user/settings/organization"
  36. tplSettingsRepositories base.TplName = "user/settings/repos"
  37. tplSettingsDelete base.TplName = "user/settings/delete"
  38. tplSettingsSecurity base.TplName = "user/settings/security"
  39. )
  40. // Settings render user's profile page
  41. func Settings(ctx *context.Context) {
  42. ctx.Data["Title"] = ctx.Tr("settings")
  43. ctx.Data["PageIsSettingsProfile"] = true
  44. ctx.HTML(200, tplSettingsProfile)
  45. }
  46. func handleUsernameChange(ctx *context.Context, newName string) {
  47. // Non-local users are not allowed to change their username.
  48. if len(newName) == 0 || !ctx.User.IsLocal() {
  49. return
  50. }
  51. // Check if user name has been changed
  52. if ctx.User.LowerName != strings.ToLower(newName) {
  53. if err := models.ChangeUserName(ctx.User, newName); err != nil {
  54. switch {
  55. case models.IsErrUserAlreadyExist(err):
  56. ctx.Flash.Error(ctx.Tr("newName_been_taken"))
  57. ctx.Redirect(setting.AppSubURL + "/user/settings")
  58. case models.IsErrEmailAlreadyUsed(err):
  59. ctx.Flash.Error(ctx.Tr("form.email_been_used"))
  60. ctx.Redirect(setting.AppSubURL + "/user/settings")
  61. case models.IsErrNameReserved(err):
  62. ctx.Flash.Error(ctx.Tr("user.newName_reserved"))
  63. ctx.Redirect(setting.AppSubURL + "/user/settings")
  64. case models.IsErrNamePatternNotAllowed(err):
  65. ctx.Flash.Error(ctx.Tr("user.newName_pattern_not_allowed"))
  66. ctx.Redirect(setting.AppSubURL + "/user/settings")
  67. default:
  68. ctx.Handle(500, "ChangeUserName", err)
  69. }
  70. return
  71. }
  72. log.Trace("User name changed: %s -> %s", ctx.User.Name, newName)
  73. }
  74. // In case it's just a case change
  75. ctx.User.Name = newName
  76. ctx.User.LowerName = strings.ToLower(newName)
  77. }
  78. // SettingsPost response for change user's profile
  79. func SettingsPost(ctx *context.Context, form auth.UpdateProfileForm) {
  80. ctx.Data["Title"] = ctx.Tr("settings")
  81. ctx.Data["PageIsSettingsProfile"] = true
  82. if ctx.HasError() {
  83. ctx.HTML(200, tplSettingsProfile)
  84. return
  85. }
  86. handleUsernameChange(ctx, form.Name)
  87. if ctx.Written() {
  88. return
  89. }
  90. ctx.User.FullName = form.FullName
  91. ctx.User.Email = form.Email
  92. ctx.User.KeepEmailPrivate = form.KeepEmailPrivate
  93. ctx.User.Website = form.Website
  94. ctx.User.Location = form.Location
  95. if err := models.UpdateUserSetting(ctx.User); err != nil {
  96. if _, ok := err.(models.ErrEmailAlreadyUsed); ok {
  97. ctx.Flash.Error(ctx.Tr("form.email_been_used"))
  98. ctx.Redirect(setting.AppSubURL + "/user/settings")
  99. return
  100. }
  101. ctx.Handle(500, "UpdateUser", err)
  102. return
  103. }
  104. log.Trace("User settings updated: %s", ctx.User.Name)
  105. ctx.Flash.Success(ctx.Tr("settings.update_profile_success"))
  106. ctx.Redirect(setting.AppSubURL + "/user/settings")
  107. }
  108. // UpdateAvatarSetting update user's avatar
  109. // FIXME: limit size.
  110. func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm, ctxUser *models.User) error {
  111. ctxUser.UseCustomAvatar = form.Source == auth.AvatarLocal
  112. if len(form.Gravatar) > 0 {
  113. ctxUser.Avatar = base.EncodeMD5(form.Gravatar)
  114. ctxUser.AvatarEmail = form.Gravatar
  115. }
  116. if form.Avatar != nil {
  117. fr, err := form.Avatar.Open()
  118. if err != nil {
  119. return fmt.Errorf("Avatar.Open: %v", err)
  120. }
  121. defer fr.Close()
  122. data, err := ioutil.ReadAll(fr)
  123. if err != nil {
  124. return fmt.Errorf("ioutil.ReadAll: %v", err)
  125. }
  126. if !base.IsImageFile(data) {
  127. return errors.New(ctx.Tr("settings.uploaded_avatar_not_a_image"))
  128. }
  129. if err = ctxUser.UploadAvatar(data); err != nil {
  130. return fmt.Errorf("UploadAvatar: %v", err)
  131. }
  132. } else {
  133. // No avatar is uploaded but setting has been changed to enable,
  134. // generate a random one when needed.
  135. if ctxUser.UseCustomAvatar && !com.IsFile(ctxUser.CustomAvatarPath()) {
  136. if err := ctxUser.GenerateRandomAvatar(); err != nil {
  137. log.Error(4, "GenerateRandomAvatar[%d]: %v", ctxUser.ID, err)
  138. }
  139. }
  140. }
  141. if err := models.UpdateUserCols(ctxUser, "avatar", "avatar_email", "use_custom_avatar"); err != nil {
  142. return fmt.Errorf("UpdateUser: %v", err)
  143. }
  144. return nil
  145. }
  146. // SettingsAvatar render user avatar page
  147. func SettingsAvatar(ctx *context.Context) {
  148. ctx.Data["Title"] = ctx.Tr("settings")
  149. ctx.Data["PageIsSettingsAvatar"] = true
  150. ctx.HTML(200, tplSettingsAvatar)
  151. }
  152. // SettingsAvatarPost response for change user's avatar request
  153. func SettingsAvatarPost(ctx *context.Context, form auth.AvatarForm) {
  154. if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil {
  155. ctx.Flash.Error(err.Error())
  156. } else {
  157. ctx.Flash.Success(ctx.Tr("settings.update_avatar_success"))
  158. }
  159. ctx.Redirect(setting.AppSubURL + "/user/settings/avatar")
  160. }
  161. // SettingsDeleteAvatar render delete avatar page
  162. func SettingsDeleteAvatar(ctx *context.Context) {
  163. if err := ctx.User.DeleteAvatar(); err != nil {
  164. ctx.Flash.Error(err.Error())
  165. }
  166. ctx.Redirect(setting.AppSubURL + "/user/settings/avatar")
  167. }
  168. // SettingsSecurity render change user's password page and 2FA
  169. func SettingsSecurity(ctx *context.Context) {
  170. ctx.Data["Title"] = ctx.Tr("settings")
  171. ctx.Data["PageIsSettingsSecurity"] = true
  172. ctx.Data["Email"] = ctx.User.Email
  173. enrolled := true
  174. _, err := models.GetTwoFactorByUID(ctx.User.ID)
  175. if err != nil {
  176. if models.IsErrTwoFactorNotEnrolled(err) {
  177. enrolled = false
  178. } else {
  179. ctx.Handle(500, "SettingsTwoFactor", err)
  180. return
  181. }
  182. }
  183. ctx.Data["TwofaEnrolled"] = enrolled
  184. ctx.HTML(200, tplSettingsSecurity)
  185. }
  186. // SettingsSecurityPost response for change user's password
  187. func SettingsSecurityPost(ctx *context.Context, form auth.ChangePasswordForm) {
  188. ctx.Data["Title"] = ctx.Tr("settings")
  189. ctx.Data["PageIsSettingsSecurity"] = true
  190. ctx.Data["PageIsSettingsDelete"] = true
  191. if ctx.HasError() {
  192. ctx.HTML(200, tplSettingsSecurity)
  193. return
  194. }
  195. if ctx.User.IsPasswordSet() && !ctx.User.ValidatePassword(form.OldPassword) {
  196. ctx.Flash.Error(ctx.Tr("settings.password_incorrect"))
  197. } else if form.Password != form.Retype {
  198. ctx.Flash.Error(ctx.Tr("form.password_not_match"))
  199. } else {
  200. ctx.User.Passwd = form.Password
  201. var err error
  202. if ctx.User.Salt, err = models.GetUserSalt(); err != nil {
  203. ctx.Handle(500, "UpdateUser", err)
  204. return
  205. }
  206. ctx.User.EncodePasswd()
  207. if err := models.UpdateUserCols(ctx.User, "salt", "passwd"); err != nil {
  208. ctx.Handle(500, "UpdateUser", err)
  209. return
  210. }
  211. log.Trace("User password updated: %s", ctx.User.Name)
  212. ctx.Flash.Success(ctx.Tr("settings.change_password_success"))
  213. }
  214. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  215. }
  216. // SettingsEmails render user's emails page
  217. func SettingsEmails(ctx *context.Context) {
  218. ctx.Data["Title"] = ctx.Tr("settings")
  219. ctx.Data["PageIsSettingsEmails"] = true
  220. emails, err := models.GetEmailAddresses(ctx.User.ID)
  221. if err != nil {
  222. ctx.Handle(500, "GetEmailAddresses", err)
  223. return
  224. }
  225. ctx.Data["Emails"] = emails
  226. ctx.HTML(200, tplSettingsEmails)
  227. }
  228. // SettingsEmailPost response for change user's email
  229. func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) {
  230. ctx.Data["Title"] = ctx.Tr("settings")
  231. ctx.Data["PageIsSettingsEmails"] = true
  232. // Make emailaddress primary.
  233. if ctx.Query("_method") == "PRIMARY" {
  234. if err := models.MakeEmailPrimary(&models.EmailAddress{ID: ctx.QueryInt64("id")}); err != nil {
  235. ctx.Handle(500, "MakeEmailPrimary", err)
  236. return
  237. }
  238. log.Trace("Email made primary: %s", ctx.User.Name)
  239. ctx.Redirect(setting.AppSubURL + "/user/settings/email")
  240. return
  241. }
  242. // Add Email address.
  243. emails, err := models.GetEmailAddresses(ctx.User.ID)
  244. if err != nil {
  245. ctx.Handle(500, "GetEmailAddresses", err)
  246. return
  247. }
  248. ctx.Data["Emails"] = emails
  249. if ctx.HasError() {
  250. ctx.HTML(200, tplSettingsEmails)
  251. return
  252. }
  253. email := &models.EmailAddress{
  254. UID: ctx.User.ID,
  255. Email: form.Email,
  256. IsActivated: !setting.Service.RegisterEmailConfirm,
  257. }
  258. if err := models.AddEmailAddress(email); err != nil {
  259. if models.IsErrEmailAlreadyUsed(err) {
  260. ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsEmails, &form)
  261. return
  262. }
  263. ctx.Handle(500, "AddEmailAddress", err)
  264. return
  265. }
  266. // Send confirmation email
  267. if setting.Service.RegisterEmailConfirm {
  268. models.SendActivateEmailMail(ctx.Context, ctx.User, email)
  269. if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
  270. log.Error(4, "Set cache(MailResendLimit) fail: %v", err)
  271. }
  272. ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())))
  273. } else {
  274. ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
  275. }
  276. log.Trace("Email address added: %s", email.Email)
  277. ctx.Redirect(setting.AppSubURL + "/user/settings/email")
  278. }
  279. // DeleteEmail response for delete user's email
  280. func DeleteEmail(ctx *context.Context) {
  281. if err := models.DeleteEmailAddress(&models.EmailAddress{ID: ctx.QueryInt64("id"), UID: ctx.User.ID}); err != nil {
  282. ctx.Handle(500, "DeleteEmail", err)
  283. return
  284. }
  285. log.Trace("Email address deleted: %s", ctx.User.Name)
  286. ctx.Flash.Success(ctx.Tr("settings.email_deletion_success"))
  287. ctx.JSON(200, map[string]interface{}{
  288. "redirect": setting.AppSubURL + "/user/settings/email",
  289. })
  290. }
  291. // SettingsKeys render user's SSH/GPG public keys page
  292. func SettingsKeys(ctx *context.Context) {
  293. ctx.Data["Title"] = ctx.Tr("settings")
  294. ctx.Data["PageIsSettingsKeys"] = true
  295. ctx.Data["DisableSSH"] = setting.SSH.Disabled
  296. keys, err := models.ListPublicKeys(ctx.User.ID)
  297. if err != nil {
  298. ctx.Handle(500, "ListPublicKeys", err)
  299. return
  300. }
  301. ctx.Data["Keys"] = keys
  302. gpgkeys, err := models.ListGPGKeys(ctx.User.ID)
  303. if err != nil {
  304. ctx.Handle(500, "ListGPGKeys", err)
  305. return
  306. }
  307. ctx.Data["GPGKeys"] = gpgkeys
  308. ctx.HTML(200, tplSettingsKeys)
  309. }
  310. // SettingsKeysPost response for change user's SSH/GPG keys
  311. func SettingsKeysPost(ctx *context.Context, form auth.AddKeyForm) {
  312. ctx.Data["Title"] = ctx.Tr("settings")
  313. ctx.Data["PageIsSettingsKeys"] = true
  314. keys, err := models.ListPublicKeys(ctx.User.ID)
  315. if err != nil {
  316. ctx.Handle(500, "ListPublicKeys", err)
  317. return
  318. }
  319. ctx.Data["Keys"] = keys
  320. gpgkeys, err := models.ListGPGKeys(ctx.User.ID)
  321. if err != nil {
  322. ctx.Handle(500, "ListGPGKeys", err)
  323. return
  324. }
  325. ctx.Data["GPGKeys"] = gpgkeys
  326. if ctx.HasError() {
  327. ctx.HTML(200, tplSettingsKeys)
  328. return
  329. }
  330. switch form.Type {
  331. case "gpg":
  332. key, err := models.AddGPGKey(ctx.User.ID, form.Content)
  333. if err != nil {
  334. ctx.Data["HasGPGError"] = true
  335. switch {
  336. case models.IsErrGPGKeyParsing(err):
  337. ctx.Flash.Error(ctx.Tr("form.invalid_gpg_key", err.Error()))
  338. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  339. case models.IsErrGPGKeyIDAlreadyUsed(err):
  340. ctx.Data["Err_Content"] = true
  341. ctx.RenderWithErr(ctx.Tr("settings.gpg_key_id_used"), tplSettingsKeys, &form)
  342. case models.IsErrGPGNoEmailFound(err):
  343. ctx.Data["Err_Content"] = true
  344. ctx.RenderWithErr(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form)
  345. default:
  346. ctx.Handle(500, "AddPublicKey", err)
  347. }
  348. return
  349. }
  350. ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", key.KeyID))
  351. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  352. case "ssh":
  353. content, err := models.CheckPublicKeyString(form.Content)
  354. if err != nil {
  355. if models.IsErrSSHDisabled(err) {
  356. ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
  357. } else if models.IsErrKeyUnableVerify(err) {
  358. ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
  359. } else {
  360. ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
  361. }
  362. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  363. return
  364. }
  365. if _, err = models.AddPublicKey(ctx.User.ID, form.Title, content); err != nil {
  366. ctx.Data["HasSSHError"] = true
  367. switch {
  368. case models.IsErrKeyAlreadyExist(err):
  369. ctx.Data["Err_Content"] = true
  370. ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplSettingsKeys, &form)
  371. case models.IsErrKeyNameAlreadyUsed(err):
  372. ctx.Data["Err_Title"] = true
  373. ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), tplSettingsKeys, &form)
  374. default:
  375. ctx.Handle(500, "AddPublicKey", err)
  376. }
  377. return
  378. }
  379. ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
  380. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  381. default:
  382. ctx.Flash.Warning("Function not implemented")
  383. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  384. }
  385. }
  386. // DeleteKey response for delete user's SSH/GPG key
  387. func DeleteKey(ctx *context.Context) {
  388. switch ctx.Query("type") {
  389. case "gpg":
  390. if err := models.DeleteGPGKey(ctx.User, ctx.QueryInt64("id")); err != nil {
  391. ctx.Flash.Error("DeleteGPGKey: " + err.Error())
  392. } else {
  393. ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success"))
  394. }
  395. case "ssh":
  396. if err := models.DeletePublicKey(ctx.User, ctx.QueryInt64("id")); err != nil {
  397. ctx.Flash.Error("DeletePublicKey: " + err.Error())
  398. } else {
  399. ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success"))
  400. }
  401. default:
  402. ctx.Flash.Warning("Function not implemented")
  403. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  404. }
  405. ctx.JSON(200, map[string]interface{}{
  406. "redirect": setting.AppSubURL + "/user/settings/keys",
  407. })
  408. }
  409. // SettingsApplications render user's access tokens page
  410. func SettingsApplications(ctx *context.Context) {
  411. ctx.Data["Title"] = ctx.Tr("settings")
  412. ctx.Data["PageIsSettingsApplications"] = true
  413. tokens, err := models.ListAccessTokens(ctx.User.ID)
  414. if err != nil {
  415. ctx.Handle(500, "ListAccessTokens", err)
  416. return
  417. }
  418. ctx.Data["Tokens"] = tokens
  419. ctx.HTML(200, tplSettingsApplications)
  420. }
  421. // SettingsApplicationsPost response for add user's access token
  422. func SettingsApplicationsPost(ctx *context.Context, form auth.NewAccessTokenForm) {
  423. ctx.Data["Title"] = ctx.Tr("settings")
  424. ctx.Data["PageIsSettingsApplications"] = true
  425. if ctx.HasError() {
  426. tokens, err := models.ListAccessTokens(ctx.User.ID)
  427. if err != nil {
  428. ctx.Handle(500, "ListAccessTokens", err)
  429. return
  430. }
  431. ctx.Data["Tokens"] = tokens
  432. ctx.HTML(200, tplSettingsApplications)
  433. return
  434. }
  435. t := &models.AccessToken{
  436. UID: ctx.User.ID,
  437. Name: form.Name,
  438. }
  439. if err := models.NewAccessToken(t); err != nil {
  440. ctx.Handle(500, "NewAccessToken", err)
  441. return
  442. }
  443. ctx.Flash.Success(ctx.Tr("settings.generate_token_success"))
  444. ctx.Flash.Info(t.Sha1)
  445. ctx.Redirect(setting.AppSubURL + "/user/settings/applications")
  446. }
  447. // SettingsDeleteApplication response for delete user access token
  448. func SettingsDeleteApplication(ctx *context.Context) {
  449. if err := models.DeleteAccessTokenByID(ctx.QueryInt64("id"), ctx.User.ID); err != nil {
  450. ctx.Flash.Error("DeleteAccessTokenByID: " + err.Error())
  451. } else {
  452. ctx.Flash.Success(ctx.Tr("settings.delete_token_success"))
  453. }
  454. ctx.JSON(200, map[string]interface{}{
  455. "redirect": setting.AppSubURL + "/user/settings/applications",
  456. })
  457. }
  458. // SettingsTwoFactorRegenerateScratch regenerates the user's 2FA scratch code.
  459. func SettingsTwoFactorRegenerateScratch(ctx *context.Context) {
  460. ctx.Data["Title"] = ctx.Tr("settings")
  461. ctx.Data["PageIsSettingsSecurity"] = true
  462. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  463. if err != nil {
  464. ctx.Handle(500, "SettingsTwoFactor", err)
  465. return
  466. }
  467. if err = t.GenerateScratchToken(); err != nil {
  468. ctx.Handle(500, "SettingsTwoFactor", err)
  469. return
  470. }
  471. if err = models.UpdateTwoFactor(t); err != nil {
  472. ctx.Handle(500, "SettingsTwoFactor", err)
  473. return
  474. }
  475. ctx.Flash.Success(ctx.Tr("settings.twofa_scratch_token_regenerated", t.ScratchToken))
  476. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  477. }
  478. // SettingsTwoFactorDisable deletes the user's 2FA settings.
  479. func SettingsTwoFactorDisable(ctx *context.Context) {
  480. ctx.Data["Title"] = ctx.Tr("settings")
  481. ctx.Data["PageIsSettingsSecurity"] = true
  482. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  483. if err != nil {
  484. ctx.Handle(500, "SettingsTwoFactor", err)
  485. return
  486. }
  487. if err = models.DeleteTwoFactorByID(t.ID, ctx.User.ID); err != nil {
  488. ctx.Handle(500, "SettingsTwoFactor", err)
  489. return
  490. }
  491. ctx.Flash.Success(ctx.Tr("settings.twofa_disabled"))
  492. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  493. }
  494. func twofaGenerateSecretAndQr(ctx *context.Context) bool {
  495. var otpKey *otp.Key
  496. var err error
  497. uri := ctx.Session.Get("twofaUri")
  498. if uri != nil {
  499. otpKey, err = otp.NewKeyFromURL(uri.(string))
  500. }
  501. if otpKey == nil {
  502. err = nil // clear the error, in case the URL was invalid
  503. otpKey, err = totp.Generate(totp.GenerateOpts{
  504. Issuer: setting.AppName + " (" + strings.TrimRight(setting.AppURL, "/") + ")",
  505. AccountName: ctx.User.Name,
  506. })
  507. if err != nil {
  508. ctx.Handle(500, "SettingsTwoFactor", err)
  509. return false
  510. }
  511. }
  512. ctx.Data["TwofaSecret"] = otpKey.Secret()
  513. img, err := otpKey.Image(320, 240)
  514. if err != nil {
  515. ctx.Handle(500, "SettingsTwoFactor", err)
  516. return false
  517. }
  518. var imgBytes bytes.Buffer
  519. if err = png.Encode(&imgBytes, img); err != nil {
  520. ctx.Handle(500, "SettingsTwoFactor", err)
  521. return false
  522. }
  523. ctx.Data["QrUri"] = template.URL("data:image/png;base64," + base64.StdEncoding.EncodeToString(imgBytes.Bytes()))
  524. ctx.Session.Set("twofaSecret", otpKey.Secret())
  525. ctx.Session.Set("twofaUri", otpKey.String())
  526. return true
  527. }
  528. // SettingsTwoFactorEnroll shows the page where the user can enroll into 2FA.
  529. func SettingsTwoFactorEnroll(ctx *context.Context) {
  530. ctx.Data["Title"] = ctx.Tr("settings")
  531. ctx.Data["PageIsSettingsSecurity"] = true
  532. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  533. if t != nil {
  534. // already enrolled
  535. ctx.Handle(500, "SettingsTwoFactor", err)
  536. return
  537. }
  538. if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
  539. ctx.Handle(500, "SettingsTwoFactor", err)
  540. return
  541. }
  542. if !twofaGenerateSecretAndQr(ctx) {
  543. return
  544. }
  545. ctx.HTML(200, tplSettingsTwofaEnroll)
  546. }
  547. // SettingsTwoFactorEnrollPost handles enrolling the user into 2FA.
  548. func SettingsTwoFactorEnrollPost(ctx *context.Context, form auth.TwoFactorAuthForm) {
  549. ctx.Data["Title"] = ctx.Tr("settings")
  550. ctx.Data["PageIsSettingsSecurity"] = true
  551. t, err := models.GetTwoFactorByUID(ctx.User.ID)
  552. if t != nil {
  553. // already enrolled
  554. ctx.Handle(500, "SettingsTwoFactor", err)
  555. return
  556. }
  557. if err != nil && !models.IsErrTwoFactorNotEnrolled(err) {
  558. ctx.Handle(500, "SettingsTwoFactor", err)
  559. return
  560. }
  561. if ctx.HasError() {
  562. if !twofaGenerateSecretAndQr(ctx) {
  563. return
  564. }
  565. ctx.HTML(200, tplSettingsTwofaEnroll)
  566. return
  567. }
  568. secret := ctx.Session.Get("twofaSecret").(string)
  569. if !totp.Validate(form.Passcode, secret) {
  570. if !twofaGenerateSecretAndQr(ctx) {
  571. return
  572. }
  573. ctx.Flash.Error(ctx.Tr("settings.passcode_invalid"))
  574. ctx.HTML(200, tplSettingsTwofaEnroll)
  575. return
  576. }
  577. t = &models.TwoFactor{
  578. UID: ctx.User.ID,
  579. }
  580. err = t.SetSecret(secret)
  581. if err != nil {
  582. ctx.Handle(500, "SettingsTwoFactor", err)
  583. return
  584. }
  585. err = t.GenerateScratchToken()
  586. if err != nil {
  587. ctx.Handle(500, "SettingsTwoFactor", err)
  588. return
  589. }
  590. if err = models.NewTwoFactor(t); err != nil {
  591. ctx.Handle(500, "SettingsTwoFactor", err)
  592. return
  593. }
  594. ctx.Session.Delete("twofaSecret")
  595. ctx.Session.Delete("twofaUri")
  596. ctx.Flash.Success(ctx.Tr("settings.twofa_enrolled", t.ScratchToken))
  597. ctx.Redirect(setting.AppSubURL + "/user/settings/security")
  598. }
  599. // SettingsAccountLinks render the account links settings page
  600. func SettingsAccountLinks(ctx *context.Context) {
  601. ctx.Data["Title"] = ctx.Tr("settings")
  602. ctx.Data["PageIsSettingsAccountLink"] = true
  603. accountLinks, err := models.ListAccountLinks(ctx.User)
  604. if err != nil {
  605. ctx.Handle(500, "ListAccountLinks", err)
  606. return
  607. }
  608. // map the provider display name with the LoginSource
  609. sources := make(map[*models.LoginSource]string)
  610. for _, externalAccount := range accountLinks {
  611. if loginSource, err := models.GetLoginSourceByID(externalAccount.LoginSourceID); err == nil {
  612. var providerDisplayName string
  613. if loginSource.IsOAuth2() {
  614. providerTechnicalName := loginSource.OAuth2().Provider
  615. providerDisplayName = models.OAuth2Providers[providerTechnicalName].DisplayName
  616. } else {
  617. providerDisplayName = loginSource.Name
  618. }
  619. sources[loginSource] = providerDisplayName
  620. }
  621. }
  622. ctx.Data["AccountLinks"] = sources
  623. ctx.HTML(200, tplSettingsAccountLink)
  624. }
  625. // SettingsDeleteAccountLink delete a single account link
  626. func SettingsDeleteAccountLink(ctx *context.Context) {
  627. if _, err := models.RemoveAccountLink(ctx.User, ctx.QueryInt64("loginSourceID")); err != nil {
  628. ctx.Flash.Error("RemoveAccountLink: " + err.Error())
  629. } else {
  630. ctx.Flash.Success(ctx.Tr("settings.remove_account_link_success"))
  631. }
  632. ctx.JSON(200, map[string]interface{}{
  633. "redirect": setting.AppSubURL + "/user/settings/account_link",
  634. })
  635. }
  636. // SettingsDelete render user suicide page and response for delete user himself
  637. func SettingsDelete(ctx *context.Context) {
  638. ctx.Data["Title"] = ctx.Tr("settings")
  639. ctx.Data["PageIsSettingsDelete"] = true
  640. ctx.Data["Email"] = ctx.User.Email
  641. if ctx.Req.Method == "POST" {
  642. if _, err := models.UserSignIn(ctx.User.Name, ctx.Query("password")); err != nil {
  643. if models.IsErrUserNotExist(err) {
  644. ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), tplSettingsDelete, nil)
  645. } else {
  646. ctx.Handle(500, "UserSignIn", err)
  647. }
  648. return
  649. }
  650. if err := models.DeleteUser(ctx.User); err != nil {
  651. switch {
  652. case models.IsErrUserOwnRepos(err):
  653. ctx.Flash.Error(ctx.Tr("form.still_own_repo"))
  654. ctx.Redirect(setting.AppSubURL + "/user/settings/delete")
  655. case models.IsErrUserHasOrgs(err):
  656. ctx.Flash.Error(ctx.Tr("form.still_has_org"))
  657. ctx.Redirect(setting.AppSubURL + "/user/settings/delete")
  658. default:
  659. ctx.Handle(500, "DeleteUser", err)
  660. }
  661. } else {
  662. log.Trace("Account deleted: %s", ctx.User.Name)
  663. ctx.Redirect(setting.AppSubURL + "/")
  664. }
  665. return
  666. }
  667. ctx.HTML(200, tplSettingsDelete)
  668. }
  669. // SettingsOrganization render all the organization of the user
  670. func SettingsOrganization(ctx *context.Context) {
  671. ctx.Data["Title"] = ctx.Tr("settings")
  672. ctx.Data["PageIsSettingsOrganization"] = true
  673. orgs, err := models.GetOrgsByUserID(ctx.User.ID, ctx.IsSigned)
  674. if err != nil {
  675. ctx.Handle(500, "GetOrgsByUserID", err)
  676. return
  677. }
  678. ctx.Data["Orgs"] = orgs
  679. ctx.HTML(200, tplSettingsOrganization)
  680. }
  681. // SettingsRepos display a list of all repositories of the user
  682. func SettingsRepos(ctx *context.Context) {
  683. ctx.Data["Title"] = ctx.Tr("settings")
  684. ctx.Data["PageIsSettingsRepos"] = true
  685. ctxUser := ctx.User
  686. var err error
  687. if err = ctxUser.GetRepositories(1, setting.UI.User.RepoPagingNum); err != nil {
  688. ctx.Handle(500, "GetRepositories", err)
  689. return
  690. }
  691. repos := ctxUser.Repos
  692. for i := range repos {
  693. if repos[i].IsFork {
  694. err := repos[i].GetBaseRepo()
  695. if err != nil {
  696. ctx.Handle(500, "GetBaseRepo", err)
  697. return
  698. }
  699. err = repos[i].BaseRepo.GetOwner()
  700. if err != nil {
  701. ctx.Handle(500, "GetOwner", err)
  702. return
  703. }
  704. }
  705. }
  706. ctx.Data["Owner"] = ctxUser
  707. ctx.Data["Repos"] = repos
  708. ctx.HTML(200, tplSettingsRepositories)
  709. }