parent
b080d319af
commit
c5015bf43f
6 changed files with 228 additions and 5 deletions
@ -0,0 +1,64 @@ |
||||
import assert from 'assert'; |
||||
import { RequestHandler } from 'express'; |
||||
|
||||
import { REP_PEACEFUL_STRING, REP_UUID } from '../../consts'; |
||||
|
||||
import { insertOrUpdateUser, query } from '../../accessModule'; |
||||
import { sanitize } from '../../sanitize'; |
||||
import { openssl, stderr, stdoutVar } from '../../shell'; |
||||
|
||||
export const createUser: RequestHandler< |
||||
unknown, |
||||
CreateUserResponseBody, |
||||
CreateUserRequestBody |
||||
> = async (request, response) => { |
||||
const { body: { password: rPassword, userName: rUserName } = {} } = request; |
||||
|
||||
const password = sanitize(rPassword, 'string', { |
||||
fallback: openssl('rand', '-base64', '12').trim(), |
||||
}); |
||||
const userName = sanitize(rUserName, 'string', { modifierType: 'sql' }); |
||||
|
||||
stdoutVar({ password, userName }, 'Create user with params: '); |
||||
|
||||
try { |
||||
assert( |
||||
REP_PEACEFUL_STRING.test(password), |
||||
`Password must be a peaceful string; got: [${password}]`, |
||||
); |
||||
|
||||
assert( |
||||
REP_PEACEFUL_STRING.test(userName), |
||||
`User name must be a peaceful string; got: [${userName}]`, |
||||
); |
||||
|
||||
const [[userCount]]: [[number]] = await query( |
||||
`SELECT COUNT(user_uuid) FROM users WHERE user_name = '${userName}';`, |
||||
); |
||||
|
||||
assert(userCount === 0, `User name [${userName}] already used`); |
||||
} catch (error) { |
||||
stderr(`Failed to assert value when creating user; CAUSE: ${error}`); |
||||
|
||||
return response.status(400).send(); |
||||
} |
||||
|
||||
try { |
||||
const result = await insertOrUpdateUser({ |
||||
file: __filename, |
||||
user_name: userName, |
||||
user_password_hash: password, |
||||
}); |
||||
|
||||
assert( |
||||
REP_UUID.test(result), |
||||
`Insert or update failed with result [${result}]`, |
||||
); |
||||
} catch (error) { |
||||
stderr(`Failed to record user to database; CAUSE: ${error}`); |
||||
|
||||
return response.status(500).send(); |
||||
} |
||||
|
||||
return response.status(201).send({ password }); |
||||
}; |
@ -1,2 +1,4 @@ |
||||
export * from './createUser'; |
||||
export * from './deleteUser'; |
||||
export * from './getUser'; |
||||
export * from './updateUser'; |
||||
|
@ -0,0 +1,136 @@ |
||||
import assert from 'assert'; |
||||
import { RequestHandler } from 'express'; |
||||
|
||||
import { REP_PEACEFUL_STRING, REP_UUID } from '../../consts'; |
||||
|
||||
import { encrypt, query, write } from '../../accessModule'; |
||||
import { sanitize } from '../../sanitize'; |
||||
import { stderr, stdoutVar } from '../../shell'; |
||||
|
||||
export const updateUser: RequestHandler< |
||||
UserParamsDictionary, |
||||
undefined, |
||||
UpdateUserRequestBody |
||||
> = async (request, response) => { |
||||
const { |
||||
body: { password: rPassword, userName: rUserName } = {}, |
||||
params: { userUuid }, |
||||
} = request; |
||||
|
||||
const password = sanitize(rPassword, 'string'); |
||||
const userName = sanitize(rUserName, 'string', { modifierType: 'sql' }); |
||||
|
||||
stdoutVar({ password, userName }, `Update user ${userUuid} with params: `); |
||||
|
||||
try { |
||||
if (password.length) { |
||||
assert( |
||||
REP_PEACEFUL_STRING.test(password), |
||||
`Password must be a valid peaceful string; got: [${password}]`, |
||||
); |
||||
} |
||||
|
||||
if (userName.length) { |
||||
assert( |
||||
REP_PEACEFUL_STRING.test(userName), |
||||
`User name must be a peaceful string; got: [${userName}]`, |
||||
); |
||||
} |
||||
|
||||
assert( |
||||
REP_UUID.test(userUuid), |
||||
`User UUID must be a valid UUIDv4; got: [${userUuid}]`, |
||||
); |
||||
|
||||
const [[existingUserName]]: [[string]] = await query( |
||||
`SELECT user_name FROM users WHERE user_uuid = '${userUuid}';`, |
||||
); |
||||
|
||||
assert(existingUserName !== 'admin' || userName, 'Cannot '); |
||||
} catch (error) { |
||||
stderr(`Assert failed when update user; CAUSE: ${error}`); |
||||
|
||||
return response.status(400).send(); |
||||
} |
||||
|
||||
let existingUser: [ |
||||
[ |
||||
user_name: string, |
||||
user_password_hash: string, |
||||
user_salt: string, |
||||
user_algorithm: string, |
||||
user_hash_count: string, |
||||
], |
||||
]; |
||||
|
||||
try { |
||||
existingUser = await query( |
||||
`SELECT
|
||||
user_name, |
||||
user_password_hash, |
||||
user_salt, |
||||
user_algorithm, |
||||
user_hash_count |
||||
FROM users |
||||
WHERE user_uuid = '${userUuid}' |
||||
ORDER BY modified_date DESC |
||||
LIMIT 1;`,
|
||||
); |
||||
} catch (error) { |
||||
stderr(`Failed to find existing user ${userUuid}; CAUSE: ${error}`); |
||||
|
||||
return response.status(500).send(); |
||||
} |
||||
|
||||
if (existingUser.length !== 1) { |
||||
return response.status(404).send(); |
||||
} |
||||
|
||||
const [[xUserName, xPasswordHash, xSalt, xAlgorithm, xHashCount]] = |
||||
existingUser; |
||||
|
||||
const assigns: string[] = []; |
||||
|
||||
if (password.length) { |
||||
let passwordHash: string; |
||||
|
||||
try { |
||||
({ user_password_hash: passwordHash } = await encrypt({ |
||||
algorithm: xAlgorithm, |
||||
hash_count: xHashCount, |
||||
password, |
||||
salt: xSalt, |
||||
})); |
||||
} catch (error) { |
||||
stderr(`Encrypt failed when update user; CAUSE ${error}`); |
||||
|
||||
return response.status(500).send(); |
||||
} |
||||
|
||||
if (passwordHash !== xPasswordHash) { |
||||
assigns.push(`user_password_hash = '${passwordHash}'`); |
||||
} |
||||
} |
||||
|
||||
if (userName.length && userName !== xUserName) { |
||||
assigns.push(`user_name = '${userName}'`); |
||||
} |
||||
|
||||
if (assigns.length) { |
||||
try { |
||||
const wcode = await write( |
||||
`UPDATE users SET ${assigns.join( |
||||
',', |
||||
)} WHERE user_uuid = '${userUuid}';`,
|
||||
); |
||||
|
||||
assert(wcode === 0, `Update users failed with code: ${wcode}`); |
||||
} catch (error) { |
||||
stderr(`Failed to record user changes to database; CAUSE: ${error}`); |
||||
|
||||
return response.status(500).send(); |
||||
} |
||||
} |
||||
|
||||
return response.send(); |
||||
}; |
@ -1,7 +1,18 @@ |
||||
type DeleteUserParamsDictionary = { |
||||
userUuid: string; |
||||
type CreateUserRequestBody = { |
||||
password?: string; |
||||
userName: string; |
||||
}; |
||||
|
||||
type CreateUserResponseBody = { |
||||
password: string; |
||||
}; |
||||
|
||||
type DeleteUserRequestBody = { |
||||
uuids?: string[]; |
||||
}; |
||||
|
||||
type UpdateUserRequestBody = Partial<CreateUserRequestBody>; |
||||
|
||||
type UserParamsDictionary = { |
||||
userUuid: string; |
||||
}; |
||||
|
Loading…
Reference in new issue