127.0.0.1:8000 watch-together / master server / routes / api / registration.js
master

Tree @master (Download .tar.gz)

registration.js @masterraw · history · blame

const utils = require('../../utils');
const time = require('../../utils/time');
const snippets = require('../../utils/snippets');
const mailgun = require('../../utils/mailgun');
const bcrypt = require('bcrypt');
const query_string = require('query-string');

module.exports = {
    post: {
        "request-token": function(req, res) {
            let token = utils.uuid();
            utils.query("INSERT INTO registrations SET ?", {
                user_id: req.user.user_id,
                reg_id: token,
                expires: Date.now() + time.one_day
            }).catch(utils.handle_err.sql(res)).then(function() {
                res.send(utils.ok({
                    token: token
                }));
            }).catch(utils.handle_err.res(res, "Error creating registration token, try again later"));
        },
        "": [{
                auth: false,
                captcha: true
            },
            function(req, res) {
                let registered_by;
                let confirmation_id;

                utils.validate.keys(req.body, [
                    ['token', utils.validate.uuid],
                    'display_name',
                    ['email', utils.validate.email, "Invalid Email"],
                    ['password', utils.validate.password, "Password not strong enough"]
                ]).then(function() {
                    // Look for a registration session matching the reg_id
                    return utils.query('SELECT * FROM registrations WHERE ?', {
                        reg_id: req.body.token
                    }).catch(utils.handle_err.sql(res));
                }).then(function([registration_data]) {
                    if (!registration_data) {
                        return utils.reject("Registration token invalid");
                    }
                    if (registration_data.expires < Date.now()) {
                        return utils.reject("Registration token expired");
                    }
                    registered_by = registration_data.user_id;
                    // Make sure that the email is not taken
                    return utils.query("SELECT user_id FROM users WHERE ?", {
                        email: req.body.email
                    }).catch(utils.handle_err.sql(res));
                }).then(function([user]) {
                    if (user) {
                        return utils.reject("Email already taken");
                    }
                    // Hash the password and insert a new user with an unconfirmed email
                    return bcrypt.hash(req.body.password, 10);
                }).then(function(hashword) {
                    return utils.query("INSERT INTO users SET ?", {
                        user_id: utils.uuid(),
                        email: req.body.email,
                        display_name: req.body.display_name,
                        password: hashword,
                        registered_by: registered_by,
                        email_confirmed: 0
                    }).catch(utils.handle_err.sql(res));
                }).then(function() {
                    // Delete the registration session, the new user is created
                    return utils.query('DELETE FROM registrations WHERE ?', {
                        reg_id: req.body.token
                    }).catch(utils.handle_err.sql(res));
                }).then(function() {
                    // Create a confirmation session and send the confirmation email
                    confirmation_id = utils.uuid();
                    return utils.query("INSERT INTO email_confirmations SET ?", {
                        email: req.body.email,
                        confirmation_id: confirmation_id,
                        expires: Date.now() + time.one_day
                    }).catch(utils.handle_err.sql(res));
                }).then(function() {
                    return mailgun.send_confirmation_email(req.body.email, {
                        query: query_string.stringify({
                            token: confirmation_id
                        })
                    }).catch(utils.handle_err.mailgun(res));
                }).then(function() {
                    // Finally we are done
                    res.send(utils.ok({
                        message: "You must confirm your email to complete registration, please check your inbox"
                    }));
                }).catch(utils.handle_err.res(res, "Error registering your account. Try again or reach out whoever gave you a registration link"));
            }
        ],
        "confirm-email": {
            "": [{
                auth: false
            }, function(req, res) {
                let email;

                utils.validate.keys(req.body, [
                    ['token', utils.validate.uuid]
                ]).then(function() {
                    return utils.query('SELECT * FROM email_confirmations WHERE ?', {
                        confirmation_id: req.body.token
                    }).catch(utils.handle_err.sql(res));
                }).then(function([confirmation]) {
                    if (!confirmation) {
                        return utils.reject("Confirmation token invalid");
                    }
                    if (confirmation.expires < Date.now()) {
                        return utils.reject("Confirmation token expired. Please request a new token");
                    }

                    email = confirmation.email;
                    return utils.query("UPDATE users" + utils.set_where({
                        email_confirmed: 1
                    }, {
                        email: email
                    })).catch(utils.handle_err.sql(res));
                }).then(function() {
                    return utils.query("DELETE FROM email_confirmations WHERE ?", {
                        confirmation_id: req.body.token
                    }).catch(utils.handle_err.sql(res));
                }).then(function() {
                    res.send(utils.ok({
                        message: "Your email is confirmed! You can now log in.",
                        email: email
                    }));
                }).catch(utils.handle_err.res(res, "Error confirming email, try again later"));
            }],
            "request": [{
                auth: false,
                captcha: true
            }, function(req, res) {
                utils.validate.keys(req.body, [
                    ['token', utils.validate.uuid]
                ]).then(function() {
                    return utils.query('SELECT * FROM email_confirmations WHERE ?', {
                        confirmation_id: req.body.token
                    }).catch(utils.handle_err.sql(res));
                }).then(function([confirmation]) {
                    if (!confirmation) {
                        return utils.reject([utils.status.ok, {
                            message: "You email might already be confirmed, please log in",
                            show_login: true
                        }]);
                    }
                    if (confirmation.expires > Date.now()) {
                        return utils.reject("There is already a valid confirmation link, please check your inbox");
                    }
                    return snippets.generate_token(
                        "email_confirmations",
                        "confirmation_id",
                        confirmation.email
                    ).catch(utils.handle_err.sql(res)).then(function(token) {
                        return mailgun.send_confirmation_email(confirmation.email, {
                            query: query_string.stringify({
                                token: token
                            })
                        }).catch(utils.handle_err.mailgun(res)).catch(function(error) {
                            // If the confirmation email fails to send, we need to delete the row
                            // from the email_confirmations table so that it can be sent again.
                            return utils.query("DELETE FROM email_confirmations WHERE ?", {
                                confirmation_id: token
                            }).catch(utils.handle_err.sql(res, true)).finally(function() {
                                return utils.reject(error);
                            });
                        });
                    }).then(function() {
                        res.send(utils.ok({
                            message: "New confirmation email sent, please check your inbox",
                            show_login: false
                        }));
                    });
                }).catch(utils.handle_err.res(res, "Error sending email confirmation link, try again later"));
            }]
        }
    }
};