From af2744885fd047467b948c5414d308487c49abc4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 22 Dec 2020 16:56:02 +0100 Subject: [PATCH 1/7] added the first login tests ref #45 --- src/tests/auth/auth_login.spec.ts | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/tests/auth/auth_login.spec.ts diff --git a/src/tests/auth/auth_login.spec.ts b/src/tests/auth/auth_login.spec.ts new file mode 100644 index 0000000..dcb5d99 --- /dev/null +++ b/src/tests/auth/auth_login.spec.ts @@ -0,0 +1,49 @@ +import axios from 'axios'; +import { config } from '../../config'; +const base = "http://localhost:" + config.internal_port + +let axios_config; + +beforeAll(async () => { + axios_config = { + validateStatus: undefined + }; +}); + +describe('POST /api/auth/login valid', () => { + it('valid login should return 200', async () => { + const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }, axios_config); + expect(res.status).toEqual(200); + expect(res.headers['content-type']).toContain("application/json") + }); +}); +// --------------- +describe('POST /api/auth/login invalid body', () => { + it('Loging without a body should return 400', async () => { + const res = await axios.post(base + '/api/auth/login', null, axios_config); + expect(res.status).toEqual(400); + }); + it('Loging without a password should return 400', async () => { + const res = await axios.post(base + '/api/auth/login', { username: "demo" }, axios_config); + expect(res.status).toEqual(400); + }); + it('Loging with invalid mail format should return 400', async () => { + const res = await axios.post(base + '/api/auth/login', { email: "demo", password: "demo" }, axios_config); + expect(res.status).toEqual(400); + }); + it('Loging without a username/mail should return 404', async () => { + const res = await axios.post(base + '/api/auth/login', { password: "demo" }, axios_config); + expect(res.status).toEqual(404); + }); +}); +// --------------- +describe('POST /api/auth/login nonexistant user', () => { + it('login with nonexistant username should return 404', async () => { + const res = await axios.post(base + '/api/auth/login', { username: "-1", password: "demo" }, axios_config); + expect(res.status).toEqual(404); + }); + it('login with nonexistant mail should return 404', async () => { + const res = await axios.post(base + '/api/auth/login', { email: "test@example.com", password: "demo" }, axios_config); + expect(res.status).toEqual(404); + }); +}); \ No newline at end of file From 69796a888fa9a2f108717d320d5005db388e67b6 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 22 Dec 2020 17:04:22 +0100 Subject: [PATCH 2/7] Added wron password auth test ref #45 --- src/tests/auth/auth_login.spec.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tests/auth/auth_login.spec.ts b/src/tests/auth/auth_login.spec.ts index dcb5d99..f0c49a9 100644 --- a/src/tests/auth/auth_login.spec.ts +++ b/src/tests/auth/auth_login.spec.ts @@ -46,4 +46,11 @@ describe('POST /api/auth/login nonexistant user', () => { const res = await axios.post(base + '/api/auth/login', { email: "test@example.com", password: "demo" }, axios_config); expect(res.status).toEqual(404); }); +}); +// --------------- +describe('POST /api/auth/login wrong password', () => { + it('login with wrong password should return 401', async () => { + const res = await axios.post(base + '/api/auth/login', { username: "demo", password: "totallynotthecorrectpassword" }, axios_config); + expect(res.status).toEqual(401); + }); }); \ No newline at end of file From 3c003a60b207d744a6763fc8605abeadd07d81fc Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 22 Dec 2020 18:26:20 +0100 Subject: [PATCH 3/7] Added logut tests ref #45 --- src/tests/auth/auth_logout.spec.ts | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/tests/auth/auth_logout.spec.ts diff --git a/src/tests/auth/auth_logout.spec.ts b/src/tests/auth/auth_logout.spec.ts new file mode 100644 index 0000000..9cf997b --- /dev/null +++ b/src/tests/auth/auth_logout.spec.ts @@ -0,0 +1,49 @@ +import axios from 'axios'; +import { config } from '../../config'; + +const base = "http://localhost:" + config.internal_port + +const axios_config = { + validateStatus: undefined +};; + +beforeAll(async () => { + const res_login = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); + await axios.post(base + '/api/users', { + "firstname": "demo_logout", + "middlename": "demo_logout", + "lastname": "demo_logout", + "username": "demo_logout", + "password": "demo_logout" + }, { + headers: { "authorization": "Bearer " + res_login.data["access_token"] }, + validateStatus: undefined + }); +}); + +describe('POST /api/auth/logout valid', () => { + it('valid logout with token in cookie should return 200', async () => { + const res_login = await axios.post(base + '/api/auth/login', { username: "demo_logout", password: "demo_logout" }); + const res = await axios.post(base + '/api/auth/logout', null, { + headers: { "Cookie": res_login.headers["set-cookie"] }, + validateStatus: undefined + }); + expect(res.status).toEqual(200); + }); + it('valid logout with token in body should return 200', async () => { + const res_login = await axios.post(base + '/api/auth/login', { username: "demo_logout", password: "demo_logout" }); + const res = await axios.post(base + '/api/auth/logout', { token: res_login.data["refresh_token"] }, axios_config); + expect(res.status).toEqual(200); + }); +}); +// --------------- +describe('POST /api/auth/logout ivalid', () => { + it('invalid logout without token should return 406', async () => { + const res = await axios.post(base + '/api/auth/logout', null, axios_config); + expect(res.status).toEqual(406); + }); + it('invalid logout with invalid token in body should return 401', async () => { + const res = await axios.post(base + '/api/auth/logout', { token: "1" }, axios_config); + expect(res.status).toEqual(401); + }); +}); \ No newline at end of file From 13949af938ccc1897e3692c3facb2fefb2ed4a7b Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 22 Dec 2020 18:29:23 +0100 Subject: [PATCH 4/7] Added auth refresh tests ref #45 --- src/tests/auth/auth_refresh.spec.ts | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/tests/auth/auth_refresh.spec.ts diff --git a/src/tests/auth/auth_refresh.spec.ts b/src/tests/auth/auth_refresh.spec.ts new file mode 100644 index 0000000..02d2a02 --- /dev/null +++ b/src/tests/auth/auth_refresh.spec.ts @@ -0,0 +1,49 @@ +import axios from 'axios'; +import { config } from '../../config'; + +const base = "http://localhost:" + config.internal_port + +const axios_config = { + validateStatus: undefined +};; + +beforeAll(async () => { + const res_login = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); + await axios.post(base + '/api/users', { + "firstname": "demo_refresh", + "middlename": "demo_refresh", + "lastname": "demo_refresh", + "username": "demo_refresh", + "password": "demo_refresh" + }, { + headers: { "authorization": "Bearer " + res_login.data["access_token"] }, + validateStatus: undefined + }); +}); + +describe('POST /api/auth/refresh valid', () => { + it('valid refresh with token in cookie should return 200', async () => { + const res_login = await axios.post(base + '/api/auth/login', { username: "demo_refresh", password: "demo_refresh" }); + const res = await axios.post(base + '/api/auth/refresh', null, { + headers: { "Cookie": res_login.headers["set-cookie"] }, + validateStatus: undefined + }); + expect(res.status).toEqual(200); + }); + it('valid refresh with token in body should return 200', async () => { + const res_login = await axios.post(base + '/api/auth/login', { username: "demo_refresh", password: "demo_refresh" }); + const res = await axios.post(base + '/api/auth/refresh', { token: res_login.data["refresh_token"] }, axios_config); + expect(res.status).toEqual(200); + }); +}); +// --------------- +describe('POST /api/auth/refresh ivalid', () => { + it('invalid refresh without token should return 406', async () => { + const res = await axios.post(base + '/api/auth/refresh', null, axios_config); + expect(res.status).toEqual(406); + }); + it('invalid refresh with invalid token in body should return 401', async () => { + const res = await axios.post(base + '/api/auth/refresh', { token: "1" }, axios_config); + expect(res.status).toEqual(401); + }); +}); \ No newline at end of file From c6ecde29b59119152f8c68f6e504a81c9e628208 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 22 Dec 2020 18:48:54 +0100 Subject: [PATCH 5/7] Added auth reset tests ref #45 --- src/tests/auth/auth_reset.spec.ts | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/tests/auth/auth_reset.spec.ts diff --git a/src/tests/auth/auth_reset.spec.ts b/src/tests/auth/auth_reset.spec.ts new file mode 100644 index 0000000..2ebb8ed --- /dev/null +++ b/src/tests/auth/auth_reset.spec.ts @@ -0,0 +1,75 @@ +import axios from 'axios'; +import { config } from '../../config'; + +const base = "http://localhost:" + config.internal_port + +const axios_config = { + validateStatus: undefined +};; + +beforeAll(async () => { + const res_login = await axios.post(base + '/api/auth/login', { username: "demo", password: "demo" }); + await axios.post(base + '/api/users', { + "firstname": "demo_reset", + "middlename": "demo_reset", + "lastname": "demo_reset", + "username": "demo_reset", + "password": "demo_reset" + }, { + headers: { "authorization": "Bearer " + res_login.data["access_token"] }, + validateStatus: undefined + }); + await axios.post(base + '/api/users', { + "firstname": "demo_reset2", + "middlename": "demo_reset2", + "lastname": "demo_reset2", + "username": "demo_reset2", + "password": "demo_reset2" + }, { + headers: { "authorization": "Bearer " + res_login.data["access_token"] }, + validateStatus: undefined + }); +}); + +describe('POST /api/auth/reset valid', () => { + let reset_token; + it('valid reset token request should return 200', async () => { + const res1 = await axios.post(base + '/api/auth/reset', { username: "demo_reset" }); + reset_token = res1.data.resetToken; + expect(res1.status).toEqual(200); + }); + it('valid password reset should return 200', async () => { + const res2 = await axios.post(base + '/api/auth/reset/' + reset_token, { password: "demo" }, axios_config); + expect(res2.status).toEqual(200); + }); + it('valid login after reset should return 200', async () => { + const res = await axios.post(base + '/api/auth/login', { username: "demo_reset", password: "demo" }); + expect(res.status).toEqual(200); + }); +}); +// --------------- +describe('POST /api/auth/reset invalid requests', () => { + it('request another password reset before the timeout should return 406', async () => { + const res1 = await axios.post(base + '/api/auth/reset', { username: "demo_reset2" }, axios_config); + const res2 = await axios.post(base + '/api/auth/reset', { username: "demo_reset2" }, axios_config); + expect(res2.status).toEqual(406); + }); +}); +// --------------- +describe('POST /api/auth/reset invalid token', () => { + it('providing a invalid reset token should return 401', async () => { + const res2 = await axios.post(base + '/api/auth/reset/' + "123123", { password: "demo" }, axios_config); + expect(res2.status).toEqual(401); + }); + it('providing no reset token should return 404', async () => { + const res2 = await axios.post(base + '/api/auth/reset/' + "", { password: "demo" }, axios_config); + expect(res2.status).toEqual(404); + }); +}); +// --------------- +describe('POST /api/auth/reset invalid body', () => { + it('providing no password should return 400', async () => { + const res2 = await axios.post(base + '/api/auth/reset/' + "123123", null, axios_config); + expect(res2.status).toEqual(400); + }); +}); \ No newline at end of file From a9dbf1d0d2cb79b75707b91462d043a66c8f64a0 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 22 Dec 2020 18:49:10 +0100 Subject: [PATCH 6/7] Added login test after logout ref #45 --- src/tests/auth/auth_logout.spec.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tests/auth/auth_logout.spec.ts b/src/tests/auth/auth_logout.spec.ts index 9cf997b..7c846c1 100644 --- a/src/tests/auth/auth_logout.spec.ts +++ b/src/tests/auth/auth_logout.spec.ts @@ -22,10 +22,12 @@ beforeAll(async () => { }); describe('POST /api/auth/logout valid', () => { + let refresh_coookie; it('valid logout with token in cookie should return 200', async () => { const res_login = await axios.post(base + '/api/auth/login', { username: "demo_logout", password: "demo_logout" }); + refresh_coookie = res_login.headers["set-cookie"]; const res = await axios.post(base + '/api/auth/logout', null, { - headers: { "Cookie": res_login.headers["set-cookie"] }, + headers: { "Cookie": refresh_coookie }, validateStatus: undefined }); expect(res.status).toEqual(200); @@ -35,6 +37,13 @@ describe('POST /api/auth/logout valid', () => { const res = await axios.post(base + '/api/auth/logout', { token: res_login.data["refresh_token"] }, axios_config); expect(res.status).toEqual(200); }); + it('getting users after valid logout should return 401', async () => { + const res = await axios.get(base + '/api/users', { + headers: { "Cookie": refresh_coookie }, + validateStatus: undefined + }); + expect(res.status).toEqual(401); + }); }); // --------------- describe('POST /api/auth/logout ivalid', () => { From a4ddeee8e4fdabd5ef7abb42a2688508f6a683eb Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 22 Dec 2020 19:38:12 +0100 Subject: [PATCH 7/7] Fixed uniqueness error ref #45 --- src/models/entities/User.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/models/entities/User.ts b/src/models/entities/User.ts index 57bdf5c..a176934 100644 --- a/src/models/entities/User.ts +++ b/src/models/entities/User.ts @@ -106,7 +106,7 @@ export class User extends Principal { * The user's profile picture. * We haven't decided yet if this will be a bas64 encoded image or just a link to the profile picture. */ - @Column({ nullable: true, unique: true }) + @Column({ nullable: true, unique: false }) @IsString() @IsOptional() profilePic?: string; @@ -115,7 +115,7 @@ export class User extends Principal { * The last time the user requested a password reset. * Used to prevent spamming of the password reset route. */ - @Column({ nullable: true, unique: true }) + @Column({ nullable: true, unique: false }) @IsString() @IsOptional() resetRequestedTimestamp?: number;