Kaballas's picture
initialize project structure with essential configurations and components
56b6519
module.exports = function (app) {
var Response = require('../lib/httpResponse.js');
var User = require('mongoose').model('User');
var acl = require('../lib/auth').acl;
var jwtRefreshSecret = require('../lib/auth').jwtRefreshSecret;
var jwt = require('jsonwebtoken');
var _ = require('lodash');
var passwordpolicy = require('../lib/passwordpolicy');
// Check token validity
app.get(
'/api/users/checktoken',
acl.hasPermission('validtoken'),
function (req, res) {
Response.Ok(res, req.cookies['token']);
},
);
// Refresh token
app.get('/api/users/refreshtoken', function (req, res) {
var userAgent = req.headers['user-agent'];
var token = req.cookies['refreshToken'];
User.updateRefreshToken(token, userAgent)
.then(msg => {
res.cookie('token', `JWT ${msg.token}`, {
secure: true,
httpOnly: true,
});
res.cookie('refreshToken', msg.refreshToken, {
secure: true,
httpOnly: true,
path: '/api/users/refreshtoken',
});
Response.Ok(res, msg);
})
.catch(err => {
if (err.fn === 'Unauthorized') {
res.clearCookie('token');
res.clearCookie('refreshToken');
}
Response.Internal(res, err);
});
});
// Remove token cookie
app.delete('/api/users/refreshtoken', function (req, res) {
var token = req.cookies['refreshToken'];
try {
var decoded = jwt.verify(token, jwtRefreshSecret);
} catch (err) {
res.clearCookie('token');
res.clearCookie('refreshToken');
if (err.name === 'TokenExpiredError')
Response.Unauthorized(res, 'Expired refreshToken');
else Response.Unauthorized(res, 'Invalid refreshToken');
return;
}
User.removeSession(decoded.userId, decoded.sessionId)
.then(msg => {
res.clearCookie('token');
res.clearCookie('refreshToken');
Response.Ok(res, msg);
})
.catch(err => Response.Internal(res, err));
});
// Authenticate user -> return JWT token
app.post('/api/users/token', function (req, res) {
if (!req.body.password || !req.body.username) {
Response.BadParameters(res, 'Required parameters: username, password');
return;
}
// Validate types
if (
typeof req.body.password !== 'string' ||
typeof req.body.username !== 'string' ||
(req.body.totpToken && typeof req.body.totpToken !== 'string')
) {
Response.BadParameters(res, 'Parameters must be of type String');
return;
}
var user = new User();
//Required params
user.username = req.body.username;
user.password = req.body.password;
//Optional params
if (req.body.totpToken) user.totpToken = req.body.totpToken;
user
.getToken(req.headers['user-agent'])
.then(msg => {
res.cookie('token', `JWT ${msg.token}`, {
secure: true,
httpOnly: true,
sameSite: 'None',
});
res.cookie('refreshToken', msg.refreshToken, {
secure: true,
httpOnly: true,
path: '/api/users/refreshtoken',
sameSite: 'None',
});
Response.Ok(res, msg);
})
.catch(err => Response.Internal(res, err));
});
// Check if there are any existing users for creating first user
app.get('/api/users/init', function (req, res) {
User.getAll()
.then(msg => Response.Ok(res, msg.length === 0))
.catch(err => Response.Internal(res, err));
});
// Get all users
app.get('/api/users', acl.hasPermission('users:read'), function (req, res) {
User.getAll()
.then(msg => Response.Ok(res, msg))
.catch(err => Response.Internal(res, err));
});
// Get all reviewers
app.get(
'/api/users/reviewers',
acl.hasPermission('users:read'),
function (req, res) {
User.getAll()
.then(users => {
var reviewers = [];
users.forEach(user => {
if (
acl.isAllowed(user.role, 'audits:review') ||
acl.isAllowed(user.role, 'audits:review-all')
) {
reviewers.push(user);
}
});
Response.Ok(res, reviewers);
})
.catch(err => Response.Internal(res, err));
},
);
// Get user self
app.get(
'/api/users/me',
acl.hasPermission('validtoken'),
function (req, res) {
User.getByUsername(req.decodedToken.username)
.then(msg => Response.Ok(res, msg))
.catch(err => Response.Internal(res, err));
},
);
//get TOTP Qrcode URL
app.get(
'/api/users/totp',
acl.hasPermission('validtoken'),
function (req, res) {
User.getTotpQrcode(req.decodedToken.username)
.then(msg => Response.Ok(res, msg))
.catch(err => Response.Internal(res, err));
},
);
//setup TOTP
app.post(
'/api/users/totp',
acl.hasPermission('validtoken'),
function (req, res) {
if (!req.body.totpToken || !req.body.totpSecret) {
Response.BadParameters(res, 'Missing some required parameters');
return;
}
User.setupTotp(
req.body.totpToken,
req.body.totpSecret,
req.decodedToken.username,
)
.then(msg => Response.Ok(res, msg))
.catch(err => Response.Internal(res, err));
},
);
//cancel TOTP
app.delete(
'/api/users/totp',
acl.hasPermission('validtoken'),
function (req, res) {
if (!req.body.totpToken) {
Response.BadParameters(res, 'Missing some required parameters');
return;
}
User.cancelTotp(req.body.totpToken, req.decodedToken.username)
.then(msg => Response.Ok(res, msg))
.catch(err => Response.Internal(res, err));
},
);
// Get user by username
app.get(
'/api/users/:username',
acl.hasPermission('users:read'),
function (req, res) {
User.getByUsername(req.params.username)
.then(msg => Response.Ok(res, msg))
.catch(err => Response.Internal(res, err));
},
);
// Create user
app.post(
'/api/users',
acl.hasPermission('users:create'),
function (req, res) {
if (
!req.body.username ||
!req.body.password ||
!req.body.firstname ||
!req.body.lastname
) {
Response.BadParameters(res, 'Missing some required parameters');
return;
}
if (passwordpolicy.strongPassword(req.body.password) !== true) {
Response.BadParameters(
res,
'Password does not match the password policy',
);
return;
}
var user = {};
//Required params
user.username = req.body.username;
user.password = req.body.password;
user.firstname = req.body.firstname;
user.lastname = req.body.lastname;
//Optionals params
user.role = req.body.role || 'user';
if (req.body.email) user.email = req.body.email;
if (req.body.phone) user.phone = req.body.phone;
User.create(user)
.then(msg => Response.Created(res, 'User created successfully'))
.catch(err => Response.Internal(res, err));
},
);
// Create First User
app.post('/api/users/init', function (req, res) {
if (
!req.body.username ||
!req.body.password ||
!req.body.firstname ||
!req.body.lastname
) {
Response.BadParameters(res, 'Missing some required parameters');
return;
}
if (passwordpolicy.strongPassword(req.body.password) !== true) {
Response.BadParameters(
res,
'Password does not match the password policy',
);
return;
}
var user = {};
//Required params
user.username = req.body.username;
user.password = req.body.password;
user.firstname = req.body.firstname;
user.lastname = req.body.lastname;
user.role = 'admin';
User.getAll()
.then(users => {
if (users.length === 0)
User.create(user)
.then(msg => {
var newUser = new User();
//Required params
newUser.username = req.body.username;
newUser.password = req.body.password;
newUser
.getToken(req.headers['user-agent'])
.then(msg => {
res.cookie('token', `JWT ${msg.token}`, {
secure: true,
httpOnly: true,
});
res.cookie('refreshToken', msg.refreshToken, {
secure: true,
httpOnly: true,
path: '/api/users/refreshtoken',
});
Response.Created(res, msg);
})
.catch(err => Response.Internal(res, err));
})
.catch(err => Response.Internal(res, err));
else Response.Forbidden(res, 'Already Initialized');
})
.catch(err => Response.Internal(res, err));
});
// Update my profile
app.put(
'/api/users/me',
acl.hasPermission('validtoken'),
function (req, res) {
if (
!req.body.currentPassword ||
(req.body.newPassword && !req.body.confirmPassword) ||
(req.body.confirmPassword && !req.body.newPassword)
) {
Response.BadParameters(res, 'Missing some required parameters');
return;
}
if (
req.body.newPassword &&
passwordpolicy.strongPassword(req.body.newPassword) !== true
) {
Response.BadParameters(
res,
'New Password does not match the password policy',
);
return;
}
if (
req.body.newPassword &&
req.body.confirmPassword &&
req.body.newPassword !== req.body.confirmPassword
) {
Response.BadParameters(res, 'New password validation failed');
return;
}
var user = {};
// Required params
user.password = req.body.currentPassword;
// Optionals params
if (req.body.username) user.username = req.body.username;
if (req.body.newPassword) user.newPassword = req.body.newPassword;
if (req.body.firstname) user.firstname = req.body.firstname;
if (req.body.lastname) user.lastname = req.body.lastname;
if (!_.isNil(req.body.email)) user.email = req.body.email;
if (!_.isNil(req.body.phone)) user.phone = req.body.phone;
User.updateProfile(req.decodedToken.username, user)
.then(msg => {
res.cookie('token', msg.token, { secure: true, httpOnly: true });
Response.Ok(res, msg);
})
.catch(err => Response.Internal(res, err));
},
);
// Update any user (admin only)
app.put(
'/api/users/:id',
acl.hasPermission('users:update'),
function (req, res) {
if (
req.body.password &&
!passwordpolicy.strongPassword(req.body.password)
) {
Response.BadParameters(
res,
'New Password does not match the password policy',
);
return;
}
var user = {};
// Optionals params
if (req.body.username) user.username = req.body.username;
if (req.body.password) user.password = req.body.password;
if (req.body.firstname) user.firstname = req.body.firstname;
if (req.body.lastname) user.lastname = req.body.lastname;
if (!_.isNil(req.body.email)) user.email = req.body.email;
if (!_.isNil(req.body.phone)) user.phone = req.body.phone;
if (req.body.role) user.role = req.body.role;
if (typeof req.body.totpEnabled === 'boolean')
user.totpEnabled = req.body.totpEnabled;
if (typeof req.body.enabled === 'boolean')
user.enabled = req.body.enabled;
User.updateUser(req.params.id, user)
.then(msg => Response.Ok(res, msg))
.catch(err => Response.Internal(res, err));
},
);
};