<commit_before>'use strict';

// modules > native
const url = require('url');
const p = require('path');

// modules > 3rd party
const _ = require('lodash');
const requireDir = require('require-dir');
const nodemailer = require('nodemailer');
const passport = require('passport');

const config = requireDir(p.join(process.cwd(), 'server/config'));
const providers = config.membership.providers || [];

const formatQuery = require('midwest/factories/format-query');
const paginate = require('midwest/factories/paginate');
const factory = require('midwest/factories/rest');

const transport = nodemailer.createTransport(config.smtp);

const handlers = {
  emailTokens: require('../email-tokens/handlers'),
  invites: require('../invites/handlers'),
  permissions: require('../permissions/handlers'),
  roles: require('../roles/handlers'),
  users: require('./handlers'),
};

const { hashPassword } = require('./helpers');

function create(req, res, next) {
  handlers.users.create(req.body, (err, user) => {
    if (err) {
      if (req.body.password) {
        req.body.password = '<PASSWORD>';
      }

      if (req.body.confirmPassword) {
        req.body.confirmPassword = '<PASSWORD>';
      }

      return next(err);
    }

    /* HTTP specification says Location header shoult be included when creating
     * a new entity with POST
     */
    res.set('Location', `${req.url}/${user._id}`)
      .status(201)
      .locals.user = _.omit(user.toJSON(), 'local');

    next();
  });
}

function getRoles(req, email, callback) {
  handlers.invites.findByEmail(email, (err, invite) => {
    if (err) return callback(err);

    let roles = invite ? invite.roles : [];

    handlers.permissions.findMatches(email, (err, permissions) => {
      if (err) {
        callback(err);
      }

      if (permissions) {
        roles = _.union(roles, ...permissions.map((permission) => permission.roles));
      }

      return callback(null, roles, invite);
    });
  });
}

const resetPasswordEmailTemplate = require('./reset-password-email');

const verifyTemplate = require('./verify-email');
const welcomeTemplate = require('./welcome-email');

function resetPasswordWithToken(req, res, next) {
  // hide password in body
  function sendError(err) {
    if (req.body.password) {
      req.body.password = '<PASSWORD>';
    }

    if (req.body.confirmPassword) {
      req.body.confirmPassword = '<PASSWORD>';
    }

    next(err);
  }

  // if (!req.body.email || !req.body.password || !req.body.token) {
  if (!req.body.password) {
    const err = new Error('Not enough parameters');
    err.status = 422;
    return sendError(err);
  }

  // handlers.users.findOne({ email: req.body.email, 'passwordToken.token': req.body.token }, (err, user) => {
  handlers.users.findOne({ email: req.body.email }, (err, user) => {
    if (err) return next(err);

    if (!user) {
      return sendError(Object.assign(new Error('Incorrect token and/or email'), {
        status: 404,
      }));
    }


    // if (Date.now() > user.passwordToken.date + config.membership.timeouts.changePassword) {
    //   return sendError(Object.assign(new Error('Token expired'), {
    //     status: 410,
    //   }));
    // }

    hashPassword(req.body.password, (err, hash) => {
      if (err) return sendError(err);

      handlers.users.updatePassword(user.id, hash, (err) => {
        if (err) return sendError(err);

        res.sendStatus(200);
      });
    });
  });
}

// middleware that checks if an email and token are valid
function checkPasswordToken(req, res, next) {
  handlers.users.findOne({ email: req.find.email, 'passwordToken.token': req.find.token }, (err, user) => {
    if (err) return next(err);

    if (!user) {
      err = new Error('Token not found.');
      err.status = 404;
      return next(err);
    }

    if (user.passwordToken.date.getTime() + (24 * 60 * 60 * 1000) < Date.now()) {
      err = new Error('Token has expired.');
      err.status = 410;
      return next(err);
    }

    next();
  });
}

function exists(property) {
  return (req, res, next) => {
    // TODO maybe return true?
    if (!req.find[property]) {<commit_msg>Send 204 on successful password update<commit_after>'use strict';

// modules > native
const url = require('url');
const p = require('path');

// modules > 3rd party
const _ = require('lodash');
const requireDir = require('require-dir');
const nodemailer = require('nodemailer');
const passport = require('passport');

const config = requireDir(p.join(process.cwd(), 'server/config'));
const providers = config.membership.providers || [];

const formatQuery = require('midwest/factories/format-query');
const paginate = require('midwest/factories/paginate');
const factory = require('midwest/factories/rest');

const transport = nodemailer.createTransport(config.smtp);

const handlers = {
  emailTokens: require('../email-tokens/handlers'),
  invites: require('../invites/handlers'),
  permissions: require('../permissions/handlers'),
  roles: require('../roles/handlers'),
  users: require('./handlers'),
};

const { hashPassword } = require('./helpers');

function create(req, res, next) {
  handlers.users.create(req.body, (err, user) => {
    if (err) {
      if (req.body.password) {
        req.body.password = '<PASSWORD>';
      }

      if (req.body.confirmPassword) {
        req.body.confirmPassword = '<PASSWORD>';
      }

      return next(err);
    }

    /* HTTP specification says Location header shoult be included when creating
     * a new entity with POST
     */
    res.set('Location', `${req.url}/${user._id}`)
      .status(201)
      .locals.user = _.omit(user.toJSON(), 'local');

    next();
  });
}

function getRoles(req, email, callback) {
  handlers.invites.findByEmail(email, (err, invite) => {
    if (err) return callback(err);

    let roles = invite ? invite.roles : [];

    handlers.permissions.findMatches(email, (err, permissions) => {
      if (err) {
        callback(err);
      }

      if (permissions) {
        roles = _.union(roles, ...permissions.map((permission) => permission.roles));
      }

      return callback(null, roles, invite);
    });
  });
}

const resetPasswordEmailTemplate = require('./reset-password-email');

const verifyTemplate = require('./verify-email');
const welcomeTemplate = require('./welcome-email');

function resetPasswordWithToken(req, res, next) {
  // hide password in body
  function sendError(err) {
    if (req.body.password) {
      req.body.password = '<PASSWORD>';
    }

    if (req.body.confirmPassword) {
      req.body.confirmPassword = '<PASSWORD>';
    }

    next(err);
  }

  // if (!req.body.email || !req.body.password || !req.body.token) {
  if (!req.body.password) {
    const err = new Error('Not enough parameters');
    err.status = 422;
    return sendError(err);
  }

  // handlers.users.findOne({ email: req.body.email, 'passwordToken.token': req.body.token }, (err, user) => {
  handlers.users.findOne({ email: req.body.email }, (err, user) => {
    if (err) return next(err);

    if (!user) {
      return sendError(Object.assign(new Error('Incorrect token and/or email'), {
        status: 404,
      }));
    }


    // if (Date.now() > user.passwordToken.date + config.membership.timeouts.changePassword) {
    //   return sendError(Object.assign(new Error('Token expired'), {
    //     status: 410,
    //   }));
    // }

    hashPassword(req.body.password, (err, hash) => {
      if (err) return sendError(err);

      handlers.users.updatePassword(user.id, hash, (err) => {
        if (err) return sendError(err);

        res.sendStatus(204);
      });
    });
  });
}

// middleware that checks if an email and token are valid
function checkPasswordToken(req, res, next) {
  handlers.users.findOne({ email: req.find.email, 'passwordToken.token': req.find.token }, (err, user) => {
    if (err) return next(err);

    if (!user) {
      err = new Error('Token not found.');
      err.status = 404;
      return next(err);
    }

    if (user.passwordToken.date.getTime() + (24 * 60 * 60 * 1000) < Date.now()) {
      err = new Error('Token has expired.');
      err.status = 410;
      return next(err);
    }

    next();
  });
}

function exists(property) {
  return (req, res, next) => {
    // TODO maybe return true?
    if (!req.find[property]) {
{'fraction_non_alphanumeric': 0.1694507871650042, 'fraction_numerical': 0.00805191683691864, 'mean_word_length': 3.035887487875849, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4200365', 'n_tokens_mistral': 2691, 'n_tokens_neox': 2587, 'n_words': 585}