Skip to content

Commit

Permalink
v1.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
luwol03 authored Jan 29, 2022
2 parents 6e88b06 + d5398ff commit ac5dbfd
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 2 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
This changelog goes through all the changes that have been made in each release on the
[vocascan-server](https://github.com/vocascan/vocascan-server).

## [v1.2.1](https://github.com/vocascan/vocascan-server/releases/tag/v1.2.1) - 2022.01.29

In this release of vocascan-server we have added new security features to force secure passwords to the users.

- Features
- Added Password Complexity to register and password reset (#79)
- Bug
- closes Update Swagger Documentation for password reset (#80) (#81)

## [v1.2.0](https://github.com/vocascan/vocascan-server/releases/tag/v1.2.0) - 2022.01.22

In this release of vocascan-server we have added new features to make your server more secure. On the one hand, the legal side. You can now include static HTML pages or redirects to your privacy policy or imprint. On the other hand, in security, with an improved CORS configuration option to restrict access to only allowed frontend domains.
Expand Down
11 changes: 11 additions & 0 deletions app/Controllers/AuthController.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
const httpStatus = require('http-status');
const config = require('../config/config');
const {
createUser,
loginUser,
validateRegister,
validateLogin,
validatePassword,
destroyUser,
changePassword,
} = require('../Services/AuthServiceProvider');
const { useInviteCode } = require('../Services/InviteCodeProvider');
const { generateJWT, deleteKeysFromObject } = require('../utils');
const catchAsync = require('../utils/catchAsync');
const ApiError = require('../utils/ApiError');

const register = catchAsync(async (req, res) => {
await validateRegister(req, res);

if (!validatePassword(req.body.password)) {
throw new ApiError(httpStatus.BAD_REQUEST, 'password complexity failed', 'password');
}

const user = await createUser(req.body);
const token = generateJWT({ id: user.id }, config.server.jwt_secret);

Expand Down Expand Up @@ -56,6 +63,10 @@ const resetPassword = catchAsync(async (req, res) => {
const userId = req.user.id;
const { oldPassword, newPassword } = req.body;

if (!validatePassword(req.body.newPassword)) {
throw new ApiError(httpStatus.BAD_REQUEST, 'password complexity failed', 'newPassword');
}

await changePassword(userId, oldPassword, newPassword);

res.status(204).end();
Expand Down
22 changes: 22 additions & 0 deletions app/Services/AuthServiceProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const crypto = require('crypto');
const { deleteKeysFromObject, hashEmail } = require('../utils');
const { User, Role } = require('../../database');
const ApiError = require('../utils/ApiError.js');
const { bytesLength } = require('../utils/index.js');
const httpStatus = require('http-status');
const { validateInviteCode } = require('../Services/InviteCodeProvider.js');
const config = require('../config/config');
Expand Down Expand Up @@ -82,6 +83,26 @@ function validateLogin(req, res) {
return validateAuth(req, res);
}

function validatePassword(password) {
const passwordLength = bytesLength(password);

const length = passwordLength >= 8 && passwordLength <= 72;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasNonAlphas = /\W/.test(password);

let passwordComplexity = 0;

if (length) {
passwordComplexity = length + hasUpperCase + hasLowerCase + hasNumbers + hasNonAlphas;
} else if (passwordLength !== 0) {
passwordComplexity = 1;
}

return passwordLength >= 8 && passwordLength <= 72 && passwordComplexity >= 4;
}

// Create new user and store into database
async function createUser({ username, email, password }) {
// Hash password
Expand Down Expand Up @@ -196,6 +217,7 @@ module.exports = {
loginUser,
validateRegister,
validateLogin,
validatePassword,
destroyUser,
changePassword,
checkPasswordValid,
Expand Down
9 changes: 9 additions & 0 deletions app/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,14 @@ const askToConfirm = (question) => {
});
};

/**
* Return the length of a string in bytes
* See: https://stackoverflow.com/questions/5515869/string-length-in-bytes-in-javascript
* @param {String} string string
* @returns bytesLength
*/
const bytesLength = (string) => new TextEncoder().encode(string).length;

module.exports = {
generateJWT,
parseTokenUserId,
Expand All @@ -307,4 +315,5 @@ module.exports = {
truncateString,
hashEmail,
askToConfirm,
bytesLength,
};
2 changes: 1 addition & 1 deletion docs/api/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
}
}
},
"/user/password/reset": {
"/user/reset-password": {
"post": {
"summary": "Reset user password",
"tags": ["auth"],
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vocascan/server",
"version": "1.2.0",
"version": "1.2.1",
"description": "A highly configurable vocabulary trainer",
"main": "./server.js",
"scripts": {
Expand Down

0 comments on commit ac5dbfd

Please sign in to comment.