Files
jambonz-api-server/lib/routes/api/activation-code.js
Dave Horton ed51d8b13f merge of features from hosted branch (#7)
major merge of features from the hosted branch that was created temporarily during the initial launch of jambonz.org
2021-06-17 15:56:21 -04:00

118 lines
4.2 KiB
JavaScript

const router = require('express').Router();
const debug = require('debug')('jambonz:api-server');
const {DbErrorBadRequest} = require('../../utils/errors');
const {promisePool} = require('../../db');
const {validateEmail, emailSimpleText} = require('../../utils/email-utils');
const sysError = require('../error');
const sqlRetrieveUser = `SELECT * from users user
LEFT JOIN accounts AS account
ON user.account_sid = account.account_sid
WHERE user.user_sid = ?`;
const validateRequest = async(req, res) => {
const payload = req.body || {};
/* valid type */
if (!['email', 'phone'].includes(payload.type)) {
throw new DbErrorBadRequest(`invalid activation type: ${payload.type}`);
}
/* valid user? */
const [rows] = await promisePool.query('SELECT * from users WHERE user_sid = ?',
payload.user_sid);
if (0 === rows.length) throw new DbErrorBadRequest('invalid user_sid');
/* valid email? */
if (payload.type === 'email' && !validateEmail(payload.value)) throw new DbErrorBadRequest('invalid email');
};
router.post('/', async(req, res) => {
const logger = req.app.locals.logger;
const {user_sid, type, code, value} = req.body;
try {
await validateRequest(req, res);
const fields = type === 'email' ?
['email', 'email_validated', 'email_activation_code'] :
['phone', 'phone_validated', 'phone_activation_code'];
const sql =
`UPDATE users set ${fields[0]} = ?, ${fields[1]} = 0, ${fields[2]} = ? WHERE user_sid = ?`;
const [r] = await promisePool.execute(sql, [value, code, user_sid]);
logger.debug({r}, 'Result from adding activation code');
debug({r}, 'Result from adding activation code');
if (process.env.NODE_ENV !== 'test') {
if (type === 'email') {
/* send code via email */
const text = '';
const subject = '';
await emailSimpleText(logger, value, subject, text);
}
else {
/* send code via SMS */
}
}
res.sendStatus(204);
} catch (err) {
sysError(logger, res, err);
}
});
router.put('/:code', async(req, res) => {
const logger = req.app.locals.logger;
const code = req.params.code;
const {user_sid, type} = req.body;
try {
let activateAccount = false;
let deactivateOldUsers = false;
let account_sid;
if (type === 'email') {
/* check whether this is first-time activation of account during sign-up/register */
const [r] = await promisePool.query({sql: sqlRetrieveUser, nestTables: true}, user_sid);
logger.debug({r}, 'activationcode - selected user');
if (r.length) {
const {user, account} = r[0];
account_sid = account.account_sid;
const [otherUsers] = await promisePool.query('SELECT * from users WHERE account_sid = ? AND user_sid <> ?',
[account_sid, user_sid]);
logger.debug({otherUsers}, `activationcode - users other than ${user_sid}`);
if (0 === otherUsers.length && user.provider === 'local' && !user.email_validated) {
logger.debug('activationcode - activating account');
activateAccount = true;
}
else if (otherUsers.length) {
logger.debug('activationcode - adding new user for existing account');
deactivateOldUsers = true;
}
}
}
const fields = type === 'email' ?
['email_validated', 'email_activation_code'] :
['phone_validated', 'phone_activation_code'];
const sql = `UPDATE users set ${fields[0]} = 1, ${fields[1]} = NULL WHERE ${fields[1]} = ? AND user_sid = ?`;
const [r] = await promisePool.execute(sql, [code, user_sid]);
logger.debug({r}, 'Result from validating code');
debug({r}, 'Result from validating code');
if (activateAccount) {
await promisePool.execute('UPDATE accounts SET is_active=1 WHERE account_sid = ?', [account_sid]);
}
else if (deactivateOldUsers) {
const [r] = await promisePool.execute('DELETE FROM users WHERE account_sid = ? AND user_sid <> ?',
[account_sid, user_sid]);
logger.debug({r}, 'Result from deleting old/replaced users');
}
if (1 === r.affectedRows) return res.sendStatus(204);
throw new DbErrorBadRequest('invalid user or activation code');
} catch (err) {
sysError(logger, res, err);
}
});
module.exports = router;