From 60e83b56d1c4b656d5025a80a904bed3a778a681 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 12:56:58 +0100 Subject: [PATCH 01/10] feat: Test Logout --- .../src/graphql/resolver/UserResolver.test.ts | 117 +++++++++++++++--- backend/src/graphql/resolver/UserResolver.ts | 12 ++ backend/test/helpers.ts | 10 +- 3 files changed, 116 insertions(+), 23 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index fd0936b9a..570f09823 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { testEnvironment, createUser, headerPushMock, cleanDB } from '@test/helpers' +import { testEnvironment, createUser, headerPushMock, cleanDB, resetToken } from '@test/helpers' import { createUserMutation, setPasswordMutation } from '@test/graphql' import gql from 'graphql-tag' import { GraphQLError } from 'graphql' @@ -31,6 +31,24 @@ jest.mock('@/apis/KlicktippController', () => { let mutate: any, query: any, con: any +const loginQuery = gql` + query ($email: String!, $password: String!, $publisherId: Int) { + login(email: $email, password: $password, publisherId: $publisherId) { + email + firstName + lastName + language + coinanimation + klickTipp { + newsletterState + } + hasElopage + publisherId + isAdmin + } + } +` + beforeAll(async () => { const testEnv = await testEnvironment() mutate = testEnv.mutate @@ -284,24 +302,6 @@ describe('UserResolver', () => { }) describe('login', () => { - const loginQuery = gql` - query ($email: String!, $password: String!, $publisherId: Int) { - login(email: $email, password: $password, publisherId: $publisherId) { - email - firstName - lastName - language - coinanimation - klickTipp { - newsletterState - } - hasElopage - publisherId - isAdmin - } - } - ` - const variables = { email: 'peter@lustig.de', password: 'Aa12345_', @@ -328,7 +328,7 @@ describe('UserResolver', () => { }) }) - describe('user is in database', () => { + describe('user is in database and correct login data', () => { beforeAll(async () => { await createUser(mutate, { email: 'peter@lustig.de', @@ -370,5 +370,82 @@ describe('UserResolver', () => { expect(headerPushMock).toBeCalledWith({ key: 'token', value: expect.any(String) }) }) }) + + describe('user is in database and wrong password', () => { + beforeAll(async () => { + resetToken() + await createUser(mutate, { + email: 'peter@lustig.de', + firstName: 'Peter', + lastName: 'Lustig', + language: 'de', + publisherId: 1234, + }) + }) + + afterAll(async () => { + await cleanDB() + }) + + it('returns an error', () => { + expect( + query({ query: loginQuery, variables: { ...variables, password: 'wrong' } }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('No user with this credentials')], + }), + ) + }) + }) + }) + + describe('logout', () => { + const logoutQuery = gql` + query { + logout + } + ` + + describe('unauthenticated', () => { + it('throws an error', async () => { + await expect(query({ query: logoutQuery })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + const variables = { + email: 'peter@lustig.de', + password: 'Aa12345_', + } + + beforeAll(async () => { + resetToken() + await createUser(mutate, { + email: 'peter@lustig.de', + firstName: 'Peter', + lastName: 'Lustig', + language: 'de', + publisherId: 1234, + }) + await query({ query: loginQuery, variables }) + }) + + afterAll(async () => { + await cleanDB() + }) + + it('returns true', async () => { + await expect(query({ query: logoutQuery })).resolves.toEqual( + expect.objectContaining({ + data: { logout: 'true' }, + errors: undefined, + }), + ) + }) + }) }) }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 4d1454e86..9896ddc97 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -373,6 +373,8 @@ export class UserResolver { /{code}/g, emailOptIn.verificationCode.toString(), ) + + // eslint-disable-next-line @typescript-eslint/no-unused-vars const emailSent = await sendAccountActivationEmail({ link: activationLink, firstName, @@ -380,11 +382,13 @@ export class UserResolver { email, }) + /* uncomment this, when you need the activation link on the console // In case EMails are disabled log the activation link for the user if (!emailSent) { // eslint-disable-next-line no-console console.log(`Account confirmation link: ${activationLink}`) } + */ await queryRunner.commitTransaction() } catch (e) { await queryRunner.rollbackTransaction() @@ -414,6 +418,7 @@ export class UserResolver { emailOptIn.verificationCode.toString(), ) + // eslint-disable-next-line @typescript-eslint/no-unused-vars const emailSent = await sendAccountActivationEmail({ link: activationLink, firstName: user.firstName, @@ -421,11 +426,13 @@ export class UserResolver { email, }) + /* uncomment this, when you need the activation link on the console // In case EMails are disabled log the activation link for the user if (!emailSent) { // eslint-disable-next-line no-console console.log(`Account confirmation link: ${activationLink}`) } + */ await queryRunner.commitTransaction() } catch (e) { await queryRunner.rollbackTransaction() @@ -450,6 +457,7 @@ export class UserResolver { optInCode.verificationCode.toString(), ) + // eslint-disable-next-line @typescript-eslint/no-unused-vars const emailSent = await sendResetPasswordEmail({ link, firstName: user.firstName, @@ -457,11 +465,13 @@ export class UserResolver { email, }) + /* uncomment this, when you need the activation link on the console // In case EMails are disabled log the activation link for the user if (!emailSent) { // eslint-disable-next-line no-console console.log(`Reset password link: ${link}`) } + */ return true } @@ -551,7 +561,9 @@ export class UserResolver { } catch { // TODO is this a problem? // eslint-disable-next-line no-console + /* uncomment this, when you need the activation link on the console console.log('Could not subscribe to klicktipp') + */ } } diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index 1048b16b7..0154f268a 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -9,12 +9,16 @@ import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' import { entities } from '@entity/index' -let token = '' +export const headerPushMock = jest.fn((t) => { + context.token = t.value +}) -export const headerPushMock = jest.fn((t) => (token = t.value)) +export const resetToken = () => { + context.token = '' +} const context = { - token, + token: '', setHeaders: { push: headerPushMock, forEach: jest.fn(), From 1dd9f522599a5d957374f9450869c861b9790eae Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 13:50:30 +0100 Subject: [PATCH 02/10] try to fix the token reset --- backend/src/graphql/directive/isAuthorized.ts | 8 ++++++++ backend/src/graphql/resolver/UserResolver.test.ts | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index aa407c95f..4a31dfede 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -13,6 +13,8 @@ import { ServerUser } from '@entity/ServerUser' const isAuthorized: AuthChecker = async ({ context }, rights) => { context.role = ROLE_UNAUTHORIZED // unauthorized user + // moriz: I think it is better to check the INALIENABLE_RIGHTS here + // Do we have a token? if (context.token) { // Decode the token @@ -33,6 +35,12 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { } // Set context pubKey context.pubKey = Buffer.from(decoded.pubKey).toString('hex') + + // Problem found by unit testing: + // I have a valid token in the context, but the database is cleaned, + // so the user object cannot be found here + // this should be working for inalienable rights + // set new header token // TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests // TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 570f09823..9b2db42e8 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -373,7 +373,7 @@ describe('UserResolver', () => { describe('user is in database and wrong password', () => { beforeAll(async () => { - resetToken() + // resetToken() await createUser(mutate, { email: 'peter@lustig.de', firstName: 'Peter', From 35cc38ba7c2aa2f03682d7f5893042faaaf67385 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 14:15:24 +0100 Subject: [PATCH 03/10] introduce reset token, comment isAuthorized --- backend/src/graphql/directive/isAuthorized.ts | 6 ++++++ backend/src/graphql/resolver/UserResolver.test.ts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 4a31dfede..c72a52ac4 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -14,6 +14,12 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { context.role = ROLE_UNAUTHORIZED // unauthorized user // moriz: I think it is better to check the INALIENABLE_RIGHTS here + /* + if ((rights).reduce( + (acc, right) => acc && INALIENABLE_RIGHTS.includes(right), + true, + )) return true + */ // Do we have a token? if (context.token) { diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 9b2db42e8..570f09823 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -373,7 +373,7 @@ describe('UserResolver', () => { describe('user is in database and wrong password', () => { beforeAll(async () => { - // resetToken() + resetToken() await createUser(mutate, { email: 'peter@lustig.de', firstName: 'Peter', From 109853d257d0d6f9a9a177f0bc5c647e60311194 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 14:21:40 +0100 Subject: [PATCH 04/10] reset token not exported --- backend/src/graphql/resolver/UserResolver.test.ts | 4 +--- backend/test/helpers.ts | 9 +++++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 570f09823..4b20f035d 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { testEnvironment, createUser, headerPushMock, cleanDB, resetToken } from '@test/helpers' +import { testEnvironment, createUser, headerPushMock, cleanDB } from '@test/helpers' import { createUserMutation, setPasswordMutation } from '@test/graphql' import gql from 'graphql-tag' import { GraphQLError } from 'graphql' @@ -373,7 +373,6 @@ describe('UserResolver', () => { describe('user is in database and wrong password', () => { beforeAll(async () => { - resetToken() await createUser(mutate, { email: 'peter@lustig.de', firstName: 'Peter', @@ -423,7 +422,6 @@ describe('UserResolver', () => { } beforeAll(async () => { - resetToken() await createUser(mutate, { email: 'peter@lustig.de', firstName: 'Peter', diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index 0154f268a..aa11d54e9 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -13,10 +13,6 @@ export const headerPushMock = jest.fn((t) => { context.token = t.value }) -export const resetToken = () => { - context.token = '' -} - const context = { token: '', setHeaders: { @@ -52,6 +48,7 @@ export const resetEntity = async (entity: any) => { } export const createUser = async (mutate: any, user: any) => { + resetToken() await mutate({ mutation: createUserMutation, variables: user }) const dbUser = await User.findOne({ where: { email: user.email } }) if (!dbUser) throw new Error('Ups, no user found') @@ -62,3 +59,7 @@ export const createUser = async (mutate: any, user: any) => { variables: { password: 'Aa12345_', code: optin.verificationCode }, }) } + +const resetToken = () => { + context.token = '' +} From e5215b56aa3f8f1f6796f7be5c1f365bc00cc836 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 15:18:45 +0100 Subject: [PATCH 05/10] do not reset db on start of database in backend unit tests --- backend/test/helpers.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index aa11d54e9..74addae3d 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -35,7 +35,6 @@ export const testEnvironment = async () => { const mutate = testClient.mutate const query = testClient.query await initialize() - await resetDB() return { mutate, query, con } } From ed84a1dd56bed2dcd0d5afdfac6d32e7b2599ed4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 15:35:39 +0100 Subject: [PATCH 06/10] no resetDB and test for inalienable rights first --- backend/src/graphql/directive/isAuthorized.ts | 23 ++++--------------- backend/test/helpers.ts | 2 +- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index c72a52ac4..f2d646cad 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -13,31 +13,16 @@ import { ServerUser } from '@entity/ServerUser' const isAuthorized: AuthChecker = async ({ context }, rights) => { context.role = ROLE_UNAUTHORIZED // unauthorized user - // moriz: I think it is better to check the INALIENABLE_RIGHTS here - /* - if ((rights).reduce( - (acc, right) => acc && INALIENABLE_RIGHTS.includes(right), - true, - )) return true - */ + // is rights an inalienable right? + if ((rights).reduce((acc, right) => acc && INALIENABLE_RIGHTS.includes(right), true)) + return true // Do we have a token? if (context.token) { // Decode the token const decoded = decode(context.token) if (!decoded) { - // Are all rights requested public? - const isInalienable = (rights).reduce( - (acc, right) => acc && INALIENABLE_RIGHTS.includes(right), - true, - ) - if (isInalienable) { - // If public dont throw and permit access - return true - } else { - // Throw on a protected route - throw new Error('403.13 - Client certificate revoked') - } + throw new Error('403.13 - Client certificate revoked') } // Set context pubKey context.pubKey = Buffer.from(decoded.pubKey).toString('hex') diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index 74addae3d..f5a6c902c 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -3,7 +3,7 @@ import { createTestClient } from 'apollo-server-testing' import createServer from '../src/server/createServer' -import { resetDB, initialize } from '@dbTools/helpers' +import { initialize } from '@dbTools/helpers' import { createUserMutation, setPasswordMutation } from './graphql' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { User } from '@entity/User' From bc29e3d6a622ad2fc72cb22b74d38152d79ece01 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 16:17:11 +0100 Subject: [PATCH 07/10] fix wrong db query in create user helper, improve isAuthorized, delete token to simulate unauthenticated --- backend/src/graphql/directive/isAuthorized.ts | 12 ++++++++---- backend/src/graphql/resolver/UserResolver.test.ts | 3 ++- backend/test/helpers.ts | 8 ++++---- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index f2d646cad..2c003d818 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -36,11 +36,15 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { // TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests // TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey const userRepository = await getCustomRepository(UserRepository) - const user = await userRepository.findByPubkeyHex(context.pubKey) - const countServerUsers = await ServerUser.count({ email: user.email }) - context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER + try { + const user = await userRepository.findByPubkeyHex(context.pubKey) + const countServerUsers = await ServerUser.count({ email: user.email }) + context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER - context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) }) + context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) }) + } catch { + throw new Error('401 Unauthorized') + } } // check for correct rights diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 4b20f035d..947636aa4 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { testEnvironment, createUser, headerPushMock, cleanDB } from '@test/helpers' +import { testEnvironment, createUser, headerPushMock, cleanDB, resetToken } from '@test/helpers' import { createUserMutation, setPasswordMutation } from '@test/graphql' import gql from 'graphql-tag' import { GraphQLError } from 'graphql' @@ -407,6 +407,7 @@ describe('UserResolver', () => { describe('unauthenticated', () => { it('throws an error', async () => { + resetToken() await expect(query({ query: logoutQuery })).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('401 Unauthorized')], diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index f5a6c902c..edb4eb3e4 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -39,7 +39,7 @@ export const testEnvironment = async () => { } export const resetEntity = async (entity: any) => { - const items = await entity.find() + const items = await entity.find({ withDeleted: true }) if (items.length > 0) { const ids = items.map((i: any) => i.id) await entity.delete(ids) @@ -47,11 +47,11 @@ export const resetEntity = async (entity: any) => { } export const createUser = async (mutate: any, user: any) => { - resetToken() + // resetToken() await mutate({ mutation: createUserMutation, variables: user }) const dbUser = await User.findOne({ where: { email: user.email } }) if (!dbUser) throw new Error('Ups, no user found') - const optin = await LoginEmailOptIn.findOne(dbUser.id) + const optin = await LoginEmailOptIn.findOne({ where: { userId: dbUser.id } }) if (!optin) throw new Error('Ups, no optin found') await mutate({ mutation: setPasswordMutation, @@ -59,6 +59,6 @@ export const createUser = async (mutate: any, user: any) => { }) } -const resetToken = () => { +export const resetToken = () => { context.token = '' } From fe38cec4acb2e437e44fdc96fc9a3ef92fe368be Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 16:22:57 +0100 Subject: [PATCH 08/10] further improvement of isAuthorized --- backend/src/graphql/directive/isAuthorized.ts | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 2c003d818..9a60fb10d 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -18,33 +18,27 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { return true // Do we have a token? - if (context.token) { - // Decode the token - const decoded = decode(context.token) - if (!decoded) { - throw new Error('403.13 - Client certificate revoked') - } - // Set context pubKey - context.pubKey = Buffer.from(decoded.pubKey).toString('hex') + if (!context.token) { + throw new Error('401 Unauthorized') + } - // Problem found by unit testing: - // I have a valid token in the context, but the database is cleaned, - // so the user object cannot be found here - // this should be working for inalienable rights + // Decode the token + const decoded = decode(context.token) + if (!decoded) { + throw new Error('403.13 - Client certificate revoked') + } + // Set context pubKey + context.pubKey = Buffer.from(decoded.pubKey).toString('hex') - // set new header token - // TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests - // TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey - const userRepository = await getCustomRepository(UserRepository) - try { - const user = await userRepository.findByPubkeyHex(context.pubKey) - const countServerUsers = await ServerUser.count({ email: user.email }) - context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER - - context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) }) - } catch { - throw new Error('401 Unauthorized') - } + // TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests + // TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey + const userRepository = await getCustomRepository(UserRepository) + try { + const user = await userRepository.findByPubkeyHex(context.pubKey) + const countServerUsers = await ServerUser.count({ email: user.email }) + context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER + } catch { + throw new Error('401 Unauthorized') } // check for correct rights @@ -53,6 +47,8 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { throw new Error('401 Unauthorized') } + // set new header token + context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) }) return true } From e7b104c3b5a1ca561967f6c28acbe0fb6fc1fa6c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 14 Mar 2022 16:27:36 +0100 Subject: [PATCH 09/10] Update backend/src/graphql/directive/isAuthorized.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/directive/isAuthorized.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 9a60fb10d..159a1614c 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -38,6 +38,7 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { const countServerUsers = await ServerUser.count({ email: user.email }) context.role = countServerUsers > 0 ? ROLE_ADMIN : ROLE_USER } catch { + // in case the database query fails (user deleted) throw new Error('401 Unauthorized') } From e706d994426d694865b22877a4c45a135d31f58e Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 14 Mar 2022 17:48:00 +0100 Subject: [PATCH 10/10] 54% backend coverage --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0739729b5..e9762b4bb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -528,7 +528,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 53 + min_coverage: 54 token: ${{ github.token }} ##########################################################################