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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. // Copyright 2017 The Gitea 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 models
  5. import (
  6. "fmt"
  7. "math/rand"
  8. "strings"
  9. "testing"
  10. "code.gitea.io/gitea/modules/setting"
  11. "code.gitea.io/gitea/modules/structs"
  12. "code.gitea.io/gitea/modules/util"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. func TestUserIsPublicMember(t *testing.T) {
  16. assert.NoError(t, PrepareTestDatabase())
  17. tt := []struct {
  18. uid int64
  19. orgid int64
  20. expected bool
  21. }{
  22. {2, 3, true},
  23. {4, 3, false},
  24. {5, 6, true},
  25. {5, 7, false},
  26. }
  27. for _, v := range tt {
  28. t.Run(fmt.Sprintf("UserId%dIsPublicMemberOf%d", v.uid, v.orgid), func(t *testing.T) {
  29. testUserIsPublicMember(t, v.uid, v.orgid, v.expected)
  30. })
  31. }
  32. }
  33. func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) {
  34. user, err := GetUserByID(uid)
  35. assert.NoError(t, err)
  36. assert.Equal(t, expected, user.IsPublicMember(orgID))
  37. }
  38. func TestIsUserOrgOwner(t *testing.T) {
  39. assert.NoError(t, PrepareTestDatabase())
  40. tt := []struct {
  41. uid int64
  42. orgid int64
  43. expected bool
  44. }{
  45. {2, 3, true},
  46. {4, 3, false},
  47. {5, 6, true},
  48. {5, 7, true},
  49. }
  50. for _, v := range tt {
  51. t.Run(fmt.Sprintf("UserId%dIsOrgOwnerOf%d", v.uid, v.orgid), func(t *testing.T) {
  52. testIsUserOrgOwner(t, v.uid, v.orgid, v.expected)
  53. })
  54. }
  55. }
  56. func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
  57. user, err := GetUserByID(uid)
  58. assert.NoError(t, err)
  59. assert.Equal(t, expected, user.IsUserOrgOwner(orgID))
  60. }
  61. func TestGetUserEmailsByNames(t *testing.T) {
  62. assert.NoError(t, PrepareTestDatabase())
  63. // ignore none active user email
  64. assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user9"}))
  65. assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames([]string{"user8", "user5"}))
  66. assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user7"}))
  67. }
  68. func TestCanCreateOrganization(t *testing.T) {
  69. assert.NoError(t, PrepareTestDatabase())
  70. admin := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
  71. assert.True(t, admin.CanCreateOrganization())
  72. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  73. assert.True(t, user.CanCreateOrganization())
  74. // Disable user create organization permission.
  75. user.AllowCreateOrganization = false
  76. assert.False(t, user.CanCreateOrganization())
  77. setting.Admin.DisableRegularOrgCreation = true
  78. user.AllowCreateOrganization = true
  79. assert.True(t, admin.CanCreateOrganization())
  80. assert.False(t, user.CanCreateOrganization())
  81. }
  82. func TestSearchUsers(t *testing.T) {
  83. assert.NoError(t, PrepareTestDatabase())
  84. testSuccess := func(opts *SearchUserOptions, expectedUserOrOrgIDs []int64) {
  85. users, _, err := SearchUsers(opts)
  86. assert.NoError(t, err)
  87. if assert.Len(t, users, len(expectedUserOrOrgIDs)) {
  88. for i, expectedID := range expectedUserOrOrgIDs {
  89. assert.EqualValues(t, expectedID, users[i].ID)
  90. }
  91. }
  92. }
  93. // test orgs
  94. testOrgSuccess := func(opts *SearchUserOptions, expectedOrgIDs []int64) {
  95. opts.Type = UserTypeOrganization
  96. testSuccess(opts, expectedOrgIDs)
  97. }
  98. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1, PageSize: 2}},
  99. []int64{3, 6})
  100. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 2, PageSize: 2}},
  101. []int64{7, 17})
  102. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 3, PageSize: 2}},
  103. []int64{19, 25})
  104. testOrgSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 4, PageSize: 2}},
  105. []int64{26})
  106. testOrgSuccess(&SearchUserOptions{ListOptions: ListOptions{Page: 5, PageSize: 2}},
  107. []int64{})
  108. // test users
  109. testUserSuccess := func(opts *SearchUserOptions, expectedUserIDs []int64) {
  110. opts.Type = UserTypeIndividual
  111. testSuccess(opts, expectedUserIDs)
  112. }
  113. testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}},
  114. []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30})
  115. testUserSuccess(&SearchUserOptions{ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse},
  116. []int64{9})
  117. testUserSuccess(&SearchUserOptions{OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
  118. []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 28, 29, 30})
  119. testUserSuccess(&SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
  120. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  121. // order by name asc default
  122. testUserSuccess(&SearchUserOptions{Keyword: "user1", ListOptions: ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue},
  123. []int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
  124. }
  125. func TestDeleteUser(t *testing.T) {
  126. test := func(userID int64) {
  127. assert.NoError(t, PrepareTestDatabase())
  128. user := AssertExistsAndLoadBean(t, &User{ID: userID}).(*User)
  129. ownedRepos := make([]*Repository, 0, 10)
  130. assert.NoError(t, x.Find(&ownedRepos, &Repository{OwnerID: userID}))
  131. if len(ownedRepos) > 0 {
  132. err := DeleteUser(user)
  133. assert.Error(t, err)
  134. assert.True(t, IsErrUserOwnRepos(err))
  135. return
  136. }
  137. orgUsers := make([]*OrgUser, 0, 10)
  138. assert.NoError(t, x.Find(&orgUsers, &OrgUser{UID: userID}))
  139. for _, orgUser := range orgUsers {
  140. if err := RemoveOrgUser(orgUser.OrgID, orgUser.UID); err != nil {
  141. assert.True(t, IsErrLastOrgOwner(err))
  142. return
  143. }
  144. }
  145. assert.NoError(t, DeleteUser(user))
  146. AssertNotExistsBean(t, &User{ID: userID})
  147. CheckConsistencyFor(t, &User{}, &Repository{})
  148. }
  149. test(2)
  150. test(4)
  151. test(8)
  152. test(11)
  153. org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
  154. assert.Error(t, DeleteUser(org))
  155. }
  156. func TestEmailNotificationPreferences(t *testing.T) {
  157. assert.NoError(t, PrepareTestDatabase())
  158. for _, test := range []struct {
  159. expected string
  160. userID int64
  161. }{
  162. {EmailNotificationsEnabled, 1},
  163. {EmailNotificationsEnabled, 2},
  164. {EmailNotificationsOnMention, 3},
  165. {EmailNotificationsOnMention, 4},
  166. {EmailNotificationsEnabled, 5},
  167. {EmailNotificationsEnabled, 6},
  168. {EmailNotificationsDisabled, 7},
  169. {EmailNotificationsEnabled, 8},
  170. {EmailNotificationsOnMention, 9},
  171. } {
  172. user := AssertExistsAndLoadBean(t, &User{ID: test.userID}).(*User)
  173. assert.Equal(t, test.expected, user.EmailNotifications())
  174. // Try all possible settings
  175. assert.NoError(t, user.SetEmailNotifications(EmailNotificationsEnabled))
  176. assert.Equal(t, EmailNotificationsEnabled, user.EmailNotifications())
  177. assert.NoError(t, user.SetEmailNotifications(EmailNotificationsOnMention))
  178. assert.Equal(t, EmailNotificationsOnMention, user.EmailNotifications())
  179. assert.NoError(t, user.SetEmailNotifications(EmailNotificationsDisabled))
  180. assert.Equal(t, EmailNotificationsDisabled, user.EmailNotifications())
  181. }
  182. }
  183. func TestHashPasswordDeterministic(t *testing.T) {
  184. b := make([]byte, 16)
  185. u := &User{}
  186. algos := []string{"argon2", "pbkdf2", "scrypt", "bcrypt"}
  187. for j := 0; j < len(algos); j++ {
  188. u.PasswdHashAlgo = algos[j]
  189. for i := 0; i < 50; i++ {
  190. // generate a random password
  191. rand.Read(b)
  192. pass := string(b)
  193. // save the current password in the user - hash it and store the result
  194. u.SetPassword(pass)
  195. r1 := u.Passwd
  196. // run again
  197. u.SetPassword(pass)
  198. r2 := u.Passwd
  199. assert.NotEqual(t, r1, r2)
  200. assert.True(t, u.ValidatePassword(pass))
  201. }
  202. }
  203. }
  204. func BenchmarkHashPassword(b *testing.B) {
  205. // BenchmarkHashPassword ensures that it takes a reasonable amount of time
  206. // to hash a password - in order to protect from brute-force attacks.
  207. pass := "password1337"
  208. u := &User{Passwd: pass}
  209. b.ResetTimer()
  210. for i := 0; i < b.N; i++ {
  211. u.SetPassword(pass)
  212. }
  213. }
  214. func TestGetOrgRepositoryIDs(t *testing.T) {
  215. assert.NoError(t, PrepareTestDatabase())
  216. user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  217. user4 := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
  218. user5 := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
  219. accessibleRepos, err := user2.GetOrgRepositoryIDs()
  220. assert.NoError(t, err)
  221. // User 2's team has access to private repos 3, 5, repo 32 is a public repo of the organization
  222. assert.Equal(t, []int64{3, 5, 23, 24, 32}, accessibleRepos)
  223. accessibleRepos, err = user4.GetOrgRepositoryIDs()
  224. assert.NoError(t, err)
  225. // User 4's team has access to private repo 3, repo 32 is a public repo of the organization
  226. assert.Equal(t, []int64{3, 32}, accessibleRepos)
  227. accessibleRepos, err = user5.GetOrgRepositoryIDs()
  228. assert.NoError(t, err)
  229. // User 5's team has no access to any repo
  230. assert.Len(t, accessibleRepos, 0)
  231. }
  232. func TestNewGitSig(t *testing.T) {
  233. users := make([]*User, 0, 20)
  234. sess := x.NewSession()
  235. defer sess.Close()
  236. sess.Find(&users)
  237. for _, user := range users {
  238. sig := user.NewGitSig()
  239. assert.NotContains(t, sig.Name, "<")
  240. assert.NotContains(t, sig.Name, ">")
  241. assert.NotContains(t, sig.Name, "\n")
  242. assert.NotEqual(t, len(strings.TrimSpace(sig.Name)), 0)
  243. }
  244. }
  245. func TestDisplayName(t *testing.T) {
  246. users := make([]*User, 0, 20)
  247. sess := x.NewSession()
  248. defer sess.Close()
  249. sess.Find(&users)
  250. for _, user := range users {
  251. displayName := user.DisplayName()
  252. assert.Equal(t, strings.TrimSpace(displayName), displayName)
  253. if len(strings.TrimSpace(user.FullName)) == 0 {
  254. assert.Equal(t, user.Name, displayName)
  255. }
  256. assert.NotEqual(t, len(strings.TrimSpace(displayName)), 0)
  257. }
  258. }
  259. func TestCreateUser(t *testing.T) {
  260. user := &User{
  261. Name: "GiteaBot",
  262. Email: "GiteaBot@gitea.io",
  263. Passwd: ";p['////..-++']",
  264. IsAdmin: false,
  265. Theme: setting.UI.DefaultTheme,
  266. MustChangePassword: false,
  267. }
  268. assert.NoError(t, CreateUser(user))
  269. assert.NoError(t, DeleteUser(user))
  270. }
  271. func TestCreateUserInvalidEmail(t *testing.T) {
  272. user := &User{
  273. Name: "GiteaBot",
  274. Email: "GiteaBot@gitea.io\r\n",
  275. Passwd: ";p['////..-++']",
  276. IsAdmin: false,
  277. Theme: setting.UI.DefaultTheme,
  278. MustChangePassword: false,
  279. }
  280. err := CreateUser(user)
  281. assert.Error(t, err)
  282. assert.True(t, IsErrEmailInvalid(err))
  283. }
  284. func TestCreateUser_Issue5882(t *testing.T) {
  285. // Init settings
  286. _ = setting.Admin
  287. passwd := ".//.;1;;//.,-=_"
  288. tt := []struct {
  289. user *User
  290. disableOrgCreation bool
  291. }{
  292. {&User{Name: "GiteaBot", Email: "GiteaBot@gitea.io", Passwd: passwd, MustChangePassword: false}, false},
  293. {&User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true},
  294. }
  295. setting.Service.DefaultAllowCreateOrganization = true
  296. for _, v := range tt {
  297. setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation
  298. assert.NoError(t, CreateUser(v.user))
  299. u, err := GetUserByEmail(v.user.Email)
  300. assert.NoError(t, err)
  301. assert.Equal(t, !u.AllowCreateOrganization, v.disableOrgCreation)
  302. assert.NoError(t, DeleteUser(v.user))
  303. }
  304. }
  305. func TestGetUserIDsByNames(t *testing.T) {
  306. assert.NoError(t, PrepareTestDatabase())
  307. // ignore non existing
  308. IDs, err := GetUserIDsByNames([]string{"user1", "user2", "none_existing_user"}, true)
  309. assert.NoError(t, err)
  310. assert.Equal(t, []int64{1, 2}, IDs)
  311. // ignore non existing
  312. IDs, err = GetUserIDsByNames([]string{"user1", "do_not_exist"}, false)
  313. assert.Error(t, err)
  314. assert.Equal(t, []int64(nil), IDs)
  315. }
  316. func TestGetMaileableUsersByIDs(t *testing.T) {
  317. assert.NoError(t, PrepareTestDatabase())
  318. results, err := GetMaileableUsersByIDs([]int64{1, 4}, false)
  319. assert.NoError(t, err)
  320. assert.Len(t, results, 1)
  321. if len(results) > 1 {
  322. assert.Equal(t, results[0].ID, 1)
  323. }
  324. results, err = GetMaileableUsersByIDs([]int64{1, 4}, true)
  325. assert.NoError(t, err)
  326. assert.Len(t, results, 2)
  327. if len(results) > 2 {
  328. assert.Equal(t, results[0].ID, 1)
  329. assert.Equal(t, results[1].ID, 4)
  330. }
  331. }
  332. func TestAddLdapSSHPublicKeys(t *testing.T) {
  333. assert.NoError(t, PrepareTestDatabase())
  334. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  335. s := &LoginSource{ID: 1}
  336. testCases := []struct {
  337. keyString string
  338. number int
  339. keyContents []string
  340. }{
  341. {
  342. keyString: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment\n",
  343. number: 1,
  344. keyContents: []string{
  345. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  346. },
  347. },
  348. {
  349. keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment
  350. ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`,
  351. number: 2,
  352. keyContents: []string{
  353. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  354. "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=",
  355. },
  356. },
  357. {
  358. keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment
  359. # comment asmdna,ndp
  360. ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`,
  361. number: 2,
  362. keyContents: []string{
  363. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  364. "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=",
  365. },
  366. },
  367. {
  368. keyString: `ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM= nocomment
  369. 382488320jasdj1lasmva/vasodifipi4193-fksma.cm
  370. ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag= nocomment`,
  371. number: 2,
  372. keyContents: []string{
  373. "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4cn+iXnA4KvcQYSV88vGn0Yi91vG47t1P7okprVmhNTkipNRIHWr6WdCO4VDr/cvsRkuVJAsLO2enwjGWWueOO6BodiBgyAOZ/5t5nJNMCNuLGT5UIo/RI1b0WRQwxEZTRjt6mFNw6lH14wRd8ulsr9toSWBPMOGWoYs1PDeDL0JuTjL+tr1SZi/EyxCngpYszKdXllJEHyI79KQgeD0Vt3pTrkbNVTOEcCNqZePSVmUH8X8Vhugz3bnE0/iE9Pb5fkWO9c4AnM1FgI/8Bvp27Fw2ShryIXuR6kKvUqhVMTuOSDHwu6A8jLE5Owt3GAYugDpDYuwTVNGrHLXKpPzrGGPE/jPmaLCMZcsdkec95dYeU3zKODEm8UQZFhmJmDeWVJ36nGrGZHL4J5aTTaeFUJmmXDaJYiJ+K2/ioKgXqnXvltu0A9R8/LGy4nrTJRr4JMLuJFoUXvGm1gXQ70w2LSpk6yl71RNC0hCtsBe8BP8IhYCM0EP5jh7eCMQZNvM=",
  374. "ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ibZ2OkQ3S0SqDIa0HXSEJ1zaExQdmbO+Ux/wsytWZmCczWOVsaszBZSl90q8UnWlSH6P+/YA+RWJm5SFtuV9PtGIhyZgoNuz5kBQ7K139wuQsecdKktISwTakzAAAAFQCzKsO2JhNKlL+wwwLGOcLffoAmkwAAAIBpK7/3xvduajLBD/9vASqBQIHrgK2J+wiQnIb/Wzy0UsVmvfn8A+udRbBo+csM8xrSnlnlJnjkJS3qiM5g+eTwsLIV1IdKPEwmwB+VcP53Cw6lSyWyJcvhFb0N6s08NZysLzvj0N+ZC/FnhKTLzIyMtkHf/IrPCwlM+pV/M/96YgAAAIEAqQcGn9CKgzgPaguIZooTAOQdvBLMI5y0bQjOW6734XOpqQGf/Kra90wpoasLKZjSYKNPjE+FRUOrStLrxcNs4BeVKhy2PYTRnybfYVk1/dmKgH6P1YSRONsGKvTsH6c5IyCRG0ncCgYeF8tXppyd642982daopE7zQ/NPAnJfag=",
  375. },
  376. },
  377. }
  378. for i, kase := range testCases {
  379. s.ID = int64(i) + 20
  380. AddPublicKeysBySource(user, s, []string{kase.keyString})
  381. keys, err := ListPublicKeysBySource(user.ID, s.ID)
  382. assert.NoError(t, err)
  383. if err != nil {
  384. continue
  385. }
  386. assert.Len(t, keys, kase.number)
  387. for _, key := range keys {
  388. assert.Contains(t, kase.keyContents, key.Content)
  389. }
  390. for _, key := range keys {
  391. DeletePublicKey(user, key.ID)
  392. }
  393. }
  394. }
  395. func TestUpdateUser(t *testing.T) {
  396. assert.NoError(t, PrepareTestDatabase())
  397. user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  398. user.KeepActivityPrivate = true
  399. assert.NoError(t, UpdateUser(user))
  400. user = AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  401. assert.True(t, user.KeepActivityPrivate)
  402. setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false}
  403. user.KeepActivityPrivate = false
  404. user.Visibility = structs.VisibleTypePrivate
  405. assert.Error(t, UpdateUser(user))
  406. user = AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
  407. assert.True(t, user.KeepActivityPrivate)
  408. user.Email = "no mail@mail.org"
  409. assert.Error(t, UpdateUser(user))
  410. }