separate validation function for alias, tested

This commit is contained in:
Moriz Wahl 2023-05-10 17:37:01 +02:00
parent b7ce0e277c
commit a82f0cb284
4 changed files with 163 additions and 114 deletions

View File

@ -1208,107 +1208,6 @@ describe('UserResolver', () => {
jest.clearAllMocks()
})
describe('too short', () => {
it('throws and logs an error', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
alias: 'bibi',
},
}),
).resolves.toMatchObject({
errors: [new GraphQLError('Given alias is too short')],
data: null,
})
expect(logger.error).toBeCalledWith('Given alias is too short', 'bibi')
})
})
describe('too long', () => {
it('throws and logs an error', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
alias: 'bibis_alias_far_too_long',
},
}),
).resolves.toMatchObject({
errors: [new GraphQLError('Given alias is too long')],
data: null,
})
expect(logger.error).toBeCalledWith(
'Given alias is too long',
'bibis_alias_far_too_long',
)
})
})
describe('invalid characters', () => {
it('throws and logs an error', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
alias: 'no+äöllll',
},
}),
).resolves.toMatchObject({
errors: [new GraphQLError('Invalid characters in alias')],
data: null,
})
expect(logger.error).toBeCalledWith('Invalid characters in alias', 'no+äöllll')
})
})
describe('alias exists', () => {
let peter: User
beforeAll(async () => {
peter = await userFactory(testEnv, peterLustig)
await mutate({
mutation: login,
variables: {
email: 'peter@lustig.de',
password: 'Aa12345_',
},
})
await mutate({
mutation: updateUserInfos,
variables: {
alias: 'bibiBloxberg',
},
})
await mutate({
mutation: login,
variables: {
email: 'bibi@bloxberg.de',
password: 'Aa12345_',
},
})
})
afterAll(async () => {
const user = await User.findOne({ id: peter.id })
await user.remove()
})
it('throws and logs an error', async () => {
await expect(
mutate({
mutation: updateUserInfos,
variables: {
alias: 'bibiBloxberg',
},
}),
).resolves.toMatchObject({
errors: [new GraphQLError('Alias already in use')],
data: null,
})
expect(logger.error).toBeCalledWith('Alias already in use', 'bibiBloxberg')
})
})
describe('valid alias', () => {
it('updates the user in DB', async () => {
await mutate({

View File

@ -73,6 +73,7 @@ import { getTimeDurationObject, printTimeDuration } from '@/util/time'
import { FULL_CREATION_AVAILABLE } from './const/const'
import { getUserCreations } from './util/creations'
import { findUserByIdentifier } from './util/findUserByIdentifier'
import { validateAlias } from './util/validateAlias'
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs
const random = require('random-bigint')
@ -525,19 +526,7 @@ export class UserResolver {
}
if (alias) {
if (alias.length < 5) {
throw new LogError('Given alias is too short', alias)
}
if (alias.length > 20) {
throw new LogError('Given alias is too long', alias)
}
if (!alias.match(/^[0-9A-Za-z]([_-]?[A-Za-z0-9])+$/)) {
throw new LogError('Invalid characters in alias', alias)
}
const aliasInUse = await DbUser.find({ alias })
if (aliasInUse.length !== 0) {
throw new LogError('Alias already in use', alias)
}
await validateAlias(alias)
user.alias = alias
}

View File

@ -0,0 +1,125 @@
import { Connection } from '@dbTools/typeorm'
import { User } from '@entity/User'
import { ApolloServerTestClient } from 'apollo-server-testing'
import { testEnvironment, cleanDB } from '@test/helpers'
import { logger, i18n as localization } from '@test/testSetup'
import { userFactory } from '@/seeds/factory/user'
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
import { validateAlias } from './validateAlias'
let con: Connection
let testEnv: {
mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query']
con: Connection
}
beforeAll(async () => {
testEnv = await testEnvironment(logger, localization)
con = testEnv.con
await cleanDB()
})
afterAll(async () => {
await cleanDB()
await con.close()
})
describe('validate alias', () => {
beforeAll(() => {
jest.clearAllMocks()
})
describe('alias too short', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('Bi')).rejects.toEqual(new Error('Given alias is too short'))
expect(logger.error).toBeCalledWith('Given alias is too short', 'Bi')
})
})
describe('alias too long', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('BibiBloxbergHexHexHex')).rejects.toEqual(
new Error('Given alias is too long'),
)
expect(logger.error).toBeCalledWith('Given alias is too long', 'BibiBloxbergHexHexHex')
})
})
describe('alias contains invalid characters', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('Bibi.Bloxberg')).rejects.toEqual(
new Error('Invalid characters in alias'),
)
expect(logger.error).toBeCalledWith('Invalid characters in alias', 'Bibi.Bloxberg')
})
})
describe('alias is a reserved word', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('admin')).rejects.toEqual(new Error('Alias is not allowed'))
expect(logger.error).toBeCalledWith('Alias is not allowed', 'admin')
})
})
describe('alias is a reserved word with uppercase characters', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('Admin')).rejects.toEqual(new Error('Alias is not allowed'))
expect(logger.error).toBeCalledWith('Alias is not allowed', 'Admin')
})
})
describe('hyphens and underscore', () => {
describe('alias starts with underscore', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('_bibi')).rejects.toEqual(
new Error('Invalid characters in alias'),
)
expect(logger.error).toBeCalledWith('Invalid characters in alias', '_bibi')
})
})
describe('alias contains two following hyphens', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('bi--bi')).rejects.toEqual(
new Error('Invalid characters in alias'),
)
expect(logger.error).toBeCalledWith('Invalid characters in alias', 'bi--bi')
})
})
})
describe('test against existing alias in database', () => {
beforeAll(async () => {
const bibi = await userFactory(testEnv, bibiBloxberg)
const user = await User.findOne({ id: bibi.id })
if (user) {
user.alias = 'b-b'
await user.save()
}
})
describe('alias exists in database', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('b-b')).rejects.toEqual(new Error('Alias already in use'))
expect(logger.error).toBeCalledWith('Alias already in use', 'b-b')
})
})
describe('alias exists in database with in lower-case', () => {
it('throws and logs an error', async () => {
await expect(validateAlias('b-B')).rejects.toEqual(new Error('Alias already in use'))
expect(logger.error).toBeCalledWith('Alias already in use', 'b-B')
})
})
describe('valid alias', () => {
it('resolves to void', async () => {
await expect(validateAlias('bibi')).resolves.toEqual(undefined)
})
})
})
})

View File

@ -0,0 +1,36 @@
import { Raw } from '@dbTools/typeorm'
import { User as DbUser } from '@entity/User'
import { LogError } from '@/server/LogError'
const reservedAlias = [
'admin',
'email',
'gast',
'gdd',
'gradido',
'guest',
'home',
'root',
'support',
'temp',
'tmp',
'tmp',
'user',
'usr',
'var',
]
export const validateAlias = async (alias: string): Promise<void> => {
if (alias.length < 3) throw new LogError('Given alias is too short', alias)
if (alias.length > 20) throw new LogError('Given alias is too long', alias)
if (!alias.match(/^[0-9A-Za-z]([_-]?[A-Za-z0-9])+$/))
throw new LogError('Invalid characters in alias', alias)
if (reservedAlias.includes(alias.toLowerCase())) throw new LogError('Alias is not allowed', alias)
const aliasInUse = await DbUser.find({
where: { alias: Raw((a) => `LOWER(${a}) = "${alias.toLowerCase()}"`) },
})
if (aliasInUse.length !== 0) {
throw new LogError('Alias already in use', alias)
}
}