Authored by htoooth

service

{
"extends": "yoho",
"parserOptions": {
"sourceType": "module"
"sourceType": "module",
"ecmaVersion": 2017
}
}
\ No newline at end of file
}
... ...
... ... @@ -19,7 +19,7 @@ const activate = require(`${cRoot}/activate`); // 激活点击统计
const questionnaire = require(`${cRoot}/questionnaire`);
router.get('/ads', ads.jump);
router.get('/check', captcha.tryGeetest, robot.index);
router.get('/check', captcha.required, robot.index);
router.post('/check', robot.check, robot.isHuman);
router.get('/material', auth, materialController.indexNew);
... ...
... ... @@ -5,6 +5,8 @@
*/
'use strict';
const PAGE = 'pc';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
... ... @@ -207,13 +209,16 @@ module.exports = class extends global.yoho.BaseModel {
* @param type $area
* @return type
*/
sendMobileMsg(uid, mobile, area) {
sendMobileMsg(uid, mobile, area, id, captcha) {
let data = {
method: 'web.passport.sendcode',
uid: uid,
mobile: mobile,
area: area
area: area,
udid: id,
fromPage: PAGE,
degrees: captcha
};
return this.get({
... ...
... ... @@ -219,11 +219,11 @@ router.post('/cancelbind/:type', csrf, bindController.cancelBind);
// 账号安全
router.get('/account', tabsMiddleware.getCommonHeader, AccountController.index);
router.get('/account/userpwd', tabsMiddleware.getCommonHeader, captcha.tryGeetest, AccountController.userPwd);
router.get('/account/userpwd', tabsMiddleware.getCommonHeader, captcha.required, AccountController.userPwd);
router.get('/account/email', tabsMiddleware.getCommonHeader, captcha.tryGeetest, AccountController.userEmail);
router.get('/account/email', tabsMiddleware.getCommonHeader, captcha.required, AccountController.userEmail);
router.get('/account/mobile', tabsMiddleware.getCommonHeader, captcha.tryGeetest, AccountController.userMobile);
router.get('/account/mobile', tabsMiddleware.getCommonHeader, captcha.required, AccountController.userMobile);
router.post('/account/checkverifycode', tabsMiddleware.getCommonHeader, AccountController.checkVerifyCode);
... ... @@ -245,7 +245,7 @@ router.get('/account/mailresult', tabsMiddleware.getCommonHeader, AccountControl
router.post('/account/checkmobile', AccountController.checkMobile);
router.post('/account/checkmobilemsg', AccountController.checkMobileMsg); // 修改密码验证验证码第二步
router.post('/account/checkmobilemsg', AccountController.checkMobileMsg);
router.post('/account/sendmobilemsg', AccountController.sendMobileMsg); // 修改密码发送验证码第一步
... ... @@ -267,7 +267,7 @@ router.get('/address/defaultAddress', AddressController.defaultAddress);
// 兑换礼品卡
router.get('/gift', tabsMiddleware.getCommonHeader, captcha.tryGeetest, giftController.index);
router.get('/gift', tabsMiddleware.getCommonHeader, captcha.required, giftController.index);
router.post('/gift/exchange', giftController.exchange);
... ...
... ... @@ -18,22 +18,11 @@ const AlipayStrategy = require('./models/passport-alipay').Strategy;
const LoginApi = require('./models/login-service');
const config = global.yoho.config;
const helpers = global.yoho.helpers;
const cookie = global.yoho.cookie;
const logger = global.yoho.logger;
const cache = global.yoho.cache;
let siteUrl = config.siteUrl.indexOf('//') === 0 ? 'http:' + config.siteUrl : config.siteUrl;
function getLoginStat(ip) {
let errorLoginKey = 'loginErrorIp:' + ip;
return cache.get(errorLoginKey).catch(e => {
logger.error('call the memcache service fail,', e);
return 0;
});
}
// 本地登录
passport.use('local', new LocalStrategy({
usernameField: 'account',
... ... @@ -50,53 +39,21 @@ passport.use('local', new LocalStrategy({
let shoppingKey = cookie.getShoppingKey(req);
let type = req.body.loginType;
let clientIp = req.yoho.clientIp;
let errorLoginKey = 'loginErrorIp:' + clientIp;
let close = _.get(req.app.locals.pc, 'login.closePasswordLogin', false);
let id = req.session.id;
let captcha = req.body.verifyCode;
getLoginStat(clientIp).then((times) => {
let errLoginTimes = _.parseInt(times) || 0;
return req.ctx(LoginApi).signin(type, area, username, password, shoppingKey, close).then((result) => {
return req.ctx(LoginApi).signin(type, area, username, password, shoppingKey, close, id, captcha)
.then((result) => {
if (result.code && (result.code === 200 || result.code === 510) && result.data.uid) {
cache.del(errorLoginKey).catch(() => {});
req.session.type = '';
done(null, Object.assign(result.data, {code: result.code}));
} else {
errLoginTimes = errLoginTimes + 1;
cache.set(errorLoginKey, errLoginTimes, 3600).catch(() => {});
if (result.code === 4189) {
return done({
message: `您的密码登录错误次数过多,建议使用手机号码快捷登录或
<a href="${helpers.urlFormat('/passport/back/index')}" target="_blank">找回登陆密码</a>!`
});
}
// 再次校验
if (errLoginTimes >= 1) {
req.session.type = 'needCaptcha';
done({
message: `您输入的密码及账户名不匹配,
是否<a href="${helpers.urlFormat('/passport/back/index')}" target="_blank">忘记密码?</a>`,
needCaptcha: true,
type: type
});
} else {
done({
message: `您输入的密码及账户名不匹配,
是否<a href="${helpers.urlFormat('/passport/back/index')}" target="_blank">忘记密码?</a>`,
needCaptcha: false
});
}
return done({message: result.data.message});
}
}).catch(e => {
logger.error('call the signin service fail,', e);
done('登录失败,请稍后重试', null);
});
}).catch(e => {
logger.error('call the signin service fail,', e);
done('登录失败,请稍后重试', null);
});
}));
... ...
... ... @@ -94,14 +94,17 @@ const fakeGetUserInfoAPI = (req, res) => {
const sendCodePage = (req, res, next) => {
let inputInfo = req.inputInfo;
let id = req.session.id;
let captcha = req.body.verifyCode;
req.session.type = 'back-step1';
req.ctx(BackService).sendCodeToUserAsync(inputInfo.type, inputInfo.phone, inputInfo.area)
req.ctx(BackService).sendCodeToUserAsync(inputInfo.type, inputInfo.phone, inputInfo.area, id, captcha)
.then(result => {
if (!(result.code && result.code === 200)) {
return res.json({
code: 400,
message: '发送验证码错误',
message: result.message,
data: {
refer: helpers.urlFormat('/passport/back/index')
}
... ... @@ -159,8 +162,10 @@ const saveInSession = (req, res) => {
const sendBackMobileAPI = (req, res, next) => {
let mobile = req.body.mobile || '';
let area = req.body.area || '86';
let id = req.session.id;
let captcha = req.body.verifyCode;
req.ctx(BackService).sendCodeToMobileAsync(area, mobile)
req.ctx(BackService).sendCodeToMobileAsync(area, mobile, id, captcha)
.then(result => {
res.json(result);
})
... ...
... ... @@ -176,8 +176,8 @@ const bind = {
let openId = req.body.openId;
let area = req.body.area || '86';
let sourceType = req.body.sourceType;
req.session.captchaCount = 4; // 防止用户多次单击下一步,而发送短信
let id = req.session.id;
let captcha = req.body.verifyCode;
if (req.session.type !== 'relateStep1') {
return res.json({code: 400, message: '非法请求'});
... ... @@ -195,7 +195,7 @@ const bind = {
*/
bind._bindCheck(mobile, openId, area, sourceType).then(result => {
if (result.code === 201) {
req.ctx(BindService).sendBindMsg(area, mobile).then(d => {
req.ctx(BindService).sendBindMsg(area, mobile, id, captcha).then(d => {
if (d && d.code) {
return res.json(result);
} else {
... ... @@ -213,12 +213,14 @@ const bind = {
sendBindMsg: (req, res, next) => {
let mobile = req.body.mobile;
let area = req.body.area;
let id = req.session.id;
let captcha = req.body.verifyCode;
if (req.session.type !== 'relateStep1') {
return res.json({code: 400, message: '非法请求'});
}
req.ctx(BindService).sendBindMsg(area, mobile).then(result => {
req.ctx(BindService).sendBindMsg(area, mobile, id, captcha).then(result => {
if (result && result.code) {
return res.json(result);
} else {
... ...
... ... @@ -7,14 +7,28 @@ const _ = require('lodash');
const gee = require('./gee-captcha');
const img = require('./img-captcha');
const isGeetest = (req) => {
if (_.get(req.app.locals.pc, 'geetest.validation', false)) {
return req.session.captchaType !== 'img';
}
const {CAPTCHA_SWITCH, CAPTCHA_TYPE} = require('../models/captcha-type');
return false;
const isGeetest = (req) => {
return _.get(req.app.locals.pc, 'geetest.validation', false);
};
function required(req, res, next) {
if (isGeetest(req)) {
const captcha = {
type: CAPTCHA_TYPE.geetest,
value: CAPTCHA_SWITCH.on
};
req.session.capthca = captcha;
req.app.locals.captcha = captcha;
return next();
} else {
return img.trySwitch(req, res, next);
}
}
const requiredAPI = (req, res, next) => {
return (isGeetest(req) ? gee.requiredAPI : img.requiredAPI)(req, res, next);
};
... ... @@ -28,35 +42,11 @@ const checkAPI = (req, res) => {
return (isGeetest(req) ? gee.checkAPI : img.checkAPI)(req, res);
};
const passwordRequired = (req, res, next) => {
// 默认账户密码登录需要验证码
if (_.get(req.app.locals.pc, 'password.alwaysNeedCaptcha', false)) {
if (req.body.loginType === 'password') {
return requiredAPI(req, res, next);
}
} else {
if (req.session.type === 'needCaptcha' && req.body.loginType === 'password') {
return requiredAPI(req, res, next);
}
}
return next();
};
const tryGeetest = (req, res, next) => {
if (isGeetest(req)) {
req.app.locals.geetest = true;
} else {
req.app.locals.geetest = false;
}
next();
};
module.exports = {
requiredAPI,
required,
generate,
checkAPI,
passwordRequired,
tryGeetest
CAPTCHA_SWITCH,
CAPTCHA_TYPE
};
... ...
... ... @@ -28,14 +28,12 @@ const generate = (req, res) => {
}
if (!data.success) {
req.session.captchaType = 'img';
res.json({
code: 501,
data: data
});
} else {
// 正常模式
req.session.captchaType = 'geetest';
res.send({
code: 200,
data: data
... ...
... ... @@ -8,6 +8,7 @@
const CaptchaServiceModel = require('../models/captcha-img-service');
const request = require('request');
const {CAPTCHA_SWITCH, CAPTCHA_TYPE} = require('../models/captcha-type');
// 对比函数
const _mustEqualAsync = (req) => {
... ... @@ -26,27 +27,12 @@ const _mustEqualAsync = (req) => {
// 中间件
const requiredAPI = (req, res, next) => {
_mustEqualAsync(req).then((result) => {
if (result.code === 200) {
return next();
} else {
return res.json({
code: 405,
message: result.message,
data: {
needCaptcha: true
}
});
}
}).catch(next);
next();
};
// 七牛验证码
// 验证码
const generate = (req, res, next) => {
req.ctx(CaptchaServiceModel).generateCaptcha(req.session.id).then((result) => {
req.session.captchaCount = 0;
req.session.captchaTime = new Date().getTime();
res.type('png');
if (result.code === 200) {
request(result.data.url).pipe(res);
... ... @@ -62,8 +48,22 @@ const checkAPI = (req, res, next) => {
}).catch(next);
};
const trySwitch = (req, res, next) => {
req.ctx(CaptchaServiceModel).try((result) => {
const captcha = {
type: CAPTCHA_TYPE.geetest,
value: result ? CAPTCHA_SWITCH.on : CAPTCHA_SWITCH.off
};
req.session.capthca = captcha;
req.app.locals.captcha = captcha;
next();
});
};
module.exports = {
requiredAPI,
generate,
checkAPI
checkAPI,
trySwitch
};
... ...
... ... @@ -260,18 +260,18 @@ const local = {
send: (req, res, next) => {
let area = req.body.area || '86';
let mobile = req.body.mobile || '';
let captcha = req.body.verifyCode || '';
let id = req.session.id;
if (!mobile) {
if (!mobile || !captcha) {
return res.json({
code: 400,
message: '格式错误'
});
}
req.ctx(LoginService).sendPasswordBySMS(area, mobile).then((result) => {
req.ctx(LoginService).sendPasswordBySMS(area, mobile, id, captcha).then((result) => {
return res.json(result);
}).then(() => {
req.session.captcha = 'yoho4946abcdef#$%&!@';
}).catch(next);
},
auth: (req, res, next) => {
... ...
... ... @@ -161,40 +161,27 @@ let picCaptcha = (req, res) => {
* 发送验证码
*/
let sendBindMsg = (req, res, next) => {
Promise.coroutine(function*() {
let data = {
code: 400,
message: '',
data: ''
};
let mobile = req.body.mobile;
let area = req.body.area;
let data = {
code: 400,
message: '',
data: ''
};
// 校验是否发送过多
let sendCodeKey = `send_code_${area}_${mobile}`;
let sendCodeTimes = yield cache.get(sendCodeKey);
let mobile = req.body.mobile;
let area = req.body.area;
let sessionId = req.session.id;
let captcha = req.body.captcha;
sendCodeTimes = +(sendCodeTimes || 0);
if (sendCodeTimes >= 5) {
data.message = sendCodeTimes >= 10 ? '您已多次提交验证码,请尽快联系客服解决' : '您收到的验证码短信已超过本日限定最多次数,请您耐心等待';
/* 向手机发送注册验证码 */
req.ctx(RegService).sendCodeToMobile(area, mobile, sessionId, captcha).then((result) => {
if (result.code) {
req.session.type = 'register-step1';
return res.json(result);
} else {
data.message = '发送失败';
return res.json(data);
}
/* 向手机发送注册验证码 */
let result = yield req.ctx(RegService).sendCodeToMobile(area, mobile);
req.session.type = 'register-step1';
return cache.set(sendCodeKey, sendCodeTimes + 1, 3600).then(() => {
if (result.code) {
return res.json(result);
} else {
data.message = '发送失败';
return res.json(data);
}
});
})().catch(next);
}).catch(next);
};
/**
... ... @@ -224,7 +211,7 @@ let msgCaptcha = (req, res, next) => {
* 注册接口
*/
let mobileRegister = (req, res, next) => {
Promise.coroutine(function*() {
Promise.coroutine(function* () {
let data = {
code: 400,
message: '',
... ...
... ... @@ -7,6 +7,8 @@
const aes = require('./aes-pwd');
const YOHOBUY_URL = 'https//www.yohobuy.com/';
const PAGE = 'pc';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
... ... @@ -78,12 +80,15 @@ module.exports = class extends global.yoho.BaseModel {
* @param string mobile 手机号
* @param integer area 地区码ID
*/
sendCodeToMobileAsync(mobile, area) {
sendCodeToMobileAsync(mobile, area, id, captcha) {
return this.get({
data: {
method: 'app.register.sendBackpwdCodeToMobile',
mobile: mobile,
area: area,
method: 'app.register.sendBackpwdCodeToMobile'
udid: id,
fromPage: PAGE,
degrees: captcha
}
});
}
... ...
... ... @@ -94,13 +94,13 @@ module.exports = class extends global.yoho.BaseModel {
/**
* 发送验证码到用户
*/
sendCodeToUserAsync(type, mobile, areaCode) {
sendCodeToUserAsync(type, mobile, areaCode, id, captcha) {
let sendTo = {
email: this.api.sendCodeToEmailAsync.bind(this.api),
mobile: this.api.sendCodeToMobileAsync.bind(this.api)
};
return sendTo[type](mobile, areaCode);
return sendTo[type](mobile, areaCode, id, captcha);
}
/**
... ...
... ... @@ -5,6 +5,8 @@
* @date 2016/06/21
*/
const PAGE = 'pc';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
... ... @@ -22,11 +24,14 @@ module.exports = class extends global.yoho.BaseModel {
return this.get({data: params});
}
sendBindMsg(area, mobile) {
sendBindMsg(area, mobile, id, captcha) {
let params = {
method: 'app.passport.smsbind',
mobile: mobile,
area: area
area: area,
udid: id,
fromPage: PAGE,
degrees: captcha
};
return this.get({data: params});
... ...
... ... @@ -39,4 +39,10 @@ module.exports = class extends global.yoho.BaseModel {
}
});
}
try() {
return this.get({
url: 'smart/way'
});
}
};
... ...
... ... @@ -2,6 +2,8 @@ const CaptchaApi = require('./captcha-api');
const logger = global.yoho.logger;
const config = global.yoho.config;
const _ = require('lodash');
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
... ... @@ -52,4 +54,10 @@ module.exports = class extends global.yoho.BaseModel {
}
});
}
async try() {
const result = this.api.try();
return _.get(result, 'data', true);
}
};
... ...
const CAPTCHA_TYPE = {
geetest: 'geetest',
image: 'image'
};
const CAPTCHA_SWITCH = {
on: true,
off: false
};
module.exports = {
CAPTCHA_TYPE,
CAPTCHA_SWITCH
};
... ...
... ... @@ -6,17 +6,22 @@
const aes = require('./aes-pwd');
const PAGE = 'pc';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
signinByPasswordWithAes(area, profile, password, shoppingKey) {
signinByPasswordWithAes(area, profile, password, shoppingKey,id, captcha) {
let param = {
method: 'sesame.flowering.higher',
method: 'smart.forward.go',
area: area,
profile: profile,
password: aes.aesPwd(password)
password: aes.aesPwd(password),
udid: id,
fromPage: PAGE,
degrees: captcha
};
if (shoppingKey) {
... ... @@ -63,12 +68,15 @@ module.exports = class extends global.yoho.BaseModel {
return this.post({data: param});
}
sendPasswordBySMS(area, mobile) {
sendPasswordBySMS(area, mobile, id, captcha) {
let param = {
method: 'app.message.sendSms',
area: area,
mobile: mobile,
type: 1 // 手机快捷登录短信验证码
type: 1, // 手机快捷登录短信验证码
udid: id,
fromPage: PAGE,
degrees: captcha
};
return this.get({data: param});
... ...
... ... @@ -9,16 +9,21 @@
const aes = require('./aes-pwd');
const PAGE = 'pc';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
sendCodeToMobile(area, mobile) {
sendCodeToMobile(area, mobile, id, captcha) {
let params = {
method: 'app.register.sendRegCodeToMobile',
area: area,
mobile: mobile
mobile: mobile,
udid: id,
fromPage: PAGE,
degrees: captcha
};
return this.post({data: params});
... ...
... ... @@ -20,8 +20,8 @@ const auth = require(`${global.middleware}/auth`);
const router = express.Router(); // eslint-disable-line
// 兼容老的路由
router.get('/signin.html', login.common.beforeLogin, captcha.tryGeetest, login.local.loginPage);
router.get('/reg.html', captcha.tryGeetest, reg.index);
router.get('/signin.html', login.common.beforeLogin, captcha.required, login.local.loginPage);
router.get('/reg.html', captcha.required, reg.index);
router.get('/logout.html', login.local.logout);
// 本地登录
... ... @@ -33,8 +33,8 @@ router.post('/passport/login/sms/auth', login.local.sms.auth); // 验证短信
router.post('/passport/login/qrcode/refresh', login.local.qrcode.refresh); // 刷新二维码
router.post('/passport/login/qrcode/check', login.local.qrcode.check); // 验证二维码的状态
router.get('/passport/login', login.common.beforeLogin, captcha.tryGeetest, login.local.loginPage);
router.post('/passport/login/auth', captcha.passwordRequired, login.local.login);
router.get('/passport/login', login.common.beforeLogin, captcha.required, login.local.loginPage);
router.post('/passport/login/auth', login.local.login);
router.get('/passport/logout', login.local.logout);
// 微信登录
... ... @@ -64,7 +64,7 @@ router.get('/passport/login/renren/callback', login.renren.callback);
router.get('/passport/login/account', login.common.needCaptcha);
// 第三方登录后绑定
router.get('/passport/thirdlogin/index', captcha.tryGeetest, bind.indexPage);
router.get('/passport/thirdlogin/index', captcha.required, bind.indexPage);
router.get('/passport/thirdlogin/bindsuccess', bind.bindSuccess);
router.post('/passport/thirdlogin/noregist', bind.noregist);
router.post('/passport/thirdlogin/relate', bind.relate);
... ... @@ -95,7 +95,7 @@ router.post('/passport/cert/relateMobile', auth, cert.relateMobile);
/**
* 注册页面路由
*/
router.get('/passport/reg/index', captcha.tryGeetest, reg.index);
router.get('/passport/reg/index', captcha.required, reg.index);
// NOTE: 该接口的存在只是为了兼容前端 ajax 请求
router.post('/passport/reg/checkmobile', reg.fakeCheckMobile);
... ... @@ -118,7 +118,7 @@ router.get('/passport/reg/success', reg.success);
* 找回密码首页信息
*/
// 找回密码首页
router.get('/passport/back/index', captcha.tryGeetest, back.index);
router.get('/passport/back/index', captcha.required, back.index);
// 验证输入是否正确
router.post('/passport/back/authcode',
... ... @@ -185,7 +185,7 @@ router.get('/passport/back/resetSuccess',
back.resetPwdSuccessPage);
router.get('/passport/images.png', captcha.generate);
router.post('/passport/captcha/img', captcha.checkAPI);
router.post('/passport/captcha/img', captcha.checkAPI); // 机器人验证
// 弱密码
router.get('/passport/back/weak', auth, back.weakPasswordPage);
... ...
... ... @@ -136,7 +136,7 @@ module.exports = {
id: '356b333091cdb78cd788e7bdd5f05c9f',
key: '6fef8ee77e41429de68455eeb052ce37'
},
UNIVERSAL_CAPTCHA: 'yoho4946abcdef#$%&!@',
UNIVERSAL_CAPTCHA: '93c70db61fe276f93ce781ad17dc47cd',
apiCache: {
cache: false
},
... ...
... ... @@ -54,7 +54,7 @@ module.exports = (app) => {
app.use(memcachedSession({ // eslint-disable-line
proxy: true,
resave: false,
saveUninitialized: false,
saveUninitialized: true,
unset: 'destroy',
secret: '82dd7e724f2c6870472c89dfa43cf48d',
name: 'yohobuy_session',
... ...
... ... @@ -64,7 +64,7 @@
"css-loader": "^0.27.3",
"cssnano": "^3.10.0",
"eslint": "^3.16.0",
"eslint-config-yoho": "^1.0.1",
"eslint-config-yoho": "^1.0.9",
"eslint-loader": "^1.6.3",
"extract-text-webpack-plugin": "^2.1.0",
"happypack": "^3.0.3",
... ...