back.js 10.5 KB
/**
 * 找回密码
 * Created by Tao.Huang on 2016/6/12.
 */

'use strict';

const _ = require('lodash');

const helpers = global.yoho.helpers;
const sign = global.yoho.sign;
const service = require('../models/back-service');
const captchaService = require('../models/captcha-service');

const SIGN_IN = helpers.urlFormat('/signin.html');

/**
 * 通过邮箱找回密码页面
 */
const indexEmailPage = (req, res) => {
    res.render('back/email', Object.assign(
        {
            module: 'passport',
            page: 'back-email',
            title: '找回密码-通过邮箱'
        }, {
            // backUrl: SIGN_IN,
            headerText: '找回密码',
            isPassportPage: true,
            backEmail: true
        }
    ));
};

/**
 * 发送验证码到邮箱
 */
const sendCodeToEmailAPI = (req, res) => {
    let email = req.body.email || '';
    const ERR = {
        code: 400,
        message: '邮箱格式不正确,请重新输入',
        data: ''
    };

    if (!helpers.verifyEmail(email)) {
        res.json(ERR);
        return;
    }

    service.sendCodeToEmailAsync(email)
        .then(result => {
            if (result.code === 200) {
                result.data = helpers.urlFormat('/passport/back/success', { email: email });
            }

            res.json(result);
        })
        .catch(() => {
            res.json(ERR);
        });
};

/**
 * 重新发送验证码到邮箱
 */
const resendCodeToEmailAPI = (req, res) => {
    let email = req.query.email || '';

    service.sendCodeToEmailAsync(email)
        .then(result => {
            if (_.isEmpty(result)) {
                return Promise.rejected('重新发邮件失败');
            }

            res.json(result);
        })
        .catch(err => {
            res.json({
                code: 400,
                message: err
            });
        });
};

/**
 * 邮箱找回密码-返回成功页面
 */
const backSuccessByEmailPage = (req, res) => {
    let email = req.query.email || '';

    if (!helpers.verifyEmail(email)) {
        res.redirect(400);
    }

    let domain = email.split('@')[1];
    let emailUrl = `http://${domain === 'gmail.com' ? 'mail.google.com' : 'mail.'}${domain}`;

    res.render('back/email-success', Object.assign({
        module: 'passport',
        page: 'back-email-success',
        title: '找回密码-通过邮箱'
    }, {
        // backUrl: helpers.urlFormat('/passport/back/email'),
        headerText: '找回密码',
        isPassportPage: true,
        backEmailSuccess: true,
        goEmail: emailUrl,
        resendUrl: helpers.urlFormat('/passport/back/resendemail', { email: email })
    }));
};

/**
 * 根据邮箱修改密码
 */
const setNewPasswordByEmailAPI = (req, res) => {
    let pwd = req.body.password || '';
    let code = req.body.code || '';
    let data = {
        code: 200,
        data: SIGN_IN
    };

    service.modifyPasswordByEmailAsyncAes(pwd, code)
        .then(result => {
            if (result.includes('history.back')) {
                data.code = 400;
                data.message = '修改失败';
            }

            res.json(data);
        })
        .catch(() => {
            res.json(data);
        });
};

/**
 * 找回密码页面-通过手机号
 */
const indexMobilePage = (req, res, next) => {
    _.set(req.session, 'backupCaptch.verifyResult', false);

    if (req.session.captchaValidCount == null) { // eslint-disable-line
        req.session.captchaValidCount = 5;
    }

    service.getAreaDataAsync()
        .then(result => {
            res.render('back/mobile', Object.assign({
                width750: true,
                module: 'passport',
                page: 'back-mobile',
                title: '找回密码-通过手机号'
            }, {
                // backUrl: SIGN_IN,
                headerText: '找回密码',
                isPassportPage: true,
                backMobile: true,
                countrys: result.data,
                areaCode: '+86',
                verifySrc: helpers.urlFormat('/passport/back/generatecodeimg.png', {t: Date.now()})
            }));
        })
        .catch(next);
};

/**
 * 生成验证码
 * @param req
 * @param res
 */
const generateCodeImg = (req, res) => {
    let verifyCodeImg = captchaService.generateCaptcha(109, 50, 4);

    if (verifyCodeImg) {

        if (req.session.backupCaptch) {
            req.session.backupCaptch.code = verifyCodeImg.text;
            req.session.backupCaptch.verifyResult = false;
        } else {
            req.session.backupCaptch = {
                code: verifyCodeImg.text,
                verifyResult: false
            };
        }

        res.set('Cache-Control', 'no-cache').send(verifyCodeImg.image);
    }
};

/**
 * 发送手机验证码
 */
const sendCodeToMobileAPI = (req, res, next) => {
    let phoneNum = req.body.phoneNum || '';
    let areaCode = req.body.areaCode || '86';

    let ERR = {
        code: 400,
        message: '输入手机号码出错'
    };

    if (!helpers.verifyMobile(phoneNum)) {
        return res.json(ERR);
    }

    let backCount = _.get(req.session, 'backupCaptch.count'); // 短信验证码 发送次数

    if (!backCount) {
        /* 如果设置了冻结时间,验证 */
        let untilTime = (parseInt(req.session.backupCaptch.timeout, 10) -
            parseInt(Date.now(), 10)) / 1000 / 60;

        if (parseInt(Date.now(), 10) < parseInt(req.session.backupCaptch.timeout, 10)) {
            return res.json({
                code: 401,
                message: '请' + (parseInt(untilTime, 10) + 1) + '分钟后尝试!'
            });
        } else {
            _.set(req.session, 'backupCaptch.count', 5);
        }
    }

    _.set(req.session, 'backupCaptch.verifyResult', true);
    service.sendCodeToMobileAsync(phoneNum, areaCode)
        .then(result => {
            if (_.isEmpty(result) || result.code !== 200) {
                ERR.message = '发送验证码出错';
                res.json(ERR);
            }

            if (result.code === 200) {
                let token = sign.makeToken(phoneNum);

                --req.session.backupCaptch.count;

                if (!req.session.backupCaptch.count) {
                    _.set(req.session, 'backupCaptch.timeout', Date.now() + 5 * 60 * 1000);
                }

                req.session.backupCaptchStep2 = true; // 允许跳到第二步

                return res.json({
                    code: 200,
                    data: {
                        href: helpers.urlFormat('/passport/back/mobilecode', {
                            phoneNum: phoneNum,
                            areaCode: areaCode
                        }),
                        token: token
                    }
                });
            }
        })
        .catch(next);
};

/**
 * 校验验证码页面
 */
const verifyCodeByMobilePage = (req, res) => {
    let phoneNum = req.query.phoneNum || '';
    let areaCode = req.query.areaCode || '86';

    /* 用户直接进入第二个页面的情况 */
    if (!_.get(req, 'session.backupCaptch.verifyResult')) {
        return res.redirect(helpers.urlFormat('/'));
    }

    res.render('back/mobile-code', Object.assign({
        module: 'passport',
        page: 'back-code',
        title: '找回密码-通过手机号'
    }, {
        // backUrl: helpers.urlFormat('/passport/back/mobile'),
        headerText: '找回密码',
        isPassportPage: true,
        backCode: true,
        areaCode: areaCode,
        phoneNum: phoneNum,
        verifySrc: helpers.urlFormat('/passport/back/generatecodeimg.png', {t: Date.now()})
    }));
};

/**
 * 校验手机验证码
 */
const verifyCodeByMobileAPI = (req, res, next) => {
    let phoneNum = req.body.phoneNum || '';
    let code = req.body.code || '';
    let areaCode = req.body.areaCode || '86';

    service.validateMobileCodeAsync(phoneNum, code, areaCode)
        .then(result => {
            if (result.code === 200 && result.data) {
                req.session.backcode = {
                    phoneNum: phoneNum,
                    token: result.data.token,
                    areaCode: areaCode,
                    code: code
                };

                res.json({
                    code: 200,
                    data: helpers.urlFormat('/passport/back/backcode')
                });
            } else {
                res.json({
                    code: 400,
                    message: '验证码失败'
                });
            }
        })
        .catch(next);
};

/**
 * 找回密码页面,设置新密码页面-手机
 */
const setNewPasswordByMobilePage = (req, res) => {
    let backcode = req.session.backcode;

    if (!backcode || !(backcode.code || (backcode.token && helpers.verifyMobile(backcode.phoneNum)))) {
        res.redirect(400);
        return;
    }

    req.session.backcode = null;

    res.render('back/new-password', Object.assign({
        module: 'passport',
        page: 'back-new-password',
        title: '找回密码-输入新密码'
    }, {
        // backUrl: SIGN_IN,
        headerText: '找回密码',
        isPassportPage: true,
        backNewPwd: true,
        phoneNum: backcode.phoneNum,
        token: backcode.token,
        areaCode: backcode.areaCode,
        code: backcode.code
    }));
};

/**
 * 根据手机验证码修改密码
 */
const setNewPasswordByMobileAPI = (req, res, next) => {
    let phoneNum = req.body.phoneNum || '';
    let token = req.body.token || '';
    let areaCode = req.body.areaCode || '86';
    let newPwd = req.body.password || '';

    service.modifyPasswordByMobileAsyncAes(phoneNum, token, newPwd, areaCode)
        .then(result => {
            if (result.code === 200) {
                res.json({
                    code: 200,
                    data: SIGN_IN
                });
            } else {
                res.json({
                    code: 400,
                    message: '修改密码失败'
                });
            }
        })
        .catch(next);
};

/**
 * 直接调用发短信接口的情况
 */
const verifySmsAllow = (req, res, next) => {
    if (_.get(req, 'session.backupCaptch.verifyResult')) {
        return next();
    } else {
        return res.json({
            code: 400,
            message: '非法请求'
        });
    }
};

module.exports = {
    indexEmailPage,
    sendCodeToEmailAPI,
    resendCodeToEmailAPI,
    backSuccessByEmailPage,
    setNewPasswordByEmailAPI,
    indexMobilePage,
    sendCodeToMobileAPI,
    verifyCodeByMobilePage,
    verifyCodeByMobileAPI,
    setNewPasswordByMobilePage,
    setNewPasswordByMobileAPI,
    generateCodeImg,
    verifySmsAllow
};