Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📩 feat: invite user #3012

Merged
merged 22 commits into from
Aug 18, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2d09218
feat: basic invite-user script
berry-13 Jun 8, 2024
7774efb
feat: add invite user functionality and registration validation middl…
berry-13 Jun 8, 2024
1809551
Merge branch 'main' into invite-user
berry-13 Jun 8, 2024
f7ad1d8
fix: invite user fixes
berry-13 Jun 8, 2024
731fd0a
refactor: consolidate direct model access to a central place of funct…
berry-13 Jun 9, 2024
8d1be0c
style(Registration): add spinner to continue button
berry-13 Jun 9, 2024
a1560fd
refactor: import ordrer
berry-13 Jun 9, 2024
6c8494c
feat: improve invite user script and error handling
berry-13 Jun 9, 2024
7651c23
Merge branch 'main' into invite-user
berry-13 Jun 16, 2024
61a630d
Merge branch 'main' into invite-user
berry-13 Jun 18, 2024
70ee923
fix: merge conflict
berry-13 Jun 21, 2024
0ffedf0
Merge branch 'main' into invite-user
berry-13 Jun 21, 2024
78a83ad
refactor: remove `console.log` and use `logger`
berry-13 Jul 3, 2024
89606f7
Merge branch 'main' into invite-user
berry-13 Aug 17, 2024
4e62aaf
fix: token operation and checkinvite issues
berry-13 Aug 17, 2024
2f69a20
bring back comment and remove console log
berry-13 Aug 17, 2024
3507fde
fix: return invalid token when token is not found
berry-13 Aug 17, 2024
b0428f4
fix: getInvite fix
berry-13 Aug 17, 2024
6fe37d9
refactor: Update Token.js to use async/await syntax for update and de…
danny-avila Aug 18, 2024
569812e
feat: Refactor Token.js to use async/await syntax for createToken and…
danny-avila Aug 18, 2024
2177734
refactor(inviteUser): define functions outside of module.exports
danny-avila Aug 18, 2024
07b5390
Update AuthService.js
danny-avila Aug 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions api/models/inviteUser.js
berry-13 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const crypto = require('crypto');
const bcrypt = require('bcryptjs');
const InviteUser = require('./schema/inviteUserSchema');
const logger = require('~/config/winston');

/**
* @module inviteUser
* @description This module provides functions to create and get user invites
*/

module.exports = {
/**
* @type {InviteUser}
*/
InviteUser,

/**
* @function createInvite
* @description This function creates a new user invite
* @param {string} email - The email of the user to invite
* @returns {Promise<Object>} A promise that resolves to the saved invite document
* @throws {Error} If there is an error creating the invite
*/
createInvite: async (email) => {
danny-avila marked this conversation as resolved.
Show resolved Hide resolved
try {
let token = crypto.randomBytes(32).toString('hex');
const hash = bcrypt.hashSync(token, 10);
const encodedToken = encodeURIComponent(token);
const invite = new InviteUser({ email, token: hash, createdAt: Date.now() });
await invite.save();
return encodedToken;
} catch (error) {
logger.error('[createInvite] Error creating invite', error);
return { message: 'Error creating invite' };
}
},

/**
* @function getInvite
* @description This function retrieves a user invite
* @param {string} token - The token of the invite to retrieve
* @returns {Promise<Object>} A promise that resolves to the retrieved invite document
* @throws {Error} If there is an error retrieving the invite or if the invite does not exist
*/
getInvite: async (encodedToken) => {
try {
const token = decodeURIComponent(encodedToken);
const hash = bcrypt.hashSync(token, 10);
const invite = await InviteUser.findOne({ token: hash }).lean().exec();
if (!invite) {
throw new Error('Invite not found');
}
return invite;
} catch (error) {
logger.error('[getInvite] Error getting invite', error);
return { message: 'Error getting invite' };
}
},
};
21 changes: 21 additions & 0 deletions api/models/schema/inviteUserSchema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const inviteUserSchema = new Schema({
email: {
required: true,
type: String,
},
token: {
type: String,
required: true,
},
createdAt: {
type: Date,
required: true,
default: Date.now,
expires: 604800,
},
});

module.exports = mongoose.model('InviteUser', inviteUserSchema);
1 change: 1 addition & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"list-balances": "node ./list-balances.js",
"user-stats": "node ./user-stats.js",
"create-user": "node ./create-user.js",
"invite-user": "node ./invite-user.js",
"ban-user": "node ./ban-user.js",
"delete-user": "node ./delete-user.js"
},
Expand Down
27 changes: 27 additions & 0 deletions api/server/middleware/checkInviteUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { getInvite } = require('~/models/inviteUser');

function checkInviteUser(req, res, next) {
berry-13 marked this conversation as resolved.
Show resolved Hide resolved
const token = req.body.token;

if (!token || token === 'undefined') {
console.log('No token provided');
next();
return;
}

getInvite(token)
.then((invite) => {
console.log('Invite:', invite);
if (invite) {
req.invite = invite;
next();
} else {
res.status(400).json({ message: 'Invalid invite' });
}
})
.catch((error) => {
return res.status(400).json({ message: error.message });
});
}

module.exports = checkInviteUser;
2 changes: 2 additions & 0 deletions api/server/middleware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const requireLocalAuth = require('./requireLocalAuth');
const canDeleteAccount = require('./canDeleteAccount');
const requireLdapAuth = require('./requireLdapAuth');
const abortMiddleware = require('./abortMiddleware');
const checkInviteUser = require('./checkInviteUser');
const requireJwtAuth = require('./requireJwtAuth');
const validateModel = require('./validateModel');
const moderateText = require('./moderateText');
Expand All @@ -29,6 +30,7 @@ module.exports = {
moderateText,
validateModel,
requireJwtAuth,
checkInviteUser,
requireLdapAuth,
requireLocalAuth,
canDeleteAccount,
Expand Down
8 changes: 8 additions & 0 deletions api/server/middleware/validateRegistration.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
const { isEnabled } = require('~/server/utils');

function validateRegistration(req, res, next) {
console.log('Invite:', req.invite);
if (req.invite) {
console.log('Registration is allowed because of invite.');
return next();
}

if (isEnabled(process.env.ALLOW_REGISTRATION)) {
console.log('Registration is allowed.');
berry-13 marked this conversation as resolved.
Show resolved Hide resolved
next();
} else {
console.log('Registration is not allowed.');
res.status(403).send('Registration is not allowed.');
}
}
Expand Down
10 changes: 9 additions & 1 deletion api/server/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const {
checkBan,
loginLimiter,
requireJwtAuth,
checkInviteUser,
registerLimiter,
requireLdapAuth,
requireLocalAuth,
Expand All @@ -33,7 +34,14 @@ router.post(
loginController,
);
router.post('/refresh', refreshController);
router.post('/register', registerLimiter, checkBan, validateRegistration, registrationController);
router.post(
'/register',
registerLimiter,
checkBan,
checkInviteUser,
validateRegistration,
registrationController,
);
router.post(
'/requestPasswordReset',
resetPasswordLimiter,
Expand Down
Loading
Loading