From b379759f55a35837b803a3b988674972db2903d1 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 19 Jan 2023 09:28:29 +0100 Subject: Add signup approval API tests --- server/tests/api/users/index.ts | 3 +- server/tests/api/users/registrations.ts | 379 +++++++++++++++++++++ server/tests/api/users/users-email-verification.ts | 167 +++++++++ server/tests/api/users/users-verification.ts | 170 --------- server/tests/api/users/users.ts | 50 --- 5 files changed, 548 insertions(+), 221 deletions(-) create mode 100644 server/tests/api/users/registrations.ts create mode 100644 server/tests/api/users/users-email-verification.ts delete mode 100644 server/tests/api/users/users-verification.ts (limited to 'server/tests/api/users') diff --git a/server/tests/api/users/index.ts b/server/tests/api/users/index.ts index 0313845ef..a4443a8ec 100644 --- a/server/tests/api/users/index.ts +++ b/server/tests/api/users/index.ts @@ -1,7 +1,8 @@ import './oauth' +import './registrations`' import './two-factor' import './user-subscriptions' import './user-videos' import './users' import './users-multiple-servers' -import './users-verification' +import './users-email-verification' diff --git a/server/tests/api/users/registrations.ts b/server/tests/api/users/registrations.ts new file mode 100644 index 000000000..a9e1114e8 --- /dev/null +++ b/server/tests/api/users/registrations.ts @@ -0,0 +1,379 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { expect } from 'chai' +import { MockSmtpServer } from '@server/tests/shared' +import { UserRegistrationState, UserRole } from '@shared/models' +import { + cleanupTests, + ConfigCommand, + createSingleServer, + PeerTubeServer, + setAccessTokensToServers, + waitJobs +} from '@shared/server-commands' + +describe('Test registrations', function () { + let server: PeerTubeServer + + const emails: object[] = [] + let emailPort: number + + before(async function () { + this.timeout(30000) + + emailPort = await MockSmtpServer.Instance.collectEmails(emails) + + server = await createSingleServer(1, ConfigCommand.getEmailOverrideConfig(emailPort)) + + await setAccessTokensToServers([ server ]) + await server.config.enableSignup(false) + }) + + describe('Direct registrations of a new user', function () { + let user1Token: string + + it('Should register a new user', async function () { + const user = { displayName: 'super user 1', username: 'user_1', password: 'my super password' } + const channel = { name: 'my_user_1_channel', displayName: 'my channel rocks' } + + await server.registrations.register({ ...user, channel }) + }) + + it('Should be able to login with this registered user', async function () { + const user1 = { username: 'user_1', password: 'my super password' } + + user1Token = await server.login.getAccessToken(user1) + }) + + it('Should have the correct display name', async function () { + const user = await server.users.getMyInfo({ token: user1Token }) + expect(user.account.displayName).to.equal('super user 1') + }) + + it('Should have the correct video quota', async function () { + const user = await server.users.getMyInfo({ token: user1Token }) + expect(user.videoQuota).to.equal(5 * 1024 * 1024) + }) + + it('Should have created the channel', async function () { + const { displayName } = await server.channels.get({ channelName: 'my_user_1_channel' }) + + expect(displayName).to.equal('my channel rocks') + }) + + it('Should remove me', async function () { + { + const { data } = await server.users.list() + expect(data.find(u => u.username === 'user_1')).to.not.be.undefined + } + + await server.users.deleteMe({ token: user1Token }) + + { + const { data } = await server.users.list() + expect(data.find(u => u.username === 'user_1')).to.be.undefined + } + }) + }) + + describe('Registration requests', function () { + let id2: number + let id3: number + let id4: number + + let user2Token: string + let user3Token: string + + before(async function () { + this.timeout(60000) + + await server.config.enableSignup(true) + + { + const { id } = await server.registrations.requestRegistration({ + username: 'user4', + registrationReason: 'registration reason 4' + }) + + id4 = id + } + }) + + it('Should request a registration without a channel', async function () { + { + const { id } = await server.registrations.requestRegistration({ + username: 'user2', + displayName: 'my super user 2', + email: 'user2@example.com', + password: 'user2password', + registrationReason: 'registration reason 2' + }) + + id2 = id + } + }) + + it('Should request a registration with a channel', async function () { + const { id } = await server.registrations.requestRegistration({ + username: 'user3', + displayName: 'my super user 3', + channel: { + displayName: 'my user 3 channel', + name: 'super_user3_channel' + }, + email: 'user3@example.com', + password: 'user3password', + registrationReason: 'registration reason 3' + }) + + id3 = id + }) + + it('Should list these registration requests', async function () { + { + const { total, data } = await server.registrations.list({ sort: '-createdAt' }) + expect(total).to.equal(3) + expect(data).to.have.lengthOf(3) + + { + expect(data[0].id).to.equal(id3) + expect(data[0].username).to.equal('user3') + expect(data[0].accountDisplayName).to.equal('my super user 3') + + expect(data[0].channelDisplayName).to.equal('my user 3 channel') + expect(data[0].channelHandle).to.equal('super_user3_channel') + + expect(data[0].createdAt).to.exist + expect(data[0].updatedAt).to.exist + + expect(data[0].email).to.equal('user3@example.com') + expect(data[0].emailVerified).to.be.null + + expect(data[0].moderationResponse).to.be.null + expect(data[0].registrationReason).to.equal('registration reason 3') + expect(data[0].state.id).to.equal(UserRegistrationState.PENDING) + expect(data[0].state.label).to.equal('Pending') + expect(data[0].user).to.be.null + } + + { + expect(data[1].id).to.equal(id2) + expect(data[1].username).to.equal('user2') + expect(data[1].accountDisplayName).to.equal('my super user 2') + + expect(data[1].channelDisplayName).to.be.null + expect(data[1].channelHandle).to.be.null + + expect(data[1].createdAt).to.exist + expect(data[1].updatedAt).to.exist + + expect(data[1].email).to.equal('user2@example.com') + expect(data[1].emailVerified).to.be.null + + expect(data[1].moderationResponse).to.be.null + expect(data[1].registrationReason).to.equal('registration reason 2') + expect(data[1].state.id).to.equal(UserRegistrationState.PENDING) + expect(data[1].state.label).to.equal('Pending') + expect(data[1].user).to.be.null + } + + { + expect(data[2].username).to.equal('user4') + } + } + + { + const { total, data } = await server.registrations.list({ count: 1, start: 1, sort: 'createdAt' }) + + expect(total).to.equal(3) + expect(data).to.have.lengthOf(1) + expect(data[0].id).to.equal(id2) + } + + { + const { total, data } = await server.registrations.list({ search: 'user3' }) + expect(total).to.equal(1) + expect(data).to.have.lengthOf(1) + expect(data[0].id).to.equal(id3) + } + }) + + it('Should reject a registration request', async function () { + await server.registrations.reject({ id: id4, moderationResponse: 'I do not want id 4 on this instance' }) + }) + + it('Should have sent an email to the user explanining the registration has been rejected', async function () { + this.timeout(50000) + + await waitJobs([ server ]) + + const email = emails.find(e => e['to'][0]['address'] === 'user4@example.com') + expect(email).to.exist + + expect(email['subject']).to.contain('been rejected') + expect(email['text']).to.contain('been rejected') + expect(email['text']).to.contain('I do not want id 4 on this instance') + }) + + it('Should accept registration requests', async function () { + await server.registrations.accept({ id: id2, moderationResponse: 'Welcome id 2' }) + await server.registrations.accept({ id: id3, moderationResponse: 'Welcome id 3' }) + }) + + it('Should have sent an email to the user explanining the registration has been accepted', async function () { + this.timeout(50000) + + await waitJobs([ server ]) + + { + const email = emails.find(e => e['to'][0]['address'] === 'user2@example.com') + expect(email).to.exist + + expect(email['subject']).to.contain('been accepted') + expect(email['text']).to.contain('been accepted') + expect(email['text']).to.contain('Welcome id 2') + } + + { + const email = emails.find(e => e['to'][0]['address'] === 'user3@example.com') + expect(email).to.exist + + expect(email['subject']).to.contain('been accepted') + expect(email['text']).to.contain('been accepted') + expect(email['text']).to.contain('Welcome id 3') + } + }) + + it('Should login with these users', async function () { + user2Token = await server.login.getAccessToken({ username: 'user2', password: 'user2password' }) + user3Token = await server.login.getAccessToken({ username: 'user3', password: 'user3password' }) + }) + + it('Should have created the appropriate attributes for user 2', async function () { + const me = await server.users.getMyInfo({ token: user2Token }) + + expect(me.username).to.equal('user2') + expect(me.account.displayName).to.equal('my super user 2') + expect(me.videoQuota).to.equal(5 * 1024 * 1024) + expect(me.videoChannels[0].name).to.equal('user2_channel') + expect(me.videoChannels[0].displayName).to.equal('Main user2 channel') + expect(me.role.id).to.equal(UserRole.USER) + expect(me.email).to.equal('user2@example.com') + }) + + it('Should have created the appropriate attributes for user 3', async function () { + const me = await server.users.getMyInfo({ token: user3Token }) + + expect(me.username).to.equal('user3') + expect(me.account.displayName).to.equal('my super user 3') + expect(me.videoQuota).to.equal(5 * 1024 * 1024) + expect(me.videoChannels[0].name).to.equal('super_user3_channel') + expect(me.videoChannels[0].displayName).to.equal('my user 3 channel') + expect(me.role.id).to.equal(UserRole.USER) + expect(me.email).to.equal('user3@example.com') + }) + + it('Should list these accepted/rejected registration requests', async function () { + const { data } = await server.registrations.list({ sort: 'createdAt' }) + const { data: users } = await server.users.list() + + { + expect(data[0].id).to.equal(id4) + expect(data[0].state.id).to.equal(UserRegistrationState.REJECTED) + expect(data[0].state.label).to.equal('Rejected') + + expect(data[0].moderationResponse).to.equal('I do not want id 4 on this instance') + expect(data[0].user).to.be.null + + expect(users.find(u => u.username === 'user4')).to.not.exist + } + + { + expect(data[1].id).to.equal(id2) + expect(data[1].state.id).to.equal(UserRegistrationState.ACCEPTED) + expect(data[1].state.label).to.equal('Accepted') + + expect(data[1].moderationResponse).to.equal('Welcome id 2') + expect(data[1].user).to.exist + + const user2 = users.find(u => u.username === 'user2') + expect(data[1].user.id).to.equal(user2.id) + } + + { + expect(data[2].id).to.equal(id3) + expect(data[2].state.id).to.equal(UserRegistrationState.ACCEPTED) + expect(data[2].state.label).to.equal('Accepted') + + expect(data[2].moderationResponse).to.equal('Welcome id 3') + expect(data[2].user).to.exist + + const user3 = users.find(u => u.username === 'user3') + expect(data[2].user.id).to.equal(user3.id) + } + }) + + it('Shoulde delete a registration', async function () { + await server.registrations.delete({ id: id2 }) + await server.registrations.delete({ id: id3 }) + + const { total, data } = await server.registrations.list() + expect(total).to.equal(1) + expect(data).to.have.lengthOf(1) + expect(data[0].id).to.equal(id4) + + const { data: users } = await server.users.list() + + for (const username of [ 'user2', 'user3' ]) { + expect(users.find(u => u.username === username)).to.exist + } + }) + + it('Should request a registration without a channel, that will conflict with an already existing channel', async function () { + let id1: number + let id2: number + + { + const { id } = await server.registrations.requestRegistration({ + registrationReason: 'tt', + username: 'user5', + password: 'user5password', + channel: { + displayName: 'channel 6', + name: 'user6_channel' + } + }) + + id1 = id + } + + { + const { id } = await server.registrations.requestRegistration({ + registrationReason: 'tt', + username: 'user6', + password: 'user6password' + }) + + id2 = id + } + + await server.registrations.accept({ id: id1, moderationResponse: 'tt' }) + await server.registrations.accept({ id: id2, moderationResponse: 'tt' }) + + const user5Token = await server.login.getAccessToken('user5', 'user5password') + const user6Token = await server.login.getAccessToken('user6', 'user6password') + + const user5 = await server.users.getMyInfo({ token: user5Token }) + const user6 = await server.users.getMyInfo({ token: user6Token }) + + expect(user5.videoChannels[0].name).to.equal('user6_channel') + expect(user6.videoChannels[0].name).to.equal('user6_channel-1') + }) + }) + + after(async function () { + MockSmtpServer.Instance.kill() + + await cleanupTests([ server ]) + }) +}) diff --git a/server/tests/api/users/users-email-verification.ts b/server/tests/api/users/users-email-verification.ts new file mode 100644 index 000000000..cb84dc758 --- /dev/null +++ b/server/tests/api/users/users-email-verification.ts @@ -0,0 +1,167 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { expect } from 'chai' +import { MockSmtpServer } from '@server/tests/shared' +import { HttpStatusCode } from '@shared/models' +import { + cleanupTests, + ConfigCommand, + createSingleServer, + PeerTubeServer, + setAccessTokensToServers, + waitJobs +} from '@shared/server-commands' + +describe('Test users email verification', function () { + let server: PeerTubeServer + let userId: number + let userAccessToken: string + let verificationString: string + let expectedEmailsLength = 0 + const user1 = { + username: 'user_1', + password: 'super password' + } + const user2 = { + username: 'user_2', + password: 'super password' + } + const emails: object[] = [] + + before(async function () { + this.timeout(30000) + + const port = await MockSmtpServer.Instance.collectEmails(emails) + server = await createSingleServer(1, ConfigCommand.getEmailOverrideConfig(port)) + + await setAccessTokensToServers([ server ]) + }) + + it('Should register user and send verification email if verification required', async function () { + this.timeout(30000) + + await server.config.updateExistingSubConfig({ + newConfig: { + signup: { + enabled: true, + requiresApproval: false, + requiresEmailVerification: true, + limit: 10 + } + } + }) + + await server.registrations.register(user1) + + await waitJobs(server) + expectedEmailsLength++ + expect(emails).to.have.lengthOf(expectedEmailsLength) + + const email = emails[expectedEmailsLength - 1] + + const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) + expect(verificationStringMatches).not.to.be.null + + verificationString = verificationStringMatches[1] + expect(verificationString).to.have.length.above(2) + + const userIdMatches = /userId=([0-9]+)/.exec(email['text']) + expect(userIdMatches).not.to.be.null + + userId = parseInt(userIdMatches[1], 10) + + const body = await server.users.get({ userId }) + expect(body.emailVerified).to.be.false + }) + + it('Should not allow login for user with unverified email', async function () { + const { detail } = await server.login.login({ user: user1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) + expect(detail).to.contain('User email is not verified.') + }) + + it('Should verify the user via email and allow login', async function () { + await server.users.verifyEmail({ userId, verificationString }) + + const body = await server.login.login({ user: user1 }) + userAccessToken = body.access_token + + const user = await server.users.get({ userId }) + expect(user.emailVerified).to.be.true + }) + + it('Should be able to change the user email', async function () { + this.timeout(10000) + + let updateVerificationString: string + + { + await server.users.updateMe({ + token: userAccessToken, + email: 'updated@example.com', + currentPassword: user1.password + }) + + await waitJobs(server) + expectedEmailsLength++ + expect(emails).to.have.lengthOf(expectedEmailsLength) + + const email = emails[expectedEmailsLength - 1] + + const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) + updateVerificationString = verificationStringMatches[1] + } + + { + const me = await server.users.getMyInfo({ token: userAccessToken }) + expect(me.email).to.equal('user_1@example.com') + expect(me.pendingEmail).to.equal('updated@example.com') + } + + { + await server.users.verifyEmail({ userId, verificationString: updateVerificationString, isPendingEmail: true }) + + const me = await server.users.getMyInfo({ token: userAccessToken }) + expect(me.email).to.equal('updated@example.com') + expect(me.pendingEmail).to.be.null + } + }) + + it('Should register user not requiring email verification if setting not enabled', async function () { + this.timeout(5000) + await server.config.updateExistingSubConfig({ + newConfig: { + signup: { + requiresEmailVerification: false + } + } + }) + + await server.registrations.register(user2) + + await waitJobs(server) + expect(emails).to.have.lengthOf(expectedEmailsLength) + + const accessToken = await server.login.getAccessToken(user2) + + const user = await server.users.getMyInfo({ token: accessToken }) + expect(user.emailVerified).to.be.null + }) + + it('Should allow login for user with unverified email when setting later enabled', async function () { + await server.config.updateCustomSubConfig({ + newConfig: { + signup: { + requiresEmailVerification: true + } + } + }) + + await server.login.getAccessToken(user2) + }) + + after(async function () { + MockSmtpServer.Instance.kill() + + await cleanupTests([ server ]) + }) +}) diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts deleted file mode 100644 index 19a8df9e1..000000000 --- a/server/tests/api/users/users-verification.ts +++ /dev/null @@ -1,170 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { MockSmtpServer } from '@server/tests/shared' -import { HttpStatusCode } from '@shared/models' -import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' - -describe('Test users account verification', function () { - let server: PeerTubeServer - let userId: number - let userAccessToken: string - let verificationString: string - let expectedEmailsLength = 0 - const user1 = { - username: 'user_1', - password: 'super password' - } - const user2 = { - username: 'user_2', - password: 'super password' - } - const emails: object[] = [] - - before(async function () { - this.timeout(30000) - - const port = await MockSmtpServer.Instance.collectEmails(emails) - - const overrideConfig = { - smtp: { - hostname: '127.0.0.1', - port - } - } - server = await createSingleServer(1, overrideConfig) - - await setAccessTokensToServers([ server ]) - }) - - it('Should register user and send verification email if verification required', async function () { - this.timeout(30000) - - await server.config.updateCustomSubConfig({ - newConfig: { - signup: { - enabled: true, - requiresEmailVerification: true, - limit: 10 - } - } - }) - - await server.users.register(user1) - - await waitJobs(server) - expectedEmailsLength++ - expect(emails).to.have.lengthOf(expectedEmailsLength) - - const email = emails[expectedEmailsLength - 1] - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - expect(verificationStringMatches).not.to.be.null - - verificationString = verificationStringMatches[1] - expect(verificationString).to.have.length.above(2) - - const userIdMatches = /userId=([0-9]+)/.exec(email['text']) - expect(userIdMatches).not.to.be.null - - userId = parseInt(userIdMatches[1], 10) - - const body = await server.users.get({ userId }) - expect(body.emailVerified).to.be.false - }) - - it('Should not allow login for user with unverified email', async function () { - const { detail } = await server.login.login({ user: user1, expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) - expect(detail).to.contain('User email is not verified.') - }) - - it('Should verify the user via email and allow login', async function () { - await server.users.verifyEmail({ userId, verificationString }) - - const body = await server.login.login({ user: user1 }) - userAccessToken = body.access_token - - const user = await server.users.get({ userId }) - expect(user.emailVerified).to.be.true - }) - - it('Should be able to change the user email', async function () { - this.timeout(10000) - - let updateVerificationString: string - - { - await server.users.updateMe({ - token: userAccessToken, - email: 'updated@example.com', - currentPassword: user1.password - }) - - await waitJobs(server) - expectedEmailsLength++ - expect(emails).to.have.lengthOf(expectedEmailsLength) - - const email = emails[expectedEmailsLength - 1] - - const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) - updateVerificationString = verificationStringMatches[1] - } - - { - const me = await server.users.getMyInfo({ token: userAccessToken }) - expect(me.email).to.equal('user_1@example.com') - expect(me.pendingEmail).to.equal('updated@example.com') - } - - { - await server.users.verifyEmail({ userId, verificationString: updateVerificationString, isPendingEmail: true }) - - const me = await server.users.getMyInfo({ token: userAccessToken }) - expect(me.email).to.equal('updated@example.com') - expect(me.pendingEmail).to.be.null - } - }) - - it('Should register user not requiring email verification if setting not enabled', async function () { - this.timeout(5000) - await server.config.updateCustomSubConfig({ - newConfig: { - signup: { - enabled: true, - requiresEmailVerification: false, - limit: 10 - } - } - }) - - await server.users.register(user2) - - await waitJobs(server) - expect(emails).to.have.lengthOf(expectedEmailsLength) - - const accessToken = await server.login.getAccessToken(user2) - - const user = await server.users.getMyInfo({ token: accessToken }) - expect(user.emailVerified).to.be.null - }) - - it('Should allow login for user with unverified email when setting later enabled', async function () { - await server.config.updateCustomSubConfig({ - newConfig: { - signup: { - enabled: true, - requiresEmailVerification: true, - limit: 10 - } - } - }) - - await server.login.getAccessToken(user2) - }) - - after(async function () { - MockSmtpServer.Instance.kill() - - await cleanupTests([ server ]) - }) -}) diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 93e2e489a..f1e170971 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts @@ -429,56 +429,6 @@ describe('Test users', function () { }) }) - describe('Registering a new user', function () { - let user15AccessToken: string - - it('Should register a new user', async function () { - const user = { displayName: 'super user 15', username: 'user_15', password: 'my super password' } - const channel = { name: 'my_user_15_channel', displayName: 'my channel rocks' } - - await server.users.register({ ...user, channel }) - }) - - it('Should be able to login with this registered user', async function () { - const user15 = { - username: 'user_15', - password: 'my super password' - } - - user15AccessToken = await server.login.getAccessToken(user15) - }) - - it('Should have the correct display name', async function () { - const user = await server.users.getMyInfo({ token: user15AccessToken }) - expect(user.account.displayName).to.equal('super user 15') - }) - - it('Should have the correct video quota', async function () { - const user = await server.users.getMyInfo({ token: user15AccessToken }) - expect(user.videoQuota).to.equal(5 * 1024 * 1024) - }) - - it('Should have created the channel', async function () { - const { displayName } = await server.channels.get({ channelName: 'my_user_15_channel' }) - - expect(displayName).to.equal('my channel rocks') - }) - - it('Should remove me', async function () { - { - const { data } = await server.users.list() - expect(data.find(u => u.username === 'user_15')).to.not.be.undefined - } - - await server.users.deleteMe({ token: user15AccessToken }) - - { - const { data } = await server.users.list() - expect(data.find(u => u.username === 'user_15')).to.be.undefined - } - }) - }) - describe('User blocking', function () { let user16Id: number let user16AccessToken: string -- cgit v1.2.3