users.ts 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
  2. import 'mocha'
  3. import { expect } from 'chai'
  4. import { omit } from 'lodash'
  5. import { join } from 'path'
  6. import { User, UserRole, VideoImport, VideoImportState } from '../../../../shared'
  7. import {
  8. addVideoChannel,
  9. blockUser,
  10. cleanupTests,
  11. createUser,
  12. deleteMe,
  13. flushAndRunServer,
  14. getMyUserInformation,
  15. getMyUserVideoRating,
  16. getUserScopedTokens,
  17. getUsersList,
  18. immutableAssign,
  19. killallServers,
  20. makeGetRequest,
  21. makePostBodyRequest,
  22. makePutBodyRequest,
  23. makeUploadRequest,
  24. registerUser,
  25. removeUser,
  26. renewUserScopedTokens,
  27. reRunServer,
  28. ServerInfo,
  29. setAccessTokensToServers,
  30. unblockUser,
  31. updateUser,
  32. uploadVideo,
  33. userLogin
  34. } from '../../../../shared/extra-utils'
  35. import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
  36. import {
  37. checkBadCountPagination,
  38. checkBadSortPagination,
  39. checkBadStartPagination
  40. } from '../../../../shared/extra-utils/requests/check-api-params'
  41. import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
  42. import { getGoodVideoUrl, getMagnetURI, getMyVideoImports, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
  43. import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
  44. import { VideoPrivacy } from '../../../../shared/models/videos'
  45. import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
  46. describe('Test users API validators', function () {
  47. const path = '/api/v1/users/'
  48. let userId: number
  49. let rootId: number
  50. let moderatorId: number
  51. let videoId: number
  52. let server: ServerInfo
  53. let serverWithRegistrationDisabled: ServerInfo
  54. let userAccessToken = ''
  55. let moderatorAccessToken = ''
  56. let emailPort: number
  57. let overrideConfig: Object
  58. // ---------------------------------------------------------------
  59. before(async function () {
  60. this.timeout(30000)
  61. const emails: object[] = []
  62. emailPort = await MockSmtpServer.Instance.collectEmails(emails)
  63. overrideConfig = { signup: { limit: 8 } }
  64. {
  65. const res = await Promise.all([
  66. flushAndRunServer(1, overrideConfig),
  67. flushAndRunServer(2)
  68. ])
  69. server = res[0]
  70. serverWithRegistrationDisabled = res[1]
  71. await setAccessTokensToServers([ server ])
  72. }
  73. {
  74. const user = {
  75. username: 'user1',
  76. password: 'my super password'
  77. }
  78. const videoQuota = 42000000
  79. await createUser({
  80. url: server.url,
  81. accessToken: server.accessToken,
  82. username: user.username,
  83. password: user.password,
  84. videoQuota: videoQuota
  85. })
  86. userAccessToken = await userLogin(server, user)
  87. }
  88. {
  89. const moderator = {
  90. username: 'moderator1',
  91. password: 'super password'
  92. }
  93. await createUser({
  94. url: server.url,
  95. accessToken: server.accessToken,
  96. username: moderator.username,
  97. password: moderator.password,
  98. role: UserRole.MODERATOR
  99. })
  100. moderatorAccessToken = await userLogin(server, moderator)
  101. }
  102. {
  103. const moderator = {
  104. username: 'moderator2',
  105. password: 'super password'
  106. }
  107. await createUser({
  108. url: server.url,
  109. accessToken: server.accessToken,
  110. username: moderator.username,
  111. password: moderator.password,
  112. role: UserRole.MODERATOR
  113. })
  114. }
  115. {
  116. const res = await uploadVideo(server.url, server.accessToken, {})
  117. videoId = res.body.video.id
  118. }
  119. {
  120. const res = await getUsersList(server.url, server.accessToken)
  121. const users: User[] = res.body.data
  122. userId = users.find(u => u.username === 'user1').id
  123. rootId = users.find(u => u.username === 'root').id
  124. moderatorId = users.find(u => u.username === 'moderator2').id
  125. }
  126. })
  127. describe('When listing users', function () {
  128. it('Should fail with a bad start pagination', async function () {
  129. await checkBadStartPagination(server.url, path, server.accessToken)
  130. })
  131. it('Should fail with a bad count pagination', async function () {
  132. await checkBadCountPagination(server.url, path, server.accessToken)
  133. })
  134. it('Should fail with an incorrect sort', async function () {
  135. await checkBadSortPagination(server.url, path, server.accessToken)
  136. })
  137. it('Should fail with a non authenticated user', async function () {
  138. await makeGetRequest({
  139. url: server.url,
  140. path,
  141. statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
  142. })
  143. })
  144. it('Should fail with a non admin user', async function () {
  145. await makeGetRequest({
  146. url: server.url,
  147. path,
  148. token: userAccessToken,
  149. statusCodeExpected: HttpStatusCode.FORBIDDEN_403
  150. })
  151. })
  152. })
  153. describe('When adding a new user', function () {
  154. const baseCorrectParams = {
  155. username: 'user2',
  156. email: 'test@example.com',
  157. password: 'my super password',
  158. videoQuota: -1,
  159. videoQuotaDaily: -1,
  160. role: UserRole.USER,
  161. adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLACKLIST
  162. }
  163. it('Should fail with a too small username', async function () {
  164. const fields = immutableAssign(baseCorrectParams, { username: '' })
  165. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  166. })
  167. it('Should fail with a too long username', async function () {
  168. const fields = immutableAssign(baseCorrectParams, { username: 'super'.repeat(50) })
  169. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  170. })
  171. it('Should fail with a not lowercase username', async function () {
  172. const fields = immutableAssign(baseCorrectParams, { username: 'Toto' })
  173. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  174. })
  175. it('Should fail with an incorrect username', async function () {
  176. const fields = immutableAssign(baseCorrectParams, { username: 'my username' })
  177. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  178. })
  179. it('Should fail with a missing email', async function () {
  180. const fields = omit(baseCorrectParams, 'email')
  181. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  182. })
  183. it('Should fail with an invalid email', async function () {
  184. const fields = immutableAssign(baseCorrectParams, { email: 'test_example.com' })
  185. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  186. })
  187. it('Should fail with a too small password', async function () {
  188. const fields = immutableAssign(baseCorrectParams, { password: 'bla' })
  189. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  190. })
  191. it('Should fail with a too long password', async function () {
  192. const fields = immutableAssign(baseCorrectParams, { password: 'super'.repeat(61) })
  193. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  194. })
  195. it('Should fail with empty password and no smtp configured', async function () {
  196. const fields = immutableAssign(baseCorrectParams, { password: '' })
  197. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  198. })
  199. it('Should succeed with no password on a server with smtp enabled', async function () {
  200. this.timeout(10000)
  201. killallServers([ server ])
  202. const config = immutableAssign(overrideConfig, {
  203. smtp: {
  204. hostname: 'localhost',
  205. port: emailPort
  206. }
  207. })
  208. await reRunServer(server, config)
  209. const fields = immutableAssign(baseCorrectParams, {
  210. password: '',
  211. username: 'create_password',
  212. email: 'create_password@example.com'
  213. })
  214. await makePostBodyRequest({
  215. url: server.url,
  216. path: path,
  217. token: server.accessToken,
  218. fields,
  219. statusCodeExpected: HttpStatusCode.OK_200
  220. })
  221. })
  222. it('Should fail with invalid admin flags', async function () {
  223. const fields = immutableAssign(baseCorrectParams, { adminFlags: 'toto' })
  224. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  225. })
  226. it('Should fail with an non authenticated user', async function () {
  227. await makePostBodyRequest({
  228. url: server.url,
  229. path,
  230. token: 'super token',
  231. fields: baseCorrectParams,
  232. statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
  233. })
  234. })
  235. it('Should fail if we add a user with the same username', async function () {
  236. const fields = immutableAssign(baseCorrectParams, { username: 'user1' })
  237. await makePostBodyRequest({
  238. url: server.url,
  239. path,
  240. token: server.accessToken,
  241. fields,
  242. statusCodeExpected: HttpStatusCode.CONFLICT_409
  243. })
  244. })
  245. it('Should fail if we add a user with the same email', async function () {
  246. const fields = immutableAssign(baseCorrectParams, { email: 'user1@example.com' })
  247. await makePostBodyRequest({
  248. url: server.url,
  249. path,
  250. token: server.accessToken,
  251. fields,
  252. statusCodeExpected: HttpStatusCode.CONFLICT_409
  253. })
  254. })
  255. it('Should fail without a videoQuota', async function () {
  256. const fields = omit(baseCorrectParams, 'videoQuota')
  257. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  258. })
  259. it('Should fail without a videoQuotaDaily', async function () {
  260. const fields = omit(baseCorrectParams, 'videoQuotaDaily')
  261. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  262. })
  263. it('Should fail with an invalid videoQuota', async function () {
  264. const fields = immutableAssign(baseCorrectParams, { videoQuota: -5 })
  265. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  266. })
  267. it('Should fail with an invalid videoQuotaDaily', async function () {
  268. const fields = immutableAssign(baseCorrectParams, { videoQuotaDaily: -7 })
  269. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  270. })
  271. it('Should fail without a user role', async function () {
  272. const fields = omit(baseCorrectParams, 'role')
  273. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  274. })
  275. it('Should fail with an invalid user role', async function () {
  276. const fields = immutableAssign(baseCorrectParams, { role: 88989 })
  277. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  278. })
  279. it('Should fail with a "peertube" username', async function () {
  280. const fields = immutableAssign(baseCorrectParams, { username: 'peertube' })
  281. await makePostBodyRequest({
  282. url: server.url,
  283. path,
  284. token: server.accessToken,
  285. fields,
  286. statusCodeExpected: HttpStatusCode.CONFLICT_409
  287. })
  288. })
  289. it('Should fail to create a moderator or an admin with a moderator', async function () {
  290. for (const role of [ UserRole.MODERATOR, UserRole.ADMINISTRATOR ]) {
  291. const fields = immutableAssign(baseCorrectParams, { role })
  292. await makePostBodyRequest({
  293. url: server.url,
  294. path,
  295. token: moderatorAccessToken,
  296. fields,
  297. statusCodeExpected: HttpStatusCode.FORBIDDEN_403
  298. })
  299. }
  300. })
  301. it('Should succeed to create a user with a moderator', async function () {
  302. const fields = immutableAssign(baseCorrectParams, { username: 'a4656', email: 'a4656@example.com', role: UserRole.USER })
  303. await makePostBodyRequest({
  304. url: server.url,
  305. path,
  306. token: moderatorAccessToken,
  307. fields,
  308. statusCodeExpected: HttpStatusCode.OK_200
  309. })
  310. })
  311. it('Should succeed with the correct params', async function () {
  312. await makePostBodyRequest({
  313. url: server.url,
  314. path,
  315. token: server.accessToken,
  316. fields: baseCorrectParams,
  317. statusCodeExpected: HttpStatusCode.OK_200
  318. })
  319. })
  320. it('Should fail with a non admin user', async function () {
  321. const user = {
  322. username: 'user1',
  323. password: 'my super password'
  324. }
  325. userAccessToken = await userLogin(server, user)
  326. const fields = {
  327. username: 'user3',
  328. email: 'test@example.com',
  329. password: 'my super password',
  330. videoQuota: 42000000
  331. }
  332. await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields, statusCodeExpected: HttpStatusCode.FORBIDDEN_403 })
  333. })
  334. })
  335. describe('When updating my account', function () {
  336. it('Should fail with an invalid email attribute', async function () {
  337. const fields = {
  338. email: 'blabla'
  339. }
  340. await makePutBodyRequest({ url: server.url, path: path + 'me', token: server.accessToken, fields })
  341. })
  342. it('Should fail with a too small password', async function () {
  343. const fields = {
  344. currentPassword: 'my super password',
  345. password: 'bla'
  346. }
  347. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  348. })
  349. it('Should fail with a too long password', async function () {
  350. const fields = {
  351. currentPassword: 'my super password',
  352. password: 'super'.repeat(61)
  353. }
  354. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  355. })
  356. it('Should fail without the current password', async function () {
  357. const fields = {
  358. currentPassword: 'my super password',
  359. password: 'super'.repeat(61)
  360. }
  361. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  362. })
  363. it('Should fail with an invalid current password', async function () {
  364. const fields = {
  365. currentPassword: 'my super password fail',
  366. password: 'super'.repeat(61)
  367. }
  368. await makePutBodyRequest({
  369. url: server.url,
  370. path: path + 'me',
  371. token: userAccessToken,
  372. fields,
  373. statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
  374. })
  375. })
  376. it('Should fail with an invalid NSFW policy attribute', async function () {
  377. const fields = {
  378. nsfwPolicy: 'hello'
  379. }
  380. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  381. })
  382. it('Should fail with an invalid autoPlayVideo attribute', async function () {
  383. const fields = {
  384. autoPlayVideo: -1
  385. }
  386. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  387. })
  388. it('Should fail with an invalid autoPlayNextVideo attribute', async function () {
  389. const fields = {
  390. autoPlayNextVideo: -1
  391. }
  392. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  393. })
  394. it('Should fail with an invalid videosHistoryEnabled attribute', async function () {
  395. const fields = {
  396. videosHistoryEnabled: -1
  397. }
  398. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  399. })
  400. it('Should fail with an non authenticated user', async function () {
  401. const fields = {
  402. currentPassword: 'my super password',
  403. password: 'my super password'
  404. }
  405. await makePutBodyRequest({
  406. url: server.url,
  407. path: path + 'me',
  408. token: 'super token',
  409. fields,
  410. statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
  411. })
  412. })
  413. it('Should fail with a too long description', async function () {
  414. const fields = {
  415. description: 'super'.repeat(201)
  416. }
  417. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  418. })
  419. it('Should fail with an invalid videoLanguages attribute', async function () {
  420. {
  421. const fields = {
  422. videoLanguages: 'toto'
  423. }
  424. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  425. }
  426. {
  427. const languages = []
  428. for (let i = 0; i < 1000; i++) {
  429. languages.push('fr')
  430. }
  431. const fields = {
  432. videoLanguages: languages
  433. }
  434. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  435. }
  436. })
  437. it('Should fail with an invalid theme', async function () {
  438. const fields = { theme: 'invalid' }
  439. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  440. })
  441. it('Should fail with an unknown theme', async function () {
  442. const fields = { theme: 'peertube-theme-unknown' }
  443. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  444. })
  445. it('Should fail with an invalid noInstanceConfigWarningModal attribute', async function () {
  446. const fields = {
  447. noInstanceConfigWarningModal: -1
  448. }
  449. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  450. })
  451. it('Should fail with an invalid noWelcomeModal attribute', async function () {
  452. const fields = {
  453. noWelcomeModal: -1
  454. }
  455. await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
  456. })
  457. it('Should succeed to change password with the correct params', async function () {
  458. const fields = {
  459. currentPassword: 'my super password',
  460. password: 'my super password',
  461. nsfwPolicy: 'blur',
  462. autoPlayVideo: false,
  463. email: 'super_email@example.com',
  464. theme: 'default',
  465. noInstanceConfigWarningModal: true,
  466. noWelcomeModal: true
  467. }
  468. await makePutBodyRequest({
  469. url: server.url,
  470. path: path + 'me',
  471. token: userAccessToken,
  472. fields,
  473. statusCodeExpected: HttpStatusCode.NO_CONTENT_204
  474. })
  475. })
  476. it('Should succeed without password change with the correct params', async function () {
  477. const fields = {
  478. nsfwPolicy: 'blur',
  479. autoPlayVideo: false
  480. }
  481. await makePutBodyRequest({
  482. url: server.url,
  483. path: path + 'me',
  484. token: userAccessToken,
  485. fields,
  486. statusCodeExpected: HttpStatusCode.NO_CONTENT_204
  487. })
  488. })
  489. })
  490. describe('When updating my avatar', function () {
  491. it('Should fail without an incorrect input file', async function () {
  492. const fields = {}
  493. const attaches = {
  494. avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
  495. }
  496. await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
  497. })
  498. it('Should fail with a big file', async function () {
  499. const fields = {}
  500. const attaches = {
  501. avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
  502. }
  503. await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
  504. })
  505. it('Should fail with an unauthenticated user', async function () {
  506. const fields = {}
  507. const attaches = {
  508. avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
  509. }
  510. await makeUploadRequest({
  511. url: server.url,
  512. path: path + '/me/avatar/pick',
  513. fields,
  514. attaches,
  515. statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
  516. })
  517. })
  518. it('Should succeed with the correct params', async function () {
  519. const fields = {}
  520. const attaches = {
  521. avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
  522. }
  523. await makeUploadRequest({
  524. url: server.url,
  525. path: path + '/me/avatar/pick',
  526. token: server.accessToken,
  527. fields,
  528. attaches,
  529. statusCodeExpected: HttpStatusCode.OK_200
  530. })
  531. })
  532. })
  533. describe('When managing my scoped tokens', function () {
  534. it('Should fail to get my scoped tokens with an non authenticated user', async function () {
  535. await getUserScopedTokens(server.url, null, HttpStatusCode.UNAUTHORIZED_401)
  536. })
  537. it('Should fail to get my scoped tokens with a bad token', async function () {
  538. await getUserScopedTokens(server.url, 'bad', HttpStatusCode.UNAUTHORIZED_401)
  539. })
  540. it('Should succeed to get my scoped tokens', async function () {
  541. await getUserScopedTokens(server.url, server.accessToken)
  542. })
  543. it('Should fail to renew my scoped tokens with an non authenticated user', async function () {
  544. await renewUserScopedTokens(server.url, null, HttpStatusCode.UNAUTHORIZED_401)
  545. })
  546. it('Should fail to renew my scoped tokens with a bad token', async function () {
  547. await renewUserScopedTokens(server.url, 'bad', HttpStatusCode.UNAUTHORIZED_401)
  548. })
  549. it('Should succeed to renew my scoped tokens', async function () {
  550. await renewUserScopedTokens(server.url, server.accessToken)
  551. })
  552. })
  553. describe('When getting a user', function () {
  554. it('Should fail with an non authenticated user', async function () {
  555. await makeGetRequest({
  556. url: server.url,
  557. path: path + userId,
  558. token: 'super token',
  559. statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
  560. })
  561. })
  562. it('Should fail with a non admin user', async function () {
  563. await makeGetRequest({ url: server.url, path, token: userAccessToken, statusCodeExpected: HttpStatusCode.FORBIDDEN_403 })
  564. })
  565. it('Should succeed with the correct params', async function () {
  566. await makeGetRequest({ url: server.url, path: path + userId, token: server.accessToken, statusCodeExpected: HttpStatusCode.OK_200 })
  567. })
  568. })
  569. describe('When updating a user', function () {
  570. it('Should fail with an invalid email attribute', async function () {
  571. const fields = {
  572. email: 'blabla'
  573. }
  574. await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
  575. })
  576. it('Should fail with an invalid emailVerified attribute', async function () {
  577. const fields = {
  578. emailVerified: 'yes'
  579. }
  580. await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
  581. })
  582. it('Should fail with an invalid videoQuota attribute', async function () {
  583. const fields = {
  584. videoQuota: -90
  585. }
  586. await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
  587. })
  588. it('Should fail with an invalid user role attribute', async function () {
  589. const fields = {
  590. role: 54878
  591. }
  592. await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
  593. })
  594. it('Should fail with a too small password', async function () {
  595. const fields = {
  596. currentPassword: 'my super password',
  597. password: 'bla'
  598. }
  599. await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
  600. })
  601. it('Should fail with a too long password', async function () {
  602. const fields = {
  603. currentPassword: 'my super password',
  604. password: 'super'.repeat(61)
  605. }
  606. await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
  607. })
  608. it('Should fail with an non authenticated user', async function () {
  609. const fields = {
  610. videoQuota: 42
  611. }
  612. await makePutBodyRequest({
  613. url: server.url,
  614. path: path + userId,
  615. token: 'super token',
  616. fields,
  617. statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401
  618. })
  619. })
  620. it('Should fail when updating root role', async function () {
  621. const fields = {
  622. role: UserRole.MODERATOR
  623. }
  624. await makePutBodyRequest({ url: server.url, path: path + rootId, token: server.accessToken, fields })
  625. })
  626. it('Should fail with invalid admin flags', async function () {
  627. const fields = { adminFlags: 'toto' }
  628. await makePutBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  629. })
  630. it('Should fail to update an admin with a moderator', async function () {
  631. const fields = {
  632. videoQuota: 42
  633. }
  634. await makePutBodyRequest({
  635. url: server.url,
  636. path: path + moderatorId,
  637. token: moderatorAccessToken,
  638. fields,
  639. statusCodeExpected: HttpStatusCode.FORBIDDEN_403
  640. })
  641. })
  642. it('Should succeed to update a user with a moderator', async function () {
  643. const fields = {
  644. videoQuota: 42
  645. }
  646. await makePutBodyRequest({
  647. url: server.url,
  648. path: path + userId,
  649. token: moderatorAccessToken,
  650. fields,
  651. statusCodeExpected: HttpStatusCode.NO_CONTENT_204
  652. })
  653. })
  654. it('Should succeed with the correct params', async function () {
  655. const fields = {
  656. email: 'email@example.com',
  657. emailVerified: true,
  658. videoQuota: 42,
  659. role: UserRole.USER
  660. }
  661. await makePutBodyRequest({
  662. url: server.url,
  663. path: path + userId,
  664. token: server.accessToken,
  665. fields,
  666. statusCodeExpected: HttpStatusCode.NO_CONTENT_204
  667. })
  668. })
  669. })
  670. describe('When getting my information', function () {
  671. it('Should fail with a non authenticated user', async function () {
  672. await getMyUserInformation(server.url, 'fake_token', HttpStatusCode.UNAUTHORIZED_401)
  673. })
  674. it('Should success with the correct parameters', async function () {
  675. await getMyUserInformation(server.url, userAccessToken)
  676. })
  677. })
  678. describe('When getting my video rating', function () {
  679. it('Should fail with a non authenticated user', async function () {
  680. await getMyUserVideoRating(server.url, 'fake_token', videoId, HttpStatusCode.UNAUTHORIZED_401)
  681. })
  682. it('Should fail with an incorrect video uuid', async function () {
  683. await getMyUserVideoRating(server.url, server.accessToken, 'blabla', HttpStatusCode.BAD_REQUEST_400)
  684. })
  685. it('Should fail with an unknown video', async function () {
  686. await getMyUserVideoRating(server.url, server.accessToken, '4da6fde3-88f7-4d16-b119-108df5630b06', HttpStatusCode.NOT_FOUND_404)
  687. })
  688. it('Should succeed with the correct parameters', async function () {
  689. await getMyUserVideoRating(server.url, server.accessToken, videoId)
  690. })
  691. })
  692. describe('When retrieving my global ratings', function () {
  693. const path = '/api/v1/accounts/user1/ratings'
  694. it('Should fail with a bad start pagination', async function () {
  695. await checkBadStartPagination(server.url, path, userAccessToken)
  696. })
  697. it('Should fail with a bad count pagination', async function () {
  698. await checkBadCountPagination(server.url, path, userAccessToken)
  699. })
  700. it('Should fail with an incorrect sort', async function () {
  701. await checkBadSortPagination(server.url, path, userAccessToken)
  702. })
  703. it('Should fail with a unauthenticated user', async function () {
  704. await makeGetRequest({ url: server.url, path, statusCodeExpected: HttpStatusCode.UNAUTHORIZED_401 })
  705. })
  706. it('Should fail with a another user', async function () {
  707. await makeGetRequest({ url: server.url, path, token: server.accessToken, statusCodeExpected: HttpStatusCode.FORBIDDEN_403 })
  708. })
  709. it('Should fail with a bad type', async function () {
  710. await makeGetRequest({
  711. url: server.url,
  712. path,
  713. token: userAccessToken,
  714. query: { rating: 'toto ' },
  715. statusCodeExpected: HttpStatusCode.BAD_REQUEST_400
  716. })
  717. })
  718. it('Should succeed with the correct params', async function () {
  719. await makeGetRequest({ url: server.url, path, token: userAccessToken, statusCodeExpected: HttpStatusCode.OK_200 })
  720. })
  721. })
  722. describe('When blocking/unblocking/removing user', function () {
  723. it('Should fail with an incorrect id', async function () {
  724. await removeUser(server.url, 'blabla', server.accessToken, HttpStatusCode.BAD_REQUEST_400)
  725. await blockUser(server.url, 'blabla', server.accessToken, HttpStatusCode.BAD_REQUEST_400)
  726. await unblockUser(server.url, 'blabla', server.accessToken, HttpStatusCode.BAD_REQUEST_400)
  727. })
  728. it('Should fail with the root user', async function () {
  729. await removeUser(server.url, rootId, server.accessToken, HttpStatusCode.BAD_REQUEST_400)
  730. await blockUser(server.url, rootId, server.accessToken, HttpStatusCode.BAD_REQUEST_400)
  731. await unblockUser(server.url, rootId, server.accessToken, HttpStatusCode.BAD_REQUEST_400)
  732. })
  733. it('Should return 404 with a non existing id', async function () {
  734. await removeUser(server.url, 4545454, server.accessToken, HttpStatusCode.NOT_FOUND_404)
  735. await blockUser(server.url, 4545454, server.accessToken, HttpStatusCode.NOT_FOUND_404)
  736. await unblockUser(server.url, 4545454, server.accessToken, HttpStatusCode.NOT_FOUND_404)
  737. })
  738. it('Should fail with a non admin user', async function () {
  739. await removeUser(server.url, userId, userAccessToken, HttpStatusCode.FORBIDDEN_403)
  740. await blockUser(server.url, userId, userAccessToken, HttpStatusCode.FORBIDDEN_403)
  741. await unblockUser(server.url, userId, userAccessToken, HttpStatusCode.FORBIDDEN_403)
  742. })
  743. it('Should fail on a moderator with a moderator', async function () {
  744. await removeUser(server.url, moderatorId, moderatorAccessToken, HttpStatusCode.FORBIDDEN_403)
  745. await blockUser(server.url, moderatorId, moderatorAccessToken, HttpStatusCode.FORBIDDEN_403)
  746. await unblockUser(server.url, moderatorId, moderatorAccessToken, HttpStatusCode.FORBIDDEN_403)
  747. })
  748. it('Should succeed on a user with a moderator', async function () {
  749. await blockUser(server.url, userId, moderatorAccessToken)
  750. await unblockUser(server.url, userId, moderatorAccessToken)
  751. })
  752. })
  753. describe('When deleting our account', function () {
  754. it('Should fail with with the root account', async function () {
  755. await deleteMe(server.url, server.accessToken, HttpStatusCode.BAD_REQUEST_400)
  756. })
  757. })
  758. describe('When registering a new user', function () {
  759. const registrationPath = path + '/register'
  760. const baseCorrectParams = {
  761. username: 'user3',
  762. displayName: 'super user',
  763. email: 'test3@example.com',
  764. password: 'my super password'
  765. }
  766. it('Should fail with a too small username', async function () {
  767. const fields = immutableAssign(baseCorrectParams, { username: '' })
  768. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  769. })
  770. it('Should fail with a too long username', async function () {
  771. const fields = immutableAssign(baseCorrectParams, { username: 'super'.repeat(50) })
  772. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  773. })
  774. it('Should fail with an incorrect username', async function () {
  775. const fields = immutableAssign(baseCorrectParams, { username: 'my username' })
  776. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  777. })
  778. it('Should fail with a missing email', async function () {
  779. const fields = omit(baseCorrectParams, 'email')
  780. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  781. })
  782. it('Should fail with an invalid email', async function () {
  783. const fields = immutableAssign(baseCorrectParams, { email: 'test_example.com' })
  784. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  785. })
  786. it('Should fail with a too small password', async function () {
  787. const fields = immutableAssign(baseCorrectParams, { password: 'bla' })
  788. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  789. })
  790. it('Should fail with a too long password', async function () {
  791. const fields = immutableAssign(baseCorrectParams, { password: 'super'.repeat(61) })
  792. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  793. })
  794. it('Should fail if we register a user with the same username', async function () {
  795. const fields = immutableAssign(baseCorrectParams, { username: 'root' })
  796. await makePostBodyRequest({
  797. url: server.url,
  798. path: registrationPath,
  799. token: server.accessToken,
  800. fields,
  801. statusCodeExpected: HttpStatusCode.CONFLICT_409
  802. })
  803. })
  804. it('Should fail with a "peertube" username', async function () {
  805. const fields = immutableAssign(baseCorrectParams, { username: 'peertube' })
  806. await makePostBodyRequest({
  807. url: server.url,
  808. path: registrationPath,
  809. token: server.accessToken,
  810. fields,
  811. statusCodeExpected: HttpStatusCode.CONFLICT_409
  812. })
  813. })
  814. it('Should fail if we register a user with the same email', async function () {
  815. const fields = immutableAssign(baseCorrectParams, { email: 'admin' + server.internalServerNumber + '@example.com' })
  816. await makePostBodyRequest({
  817. url: server.url,
  818. path: registrationPath,
  819. token: server.accessToken,
  820. fields,
  821. statusCodeExpected: HttpStatusCode.CONFLICT_409
  822. })
  823. })
  824. it('Should fail with a bad display name', async function () {
  825. const fields = immutableAssign(baseCorrectParams, { displayName: 'a'.repeat(150) })
  826. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  827. })
  828. it('Should fail with a bad channel name', async function () {
  829. const fields = immutableAssign(baseCorrectParams, { channel: { name: '[]azf', displayName: 'toto' } })
  830. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  831. })
  832. it('Should fail with a bad channel display name', async function () {
  833. const fields = immutableAssign(baseCorrectParams, { channel: { name: 'toto', displayName: '' } })
  834. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  835. })
  836. it('Should fail with a channel name that is the same as username', async function () {
  837. const source = { username: 'super_user', channel: { name: 'super_user', displayName: 'display name' } }
  838. const fields = immutableAssign(baseCorrectParams, source)
  839. await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
  840. })
  841. it('Should fail with an existing channel', async function () {
  842. const videoChannelAttributesArg = { name: 'existing_channel', displayName: 'hello', description: 'super description' }
  843. await addVideoChannel(server.url, server.accessToken, videoChannelAttributesArg)
  844. const fields = immutableAssign(baseCorrectParams, { channel: { name: 'existing_channel', displayName: 'toto' } })
  845. await makePostBodyRequest({
  846. url: server.url,
  847. path: registrationPath,
  848. token: server.accessToken,
  849. fields,
  850. statusCodeExpected: HttpStatusCode.CONFLICT_409
  851. })
  852. })
  853. it('Should succeed with the correct params', async function () {
  854. const fields = immutableAssign(baseCorrectParams, { channel: { name: 'super_channel', displayName: 'toto' } })
  855. await makePostBodyRequest({
  856. url: server.url,
  857. path: registrationPath,
  858. token: server.accessToken,
  859. fields: fields,
  860. statusCodeExpected: HttpStatusCode.NO_CONTENT_204
  861. })
  862. })
  863. it('Should fail on a server with registration disabled', async function () {
  864. const fields = {
  865. username: 'user4',
  866. email: 'test4@example.com',
  867. password: 'my super password 4'
  868. }
  869. await makePostBodyRequest({
  870. url: serverWithRegistrationDisabled.url,
  871. path: registrationPath,
  872. token: serverWithRegistrationDisabled.accessToken,
  873. fields,
  874. statusCodeExpected: HttpStatusCode.FORBIDDEN_403
  875. })
  876. })
  877. })
  878. describe('When registering multiple users on a server with users limit', function () {
  879. it('Should fail when after 3 registrations', async function () {
  880. await registerUser(server.url, 'user42', 'super password', HttpStatusCode.FORBIDDEN_403)
  881. })
  882. })
  883. describe('When having a video quota', function () {
  884. it('Should fail with a user having too many videos', async function () {
  885. await updateUser({
  886. url: server.url,
  887. userId: rootId,
  888. accessToken: server.accessToken,
  889. videoQuota: 42
  890. })
  891. await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
  892. })
  893. it('Should fail with a registered user having too many videos', async function () {
  894. this.timeout(30000)
  895. const user = {
  896. username: 'user3',
  897. password: 'my super password'
  898. }
  899. userAccessToken = await userLogin(server, user)
  900. const videoAttributes = { fixture: 'video_short2.webm' }
  901. await uploadVideo(server.url, userAccessToken, videoAttributes)
  902. await uploadVideo(server.url, userAccessToken, videoAttributes)
  903. await uploadVideo(server.url, userAccessToken, videoAttributes)
  904. await uploadVideo(server.url, userAccessToken, videoAttributes)
  905. await uploadVideo(server.url, userAccessToken, videoAttributes)
  906. await uploadVideo(server.url, userAccessToken, videoAttributes, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
  907. })
  908. it('Should fail to import with HTTP/Torrent/magnet', async function () {
  909. this.timeout(120000)
  910. const baseAttributes = {
  911. channelId: 1,
  912. privacy: VideoPrivacy.PUBLIC
  913. }
  914. await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getGoodVideoUrl() }))
  915. await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() }))
  916. await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: 'video-720p.torrent' as any }))
  917. await waitJobs([ server ])
  918. const res = await getMyVideoImports(server.url, server.accessToken)
  919. expect(res.body.total).to.equal(3)
  920. const videoImports: VideoImport[] = res.body.data
  921. expect(videoImports).to.have.lengthOf(3)
  922. for (const videoImport of videoImports) {
  923. expect(videoImport.state.id).to.equal(VideoImportState.FAILED)
  924. expect(videoImport.error).not.to.be.undefined
  925. expect(videoImport.error).to.contain('user video quota is exceeded')
  926. }
  927. })
  928. })
  929. describe('When having a daily video quota', function () {
  930. it('Should fail with a user having too many videos daily', async function () {
  931. await updateUser({
  932. url: server.url,
  933. userId: rootId,
  934. accessToken: server.accessToken,
  935. videoQuotaDaily: 42
  936. })
  937. await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
  938. })
  939. })
  940. describe('When having an absolute and daily video quota', function () {
  941. it('Should fail if exceeding total quota', async function () {
  942. await updateUser({
  943. url: server.url,
  944. userId: rootId,
  945. accessToken: server.accessToken,
  946. videoQuota: 42,
  947. videoQuotaDaily: 1024 * 1024 * 1024
  948. })
  949. await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
  950. })
  951. it('Should fail if exceeding daily quota', async function () {
  952. await updateUser({
  953. url: server.url,
  954. userId: rootId,
  955. accessToken: server.accessToken,
  956. videoQuota: 1024 * 1024 * 1024,
  957. videoQuotaDaily: 42
  958. })
  959. await uploadVideo(server.url, server.accessToken, {}, HttpStatusCode.PAYLOAD_TOO_LARGE_413)
  960. })
  961. })
  962. describe('When asking a password reset', function () {
  963. const path = '/api/v1/users/ask-reset-password'
  964. it('Should fail with a missing email', async function () {
  965. const fields = {}
  966. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  967. })
  968. it('Should fail with an invalid email', async function () {
  969. const fields = { email: 'hello' }
  970. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  971. })
  972. it('Should success with the correct params', async function () {
  973. const fields = { email: 'admin@example.com' }
  974. await makePostBodyRequest({
  975. url: server.url,
  976. path,
  977. token: server.accessToken,
  978. fields,
  979. statusCodeExpected: HttpStatusCode.NO_CONTENT_204
  980. })
  981. })
  982. })
  983. describe('When asking for an account verification email', function () {
  984. const path = '/api/v1/users/ask-send-verify-email'
  985. it('Should fail with a missing email', async function () {
  986. const fields = {}
  987. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  988. })
  989. it('Should fail with an invalid email', async function () {
  990. const fields = { email: 'hello' }
  991. await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
  992. })
  993. it('Should succeed with the correct params', async function () {
  994. const fields = { email: 'admin@example.com' }
  995. await makePostBodyRequest({
  996. url: server.url,
  997. path,
  998. token: server.accessToken,
  999. fields,
  1000. statusCodeExpected: HttpStatusCode.NO_CONTENT_204
  1001. })
  1002. })
  1003. })
  1004. after(async function () {
  1005. MockSmtpServer.Instance.kill()
  1006. await cleanupTests([ server, serverWithRegistrationDisabled ])
  1007. })
  1008. })