Skip to content

Commit

Permalink
merge master
Browse files Browse the repository at this point in the history
  • Loading branch information
rssk committed Nov 16, 2023
2 parents 791f845 + b1161d4 commit b6d49b8
Show file tree
Hide file tree
Showing 46 changed files with 20,359 additions and 14,047 deletions.
26,292 changes: 15,268 additions & 11,024 deletions coinstac-docs/package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions coinstac-docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "2.2.0",
"@docusaurus/preset-classic": "2.2.0",
"@docusaurus/core": "3.0.0",
"@docusaurus/preset-classic": "3.0.0",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
Expand Down
5,454 changes: 3,269 additions & 2,185 deletions coinstac-docs/yarn.lock

Large diffs are not rendered by default.

31 changes: 23 additions & 8 deletions packages/coinstac-api-server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/coinstac-api-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"@sendgrid/mail": "^7.7.0",
"apollo-server-hapi": "^2.25.3",
"aws-sdk": "^2.1150.0",
"axios": "^0.21.1",
"axios": "^1.6.0",
"boom": "^5.2.0",
"form-data": "^4.0.0",
"github-api": "^3.3.0",
Expand Down
7 changes: 7 additions & 0 deletions packages/coinstac-api-server/seed/populate.js
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,7 @@ async function populateUsers() {
[CONSORTIA_IDS[0]]: 'none',
[CONSORTIA_IDS[1]]: 'none',
},
passwordChangedAt: new Date(),
}, password);

await helperFunctions.createUser({
Expand All @@ -886,6 +887,7 @@ async function populateUsers() {
[CONSORTIA_IDS[0]]: 'none',
[CONSORTIA_IDS[1]]: 'none',
},
passwordChangedAt: new Date(),
}, password);

await helperFunctions.createUser({
Expand All @@ -911,6 +913,7 @@ async function populateUsers() {
[CONSORTIA_IDS[0]]: 'none',
[CONSORTIA_IDS[1]]: 'none',
},
passwordChangedAt: new Date(),
}, password);

await helperFunctions.createUser({
Expand All @@ -936,6 +939,7 @@ async function populateUsers() {
[CONSORTIA_IDS[0]]: 'none',
[CONSORTIA_IDS[1]]: 'none',
},
passwordChangedAt: new Date(),
}, password);

await helperFunctions.createUser({
Expand All @@ -961,6 +965,7 @@ async function populateUsers() {
[CONSORTIA_IDS[0]]: 'none',
[CONSORTIA_IDS[1]]: 'none',
},
passwordChangedAt: new Date(),
}, password);

await helperFunctions.createUser({
Expand All @@ -982,6 +987,7 @@ async function populateUsers() {
author: false,
},
},
passwordChangedAt: new Date(),
}, password);

const adminPassword = await helperFunctions.hashPassword(process.argv[3]
Expand All @@ -1007,6 +1013,7 @@ async function populateUsers() {
[CONSORTIA_IDS[0]]: 'none',
[CONSORTIA_IDS[1]]: 'none',
},
passwordChangedAt: new Date(),
}, adminPassword);
}

Expand Down
108 changes: 98 additions & 10 deletions packages/coinstac-api-server/src/auth-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const { eventEmitter, USER_CHANGED } = require('./data/events');

sgMail.setApiKey(process.env.SENDGRID_API_KEY);

const passwordLifeTime = 180;

const audience = 'coinstac';
const issuer = 'coinstac';
const subject = 'coinstac';
Expand Down Expand Up @@ -84,6 +86,7 @@ const helperFunctions = {
pipelines: {},
},
consortiaStatuses: user.consortiaStatuses || {},
passwordChangedAt: new Date(),
};

const db = database.getDbInstance();
Expand Down Expand Up @@ -141,7 +144,23 @@ const helperFunctions = {
* @param {string} email email to send password reset token
* @return {object}
*/
async savePasswordResetToken(email) {
async savePasswordResetToken(emailOrUsername) {
const db = database.getDbInstance();
const user = await db.collection('users').findOne(
{
$or: [
{ email: emailOrUsername },
{ username: emailOrUsername },
],
}
);

if (!user) {
return Boom.badRequest('Invalid user');
}

const { email } = user;

const resetToken = helperFunctions.createPasswordResetToken(email);

const msg = {
Expand All @@ -153,9 +172,11 @@ const helperFunctions = {
Token: <strong>${resetToken}</strong>`,
};

const db = database.getDbInstance();

await sgMail.send(msg);
try {
await sgMail.send(msg);
} catch (error) {
return Boom.badRequest('Failed to send email');
}

return db.collection('users').updateOne({ email }, {
$set: {
Expand Down Expand Up @@ -341,11 +362,21 @@ const helperFunctions = {
req.payload.password, user.passwordHash
);

if (passwordMatch) {
return h.response(transformToClient(user));
if (!passwordMatch) {
return Boom.unauthorized('Incorrect username or password');
}

return Boom.unauthorized('Incorrect username or password');
const { passwordChangedAt } = user;
const currentDate = new Date();
const difference = Math.ceil(
(currentDate.getTime() - passwordChangedAt.getTime()) / (1000 * 3600 * 24)
);

if (difference >= passwordLifeTime) {
return Boom.unauthorized('Password is expired');
}

return h.response(transformToClient(user));
},
/**
* Validate api key used by headless client
Expand Down Expand Up @@ -407,12 +438,42 @@ const helperFunctions = {
}
},
/**
* Reset password
* @param {object} password token for resetting password
* Confirms that submitted token is valid
* @param {object} req request
* @param {object} res response
* @return {object} The requested object
*/
async validateResetPassword(req, h) {
const db = database.getDbInstance();
const user = await db.collection('users').findOne({ username: req.payload.username });

if (!user) {
return Boom.badRequest('Invalid user');
}

const passwordMatch = await helperFunctions.verifyPassword(
req.payload.currentPassword, user.passwordHash
);

if (!passwordMatch) {
return Boom.badRequest('Current Password is not correct');
}

const isPasswordValid = helperFunctions.validatePasswordWithRegEx(req.payload.newPassword);

if (!isPasswordValid) {
return Boom.badRequest('New Password is not valid');
}

return h.response();
},
/**
* Reset forgot password
* @param {object} token token for resetting password
* @param {object} password new password
* @return {object}
*/
async resetPassword(token, password) {
async resetForgotPassword(token, password) {
const db = database.getDbInstance();

const newPassword = await helperFunctions.hashPassword(password);
Expand All @@ -423,6 +484,29 @@ const helperFunctions = {
$set: {
passwordHash: newPassword,
passwordResetToken: '',
passwordChangedAt: new Date(),
},
}, {
returnOriginal: false,
});
},
/**
* Reset password
* @param {object} username username
* @param {object} password new password
* @return {object}
*/
async resetPassword(username, password) {
const db = database.getDbInstance();

const newPassword = await helperFunctions.hashPassword(password);

return db.collection('users').updateOne({
username,
}, {
$set: {
passwordHash: newPassword,
passwordChangedAt: new Date(),
},
}, {
returnOriginal: false,
Expand Down Expand Up @@ -499,6 +583,10 @@ const helperFunctions = {
return Boom.badRequest('invalid user/run combination');
}
},
validatePasswordWithRegEx(password) {
const PASSWORD_PATTERN = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[#?!@$%^&*-]).{8,}$/g;
return PASSWORD_PATTERN.test(password);
},
audience,
issuer,
subject,
Expand Down
25 changes: 21 additions & 4 deletions packages/coinstac-api-server/src/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ module.exports = [
{ method: helperFunctions.validateUniqueUser },
],
handler: async (req, h) => {
const isPasswordValid = helperFunctions.validatePassword(req.payload.password);
if (!isPasswordValid) {
return h.response('Invalid password').code(400);
}
const passwordHash = await helperFunctions.hashPassword(req.payload.password);
const user = await helperFunctions.createUser(req.payload, passwordHash);
const {
Expand Down Expand Up @@ -131,10 +135,23 @@ module.exports = [
path: '/sendPasswordResetEmail',
config: {
auth: false,
pre: [{ method: helperFunctions.validateEmail }],
handler: (req, h) => {
return helperFunctions
.savePasswordResetToken(req.payload.email)
.savePasswordResetToken(req.payload.emailOrUsername)
.then(() => h.response().code(204))
.catch(() => h.response().code(400));
},
},
},
{
method: 'POST',
path: '/resetForgotPassword',
config: {
auth: false,
pre: [{ method: helperFunctions.validateResetToken }],
handler: (req, h) => {
return helperFunctions
.resetForgotPassword(req.payload.token, req.payload.password)
.then(() => h.response().code(204));
},
},
Expand All @@ -144,10 +161,10 @@ module.exports = [
path: '/resetPassword',
config: {
auth: false,
pre: [{ method: helperFunctions.validateResetToken }],
pre: [{ method: helperFunctions.validateResetPassword }],
handler: (req, h) => {
return helperFunctions
.resetPassword(req.payload.token, req.payload.password)
.resetPassword(req.payload.username, req.payload.newPassword)
.then(() => h.response().code(204));
},
},
Expand Down
6 changes: 3 additions & 3 deletions packages/coinstac-api-server/tests/resolvers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ test('decodeToken', (t) => {
t.is(decoded.id, username);
});

test('createPasswordResetToken, savePasswordResetToken, validateResetToken and resetPassword', async (t) => {
test('createPasswordResetToken, savePasswordResetToken, validateResetToken and resetForgotPassword', async (t) => {
/* createPasswordResetToken */
const email = 'test@mrn.org';
const token = helperFunctions.createPasswordResetToken(email);
Expand Down Expand Up @@ -133,9 +133,9 @@ test('createPasswordResetToken, savePasswordResetToken, validateResetToken and r
t.is(error.message, INVALID_EMAIL);
jwt.verify.restore();

/* resetPassword */
/* resetForgotPassword */
const newPassword = 'newPassword';
await helperFunctions.resetPassword(token, newPassword);
await helperFunctions.resetForgotPassword(token, newPassword);
const res = await helperFunctions.getUserDetailsByID(USER_IDS[0]);
const isValid = await helperFunctions.verifyPassword(newPassword, res.passwordHash);
t.true(isValid);
Expand Down
Loading

0 comments on commit b6d49b8

Please sign in to comment.