Authored by ccbikai(👎🏻🍜)

Merge branch 'feature/captcha'

@@ -24,7 +24,10 @@ const favicon = require('serve-favicon'); @@ -24,7 +24,10 @@ const favicon = require('serve-favicon');
24 const uuid = require('uuid'); 24 const uuid = require('uuid');
25 25
26 const pkg = require('./package.json'); 26 const pkg = require('./package.json');
27 -const session = require('client-sessions'); 27 +const cookieSession = require('client-sessions');
  28 +const memcachedSession = require('yoho-express-session');
  29 +const memcached = require('connect-memcached');
  30 +const MemcachedStore = memcached(memcachedSession);
28 const _ = require('lodash'); 31 const _ = require('lodash');
29 32
30 const app = express(); 33 const app = express();
@@ -73,25 +76,63 @@ app.use(bodyParser.urlencoded({ @@ -73,25 +76,63 @@ app.use(bodyParser.urlencoded({
73 app.use(cookieParser()); 76 app.use(cookieParser());
74 app.use(compression()); 77 app.use(compression());
75 78
76 -app.use(session({  
77 - requestKey: 'session', 79 +app.use(memcachedSession({
  80 + proxy: true,
  81 + resave: false,
  82 + saveUninitialized: true,
  83 + unset: 'destroy',
  84 + secret: '82dd7e724f2c6870472c89dfa43cf48d',
  85 + name: 'yohobuy_session',
  86 + cookie: {
  87 + domain: 'yohobuy.com',
  88 + httpOnly: false
  89 + },
  90 + store: new MemcachedStore({
  91 + hosts: config.memcache.session,
  92 + prefix: 'yohobuy_session:',
  93 + reconnect: 5000,
  94 + timeout: 1000,
  95 + retries: 0
  96 + })
  97 +}));
  98 +
  99 +app.use(cookieSession({
  100 + requestKey: 'session2',
78 cookieName: 'yohobuy_session_cookie', 101 cookieName: 'yohobuy_session_cookie',
79 secret: '82dd7e724f2c6870472c89dfa43cf48d', 102 secret: '82dd7e724f2c6870472c89dfa43cf48d',
80 domain: config.cookieDomain 103 domain: config.cookieDomain
81 })); 104 }));
82 105
83 app.use((req, res, next) => { 106 app.use((req, res, next) => {
84 - req.user = {}; // 全局的用户数据  
85 - req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等  
86 - req.app.locals.wap = app.locals.wap; // zookeper对象赋值  
87 - if (!req.session) {  
88 - req.session = {}; 107 + if (req.session) {
  108 + let sessionKeys = Object.keys(req.session || {});
  109 + let backSessionKeys = Object.keys(req.session2.sessionBack || {});
  110 +
  111 + if (backSessionKeys.length > sessionKeys.length) {
  112 + let differences = _.difference(backSessionKeys, sessionKeys);
  113 +
  114 + _.forEach(differences, d => {
  115 + req.session[d] = req.session2.sessionBack[d];
  116 + });
  117 + }
  118 + req.session2.sessionBack = req.session;
  119 + } else {
  120 + req.session = new memcachedSession.Session(req);
  121 + req.session = _.assign(req.session, req.session2.sessionBack);
89 } 122 }
90 - if (!req.session.id) {  
91 - req.session.id = uuid.v4(); 123 +
  124 + if (!req.sessionID) {
  125 + req.sessionID = uuid.v4();
92 } 126 }
93 127
94 - req.sessionID = req.session.id; 128 + next();
  129 +});
  130 +
  131 +
  132 +app.use((req, res, next) => {
  133 + req.user = {}; // 全局的用户数据
  134 + req.yoho = {}; // req和res绑定yoho对象,用于传递全局数据, 如req.yoho.channel等
  135 + req.app.locals.wap = app.locals.wap; // zookeper对象赋值
95 136
96 next(); 137 next();
97 }); 138 });
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 const _ = require('lodash'); 8 const _ = require('lodash');
9 9
10 const helpers = global.yoho.helpers; 10 const helpers = global.yoho.helpers;
  11 +const config = global.yoho.config;
11 12
12 const service = require('../models/back-service'); 13 const service = require('../models/back-service');
13 const captchaService = require('../models/captcha-service'); 14 const captchaService = require('../models/captcha-service');
@@ -139,9 +140,16 @@ const setNewPasswordByEmailAPI = (req, res) => { @@ -139,9 +140,16 @@ const setNewPasswordByEmailAPI = (req, res) => {
139 * 找回密码页面-通过手机号 140 * 找回密码页面-通过手机号
140 */ 141 */
141 const indexMobilePage = (req, res, next) => { 142 const indexMobilePage = (req, res, next) => {
  143 + _.set(req.session, 'backupCaptch.verifyResult', false);
  144 +
  145 + if (req.session.captchaValidCount == null) { // eslint-disable-line
  146 + req.session.captchaValidCount = 5;
  147 + }
  148 +
142 service.getAreaDataAsync() 149 service.getAreaDataAsync()
143 .then(result => { 150 .then(result => {
144 res.render('back/mobile', Object.assign({ 151 res.render('back/mobile', Object.assign({
  152 + width750: true,
145 module: 'passport', 153 module: 'passport',
146 page: 'back-mobile', 154 page: 'back-mobile',
147 title: '找回密码-通过手机号' 155 title: '找回密码-通过手机号'
@@ -189,6 +197,7 @@ const sendCodeToMobileAPI = (req, res, next) => { @@ -189,6 +197,7 @@ const sendCodeToMobileAPI = (req, res, next) => {
189 let verifyCode = req.body.verifyCode || ''; 197 let verifyCode = req.body.verifyCode || '';
190 let phoneNum = req.body.phoneNum || ''; 198 let phoneNum = req.body.phoneNum || '';
191 let areaCode = req.body.areaCode || '86'; 199 let areaCode = req.body.areaCode || '86';
  200 + let testCode = req.body.yohobuy;
192 201
193 /* 如果设置了冻结时间,验证 */ 202 /* 如果设置了冻结时间,验证 */
194 if (_.has(req.session, 'backupCaptch.timeout')) { 203 if (_.has(req.session, 'backupCaptch.timeout')) {
@@ -203,32 +212,35 @@ const sendCodeToMobileAPI = (req, res, next) => { @@ -203,32 +212,35 @@ const sendCodeToMobileAPI = (req, res, next) => {
203 } 212 }
204 } 213 }
205 214
206 - /* 如果设置了验证次数,验证是否合法,验证次数减 1;没有,设置验证次数 */  
207 - if (_.has(req.session, 'backupCaptch.useTime')) {  
208 - if (parseInt(req.session.backupCaptch.useTime, 10) <= 0) { 215 + let errorCount = _.get(req.session, 'captchaValidCount', 4); // 初始1次 + 后续4次, 同一个验证码 共5次
209 216
210 - /* 如果超过验证次数,冻结 5 分钟,更新验证次数 */  
211 - req.session.backupCaptch.timeout = Date.now() + 5 * 60 * 1000;  
212 - req.session.backupCaptch.useTime = 5;  
213 - return res.json({  
214 - code: 401,  
215 - message: '请5分钟后尝试!'  
216 - });  
217 - }  
218 - req.session.backupCaptch.useTime = req.session.backupCaptch.useTime - 1; 217 + if (!errorCount) {
  218 + _.set(req.session, 'captchaValidCount', 4);
219 } else { 219 } else {
220 - req.session.backupCaptch.useTime = 5; 220 + --req.session.captchaValidCount;
221 } 221 }
222 222
223 if (verifyCode) { 223 if (verifyCode) {
224 - if (verifyCode.toString() === _.get(req, 'session.backupCaptch.code', '').toString()) { 224 + let captcha = _.get(req, 'session.captcha');
  225 +
  226 + if ((captcha && verifyCode.toString() === captcha) || (testCode === config.testCode)) {
225 req.session.backupCaptch.verifyResult = true; 227 req.session.backupCaptch.verifyResult = true;
226 } else { 228 } else {
227 - return res.json({ 229 + let jsonData = {
228 code: 400, 230 code: 400,
229 - message: '验证码输入错误'  
230 - }); 231 + message: '请将图片旋转到正确位置'
  232 + };
  233 +
  234 + if (req.session.captchaValidCount === 0) {
  235 + req.session.captcha = null; // 验证码 用过就扔
  236 + jsonData.changeCaptcha = true;
  237 + }
  238 +
  239 + return res.json(jsonData);
231 } 240 }
  241 +
  242 + _.set(req.session, 'captcha', null);
  243 +
232 } else if (!req.session.backupCaptch.verifyResult) { 244 } else if (!req.session.backupCaptch.verifyResult) {
233 245
234 return res.json({ 246 return res.json({
@@ -247,6 +259,8 @@ const sendCodeToMobileAPI = (req, res, next) => { @@ -247,6 +259,8 @@ const sendCodeToMobileAPI = (req, res, next) => {
247 return res.json(ERR); 259 return res.json(ERR);
248 } 260 }
249 261
  262 +
  263 +
250 service.sendCodeToMobileAsync(phoneNum, areaCode) 264 service.sendCodeToMobileAsync(phoneNum, areaCode)
251 .then(result => { 265 .then(result => {
252 if (_.isEmpty(result) || result.code !== 200) { 266 if (_.isEmpty(result) || result.code !== 200) {
1 'use strict'; 1 'use strict';
2 2
3 -let imgCheckAPI = require('../../serverAPI/imgcheck'); 3 +let imgCheckAPI = require('../models/imgcheck');
4 4
5 exports.get = (req, res, next) => { 5 exports.get = (req, res, next) => {
6 let data = { 6 let data = {
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * @date: 2016/05/09 5 * @date: 2016/05/09
6 */ 6 */
7 'use strict'; 7 'use strict';
8 - 8 +const _ = require('lodash');
9 const passport = require('passport'); 9 const passport = require('passport');
10 10
11 // const md5 = require('md5'); 11 // const md5 = require('md5');
@@ -78,8 +78,13 @@ const common = { @@ -78,8 +78,13 @@ const common = {
78 } 78 }
79 }; 79 };
80 80
  81 +
81 const local = { 82 const local = {
82 loginPage: (req, res) => { 83 loginPage: (req, res) => {
  84 + if (req.session.captchaValidCount == null) { // eslint-disable-line
  85 + req.session.captchaValidCount = 5;
  86 + }
  87 +
83 // 先清除cookie 88 // 先清除cookie
84 // res.clearCookie('LE' + md5('_LOGIN_EXPIRE'), { 89 // res.clearCookie('LE' + md5('_LOGIN_EXPIRE'), {
85 // domain: 'yohobuy.com' 90 // domain: 'yohobuy.com'
@@ -97,7 +102,9 @@ const local = { @@ -97,7 +102,9 @@ const local = {
97 }); 102 });
98 103
99 res.render('login', { 104 res.render('login', {
  105 + width750: true,
100 loginIndex: true, // 模板中使用JS的标识 106 loginIndex: true, // 模板中使用JS的标识
  107 + captchaShow: _.get(req.session, 'login.errorCount') <= 0,
101 108
102 // 返回的URL链接 109 // 返回的URL链接
103 backUrl: 'javascript:history.go(-1)', // eslint-disable-line 110 backUrl: 'javascript:history.go(-1)', // eslint-disable-line
@@ -135,9 +142,12 @@ const local = { @@ -135,9 +142,12 @@ const local = {
135 }); 142 });
136 143
137 res.render('international', { 144 res.render('international', {
  145 + width750: true,
  146 +
138 // 返回的URL链接 147 // 返回的URL链接
139 backUrl: 'javascript:history.go(-1)', // eslint-disable-line 148 backUrl: 'javascript:history.go(-1)', // eslint-disable-line
140 loginInternational: true, // 模板中使用JS的标识 149 loginInternational: true, // 模板中使用JS的标识
  150 + captchaShow: _.get(req.session, 'login.errorCount') <= 0,
141 isPassportPage: true, // 模板中模块标识 151 isPassportPage: true, // 模板中模块标识
142 headerText: '登录', 152 headerText: '登录',
143 areaCode: '+86', // 默认区号 153 areaCode: '+86', // 默认区号
@@ -148,13 +158,64 @@ const local = { @@ -148,13 +158,64 @@ const local = {
148 }); 158 });
149 }, 159 },
150 login: (req, res, next) => { 160 login: (req, res, next) => {
  161 + let count = _.get(req.session, 'login.errorCount');
  162 +
  163 + if (count == null) { // eslint-disable-line
  164 + _.set(req.session, 'login.errorCount', 3);
  165 + }
  166 +
  167 + if (count <= 0) {
  168 + let captchaInput = req.body.captcha;
  169 + let captchaCode = _.get(req.session, 'captcha');
  170 + let testCode = req.body.yohobuy;
  171 +
  172 + let errorCount = _.get(req.session, 'captchaValidCount'); // 初始1次 + 后续4次, 同一个验证码 共5次
  173 +
  174 + let jsonData = {
  175 + code: 400,
  176 + message: '请将图片旋转到正确方向',
  177 + captchaShow: true
  178 + };
  179 +
  180 + --req.session.captchaValidCount;
  181 +
  182 + if (!errorCount) {
  183 + _.set(req.session, 'captchaValidCount', 5);
  184 +
  185 + // delete req.session.captcha; // 验证码 用过就扔
  186 + req.session.captcha = null;
  187 + jsonData.changeCaptcha = true;
  188 + }
  189 +
  190 + if (
  191 + !(
  192 + (captchaInput && captchaCode && captchaInput === captchaCode) ||
  193 + (testCode === config.testCode)
  194 + )
  195 + ) {
  196 + res.json(jsonData);
  197 +
  198 + return;
  199 + }
  200 + }
  201 +
151 passport.authenticate('local', (err, user) => { 202 passport.authenticate('local', (err, user) => {
  203 + let loginSession = req.session.login;
  204 +
152 if (err) { 205 if (err) {
153 - res.json({ 206 + let obj = {
154 code: 400, 207 code: 400,
155 message: err, 208 message: err,
156 data: '' 209 data: ''
157 - }); 210 + };
  211 +
  212 + --loginSession.errorCount;
  213 +
  214 + if (loginSession.errorCount <= 0) {
  215 + obj.captchaShow = true;
  216 + }
  217 +
  218 + res.json(obj);
158 } else { 219 } else {
159 let refer = req.cookies.refer; 220 let refer = req.cookies.refer;
160 221
@@ -182,7 +243,12 @@ const local = { @@ -182,7 +243,12 @@ const local = {
182 })(req, res, next); 243 })(req, res, next);
183 }, 244 },
184 logout: (req, res) => { 245 logout: (req, res) => {
185 - req.session.reset(); 246 + if (req.session && req.session.destroy) {
  247 + req.session.destroy();
  248 + }
  249 + if (req.session2 && req.session2.reset) {
  250 + req.session2.reset();
  251 + }
186 252
187 res.clearCookie('_UID', { 253 res.clearCookie('_UID', {
188 domain: 'yohobuy.com' 254 domain: 'yohobuy.com'
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 'use strict'; 8 'use strict';
9 9
10 const _ = require('lodash'); 10 const _ = require('lodash');
  11 +const url = require('url');
11 const utils = require(global.utils); 12 const utils = require(global.utils);
12 const helpers = global.yoho.helpers; 13 const helpers = global.yoho.helpers;
13 const sign = global.yoho.sign; 14 const sign = global.yoho.sign;
@@ -26,6 +27,7 @@ const captchaService = require('../models/captcha-service'); @@ -26,6 +27,7 @@ const captchaService = require('../models/captcha-service');
26 } 27 }
27 */ 28 */
28 29
  30 +
29 /** 31 /**
30 * 步骤校验 32 * 步骤校验
31 * step: 预期步骤 33 * step: 预期步骤
@@ -58,6 +60,17 @@ let index = (req, res) => { @@ -58,6 +60,17 @@ let index = (req, res) => {
58 return res.redirect(req.get('refer') || '/'); 60 return res.redirect(req.get('refer') || '/');
59 } 61 }
60 62
  63 + // 判断是否 来自 个人中心
  64 + if (!_.get(req.session, 'phoneReg.isFromMy')) {
  65 + let referer = req.get('Referer') || '';
  66 + let urlObj = url.parse(referer, true, true);
  67 +
  68 + referer = _.get(urlObj, 'query.refer', '');
  69 +
  70 + urlObj = url.parse(referer, true, true);
  71 + urlObj.path === '/home' && _.set(req.session, 'phoneReg.isFromMy', '1');
  72 + }
  73 +
61 // 设置注册有效时间30分钟, 防机器刷 74 // 设置注册有效时间30分钟, 防机器刷
62 // req.session.REG_EXPIRE = Date.now() + 1800000; 75 // req.session.REG_EXPIRE = Date.now() + 1800000;
63 let refer = req.query.refer; 76 let refer = req.query.refer;
@@ -76,6 +89,7 @@ let index = (req, res) => { @@ -76,6 +89,7 @@ let index = (req, res) => {
76 } 89 }
77 90
78 res.render('reg/index', { 91 res.render('reg/index', {
  92 + width750: true,
79 module: 'passport', 93 module: 'passport',
80 page: 'reg', 94 page: 'reg',
81 title: '注册', 95 title: '注册',
@@ -99,7 +113,7 @@ let verifyMobile = (req, res, next) => { @@ -99,7 +113,7 @@ let verifyMobile = (req, res, next) => {
99 let mobile = +req.body.phoneNum; 113 let mobile = +req.body.phoneNum;
100 let area = +(req.body.areaCode || 86); 114 let area = +(req.body.areaCode || 86);
101 let captcha = (req.body.captcha || '').trim(); 115 let captcha = (req.body.captcha || '').trim();
102 - let diffCaptcha = _.get(req.session, 'phoneReg.captcha'); 116 + let diffCaptcha = _.get(req.session, 'captcha');
103 117
104 // error case: 没有验证码 118 // error case: 没有验证码
105 if (!diffCaptcha) { 119 if (!diffCaptcha) {
@@ -110,7 +124,7 @@ let verifyMobile = (req, res, next) => { @@ -110,7 +124,7 @@ let verifyMobile = (req, res, next) => {
110 }); 124 });
111 } 125 }
112 126
113 - delete req.session.phoneReg.captcha; // captcha 一次性 127 + delete req.session.captcha; // captcha 一次性
114 128
115 // error case: 验证码不匹配 129 // error case: 验证码不匹配
116 if (captcha !== diffCaptcha) { 130 if (captcha !== diffCaptcha) {
@@ -189,7 +203,6 @@ let codeAction = (req, res, next) => { @@ -189,7 +203,6 @@ let codeAction = (req, res, next) => {
189 res.render('reg/code', { 203 res.render('reg/code', {
190 page: 'code', 204 page: 'code',
191 title: '注册-验证码', 205 title: '注册-验证码',
192 - backUrl: '/?go=1', // eslint-disable-line  
193 headerText: '注册', // 头部信息 206 headerText: '注册', // 头部信息
194 isPassportPage: true, // 模板中模块标识 207 isPassportPage: true, // 模板中模块标识
195 areaCode: area, // 默认的区号 208 areaCode: area, // 默认的区号
@@ -365,6 +378,7 @@ let setPassword = (req, res, next) => { @@ -365,6 +378,7 @@ let setPassword = (req, res, next) => {
365 let password = req.body.password; 378 let password = req.body.password;
366 let token = req.body.token; 379 let token = req.body.token;
367 let smsCode = +req.body.smsCode; 380 let smsCode = +req.body.smsCode;
  381 + let isFromMy = _.get(req.session, 'phoneReg.isFromMy', '0');
368 382
369 // 判断参数是否合法 383 // 判断参数是否合法
370 if (!smsCode || !_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !password) { 384 if (!smsCode || !_.isString(token) || !_.isNumber(mobile) || !_.isNumber(area) || !password) {
@@ -387,29 +401,40 @@ let setPassword = (req, res, next) => { @@ -387,29 +401,40 @@ let setPassword = (req, res, next) => {
387 let shoppingKey = cookie.getShoppingKey(req); 401 let shoppingKey = cookie.getShoppingKey(req);
388 402
389 // 验证注册的标识码是否有效 403 // 验证注册的标识码是否有效
390 - RegService.regMobileAes(area, mobile, password, shoppingKey, smsCode).then((result) => { 404 + let resultCopy = null;
  405 +
  406 + RegService.regMobileAes(area, mobile, password, shoppingKey, smsCode, isFromMy).then((result) => {
391 if (!result.code || result.code !== 200) { 407 if (!result.code || result.code !== 200) {
392 return Promise.reject(result); 408 return Promise.reject(result);
393 } 409 }
394 if (!result.data || !result.data.uid) { 410 if (!result.data || !result.data.uid) {
395 return Promise.reject(result); 411 return Promise.reject(result);
396 } 412 }
  413 +
  414 + resultCopy = result;
  415 +
397 return AuthHelper.syncUserSession(result.data.uid, req, res); 416 return AuthHelper.syncUserSession(result.data.uid, req, res);
398 }).then(() => { 417 }).then(() => {
399 // 返回跳转到来源页面 418 // 返回跳转到来源页面
400 let refer = req.cookies.refer; 419 let refer = req.cookies.refer;
401 420
402 - if (refer) {  
403 - refer = decodeURI(req.cookies.refer); 421 + // isFromMy to 新人会场
  422 + if (resultCopy.data.newUserPage) {
  423 + refer = resultCopy.data.msgDelivery; // 来自个人中心,跳新人会场
404 } else { 424 } else {
405 - refer = '/home';  
406 - } 425 + if (refer) {
  426 + refer = decodeURI(req.cookies.refer);
  427 + } else {
  428 + refer = '/home';
  429 + }
  430 +
  431 + if (/sign|login/.test(refer)) {
  432 + refer = '/home';
  433 + }
407 434
408 - if (/sign|login/.test(refer)) {  
409 - refer = '/home'; 435 + refer = utils.refererLimit(refer);
410 } 436 }
411 437
412 - refer = utils.refererLimit(refer);  
413 438
414 delete req.session.phoneNum; 439 delete req.session.phoneNum;
415 440
1 /* eslint no-unused-vars: ["error", { "args": "none" }] */ 1 /* eslint no-unused-vars: ["error", { "args": "none" }] */
2 'use strict'; 2 'use strict';
3 const _ = require('lodash'); 3 const _ = require('lodash');
  4 +const moment = require('moment');
4 const helpers = global.yoho.helpers; 5 const helpers = global.yoho.helpers;
5 const cookie = global.yoho.cookie; 6 const cookie = global.yoho.cookie;
  7 +const config = global.yoho.config;
  8 +const EventEmitter = require('events');
6 const utils = require(global.utils); 9 const utils = require(global.utils);
7 const RegService = require('../models/reg-service'); 10 const RegService = require('../models/reg-service');
8 const PhoneService = require('../models/phone-service'); 11 const PhoneService = require('../models/phone-service');
9 const AuthHelper = require('../models/auth-helper'); 12 const AuthHelper = require('../models/auth-helper');
10 -const captchaService = require('../models/captcha-service');  
11 13
12 // constrant 14 // constrant
13 const CODE_REQUIRED = '请输入校验码'; 15 const CODE_REQUIRED = '请输入校验码';
14 const PASSWORD_REQUIRED = '请输入密码'; 16 const PASSWORD_REQUIRED = '请输入密码';
15 const PASSWORD_LENGTH_ERROR = '密码6-20位,请重新输入'; 17 const PASSWORD_LENGTH_ERROR = '密码6-20位,请重新输入';
16 const BAD_PASSWORD = '密码格式不正确'; 18 const BAD_PASSWORD = '密码格式不正确';
17 -const TOO_MANY = '请求太频繁';  
18 const LOGIN_SUCCSS = '登录成功'; 19 const LOGIN_SUCCSS = '登录成功';
19 const VERIFY_ERROR = '校验失败'; 20 const VERIFY_ERROR = '校验失败';
20 21
@@ -38,12 +39,13 @@ exports.beforeIn = (req, res, next) => { @@ -38,12 +39,13 @@ exports.beforeIn = (req, res, next) => {
38 const _step1 = (req, res, next) => { 39 const _step1 = (req, res, next) => {
39 _.set(req.session, 'smsLogin.step', 1); 40 _.set(req.session, 'smsLogin.step', 1);
40 41
41 - if (req.session.smsLogin.count == null) { // eslint-disable-line  
42 - req.session.smsLogin.count = 5; 42 + if (req.session.captchaValidCount == null) { // eslint-disable-line
  43 + req.session.captchaValidCount = 5;
43 } 44 }
44 45
45 let template = 'sms/login'; 46 let template = 'sms/login';
46 let viewData = { 47 let viewData = {
  48 + width750: true,
47 module: 'passport', 49 module: 'passport',
48 page: 'sms-login', 50 page: 'sms-login',
49 title: '手机短信登录', 51 title: '手机短信登录',
@@ -55,6 +57,8 @@ const _step1 = (req, res, next) => { @@ -55,6 +57,8 @@ const _step1 = (req, res, next) => {
55 }; 57 };
56 58
57 res.render(template, viewData); 59 res.render(template, viewData);
  60 +
  61 +
58 }; 62 };
59 63
60 // 短信登录 第二步: 输入 校验码 64 // 短信登录 第二步: 输入 校验码
@@ -118,44 +122,90 @@ exports.loginPage = (req, res, next) => { @@ -118,44 +122,90 @@ exports.loginPage = (req, res, next) => {
118 } 122 }
119 }; 123 };
120 124
121 -exports.tokenBefore = (req, res, next) => {  
122 - let area = req.query.area = (req.query.area || '').trim();  
123 - let mobile = req.query.mobile = (req.query.mobile || '').trim();  
124 - let step = _.get(req.session, 'smsLogin.step');  
125 - let count = _.get(req.session, 'smsLogin.count');  
126 - let interval = _.get(req.session, 'smsLogin.interval');  
127 - let captcha1 = _.get(req.session, 'smsLogin.captcha');  
128 - let captcha2 = (req.query.captcha || '').trim();  
129 125
  126 +/**
  127 + * step1 的表单提交验证
  128 + */
  129 +exports.indexCheck = (req, res, next) => {
  130 + _.set(req.session, 'smsLogin.step', 1);
130 131
131 - if (!req.xhr) {  
132 - return next(404); 132 + let area = req.body.area = (req.body.area || '').trim();
  133 + let mobile = req.body.mobile = (req.body.mobile || '').trim();
  134 + let captcode = (req.body.captcode || '').trim();
  135 + let captcodeValid = _.get(req.session, 'captcha');
  136 + let testCode = req.body.yohobuy;
  137 +
  138 + let em = new EventEmitter();
  139 +
  140 +
  141 + let errorCount = _.get(req.session, 'captchaValidCount', 4 - 1); // 初始1次 + 后续4次, 同一个验证码 共5次
  142 + let errorData = {
  143 + code: 400,
  144 + message: ''
  145 + };
  146 +
  147 + if (!errorCount) {
  148 + _.set(req.session, 'captchaValidCount', 3);
  149 + } else {
  150 + --req.session.captchaValidCount;
133 } 151 }
134 152
135 - if ([area, mobile].some(val => val === '')) {  
136 - return res.json({  
137 - code: 401,  
138 - message: '手机号 必填' 153 + // 校验 成功
  154 + em.on('resolve', () => {
  155 + // 1. 将信息放入 session
  156 + _.set(req.session, 'smsLogin.area', area);
  157 + _.set(req.session, 'smsLogin.mobile', mobile);
  158 + _.set(req.session, 'smsLogin.step', 2);
  159 + req.session.captcha = null;
  160 +
  161 + PhoneService.sendSMS(mobile, area, 1);
  162 +
  163 + res.json({
  164 + code: 200,
  165 + redirect: '/passport/sms_login?step=2'
139 }); 166 });
  167 + });
  168 +
  169 + // 校验 失败
  170 + em.on('reject', error => {
  171 + _.set(req.session, 'smsLogin.step', 1);
  172 +
  173 +
  174 + res.json(error);
  175 + });
  176 +
  177 + if (req.session.captchaValidCount === 0) {
  178 + req.session.captcha = null; // 验证码 用过就扔
  179 + errorData.changeCaptcha = true;
140 } 180 }
141 181
142 - delete req.session.smsLogin.captcha; // 图形验证码 一次性  
143 182
144 - // step1 要 校验图形验证码  
145 - if (step === 1) {  
146 - if (!captcha2) {  
147 - return res.json({  
148 - code: 400,  
149 - message: '请填写验证码'  
150 - });  
151 - } 183 + // 验证
  184 + if ([area, mobile].some(val => val === '')) {
  185 + return em.emit('reject', Object.assign(errorData, { message: '请填写手机号'}));
  186 + } else if (!captcode) {
  187 + return em.emit('reject', Object.assign(errorData, {message: '请填写验证码'}));
  188 + } else if (
  189 + !(
  190 + (captcodeValid && captcode === captcodeValid) || (testCode === config.testCode)
  191 + )
  192 + ) {
  193 + return em.emit('reject', Object.assign(errorData, {message: '请将图片旋转到正确位置'}));
  194 + }
152 195
153 - if (captcha1 !== captcha2) {  
154 - return res.json({  
155 - code: 400,  
156 - message: VERIFY_ERROR  
157 - });  
158 - } 196 + // congratulation~~
  197 + em.emit('resolve');
  198 +};
  199 +
  200 +exports.tokenBefore = (req, res, next) => {
  201 +
  202 + let step = _.get(req.session, 'smsLogin.step');
  203 + let count = _.get(req.session, 'smsLogin.count');
  204 + let interval = _.get(req.session, 'smsLogin.interval');
  205 +
  206 +
  207 + if (!req.xhr || step !== 2) {
  208 + return next(404);
159 } 209 }
160 210
161 let now = Date.now(); 211 let now = Date.now();
@@ -164,11 +214,14 @@ exports.tokenBefore = (req, res, next) => { @@ -164,11 +214,14 @@ exports.tokenBefore = (req, res, next) => {
164 // 1. 过了冻结期, count 重设为 5次 214 // 1. 过了冻结期, count 重设为 5次
165 // 2. 没过冻结期, end 215 // 2. 没过冻结期, end
166 // 没有用完, 判断是否请求太频繁 216 // 没有用完, 判断是否请求太频繁
  217 + let during = moment.duration(interval - now, 'ms').minutes();
  218 + let message = `请${during}分钟后再试`;
  219 +
167 if (!count) { 220 if (!count) {
168 if (interval > now) { 221 if (interval > now) {
169 return res.json({ 222 return res.json({
170 code: 400, 223 code: 400,
171 - message: TOO_MANY, 224 + message: message,
172 during: Math.ceil((interval - now) / 1000) 225 during: Math.ceil((interval - now) / 1000)
173 }); 226 });
174 } else { 227 } else {
@@ -177,17 +230,19 @@ exports.tokenBefore = (req, res, next) => { @@ -177,17 +230,19 @@ exports.tokenBefore = (req, res, next) => {
177 } else if (interval > now) { 230 } else if (interval > now) {
178 return res.json({ 231 return res.json({
179 code: 429, 232 code: 429,
180 - message: TOO_MANY 233 + message: message
181 }); 234 });
182 } 235 }
183 236
184 next(); 237 next();
185 }; 238 };
186 239
  240 +
  241 +
187 // AJAX 获取验证码 242 // AJAX 获取验证码
188 exports.token = (req, res, next) => { 243 exports.token = (req, res, next) => {
189 - let area = req.query.area;  
190 - let mobile = req.query.mobile; 244 + let area = _.get(req.session, 'smsLogin.area');
  245 + let mobile = _.get(req.session, 'smsLogin.mobile');
191 246
192 PhoneService.sendSMS(mobile, area, 1).then(result => { 247 PhoneService.sendSMS(mobile, area, 1).then(result => {
193 if (result.code === 200) { 248 if (result.code === 200) {
@@ -376,6 +431,7 @@ exports.password = (req, res, next) => { @@ -376,6 +431,7 @@ exports.password = (req, res, next) => {
376 /** 431 /**
377 * 生成 校验码 432 * 生成 校验码
378 */ 433 */
  434 +/*
379 exports.genCaptcha = (req, res) => { 435 exports.genCaptcha = (req, res) => {
380 let captcha = captchaService.generateCaptcha(90, 52, 4); 436 let captcha = captchaService.generateCaptcha(90, 52, 4);
381 437
@@ -386,3 +442,4 @@ exports.genCaptcha = (req, res) => { @@ -386,3 +442,4 @@ exports.genCaptcha = (req, res) => {
386 .status(200) 442 .status(200)
387 .send(captcha.image); 443 .send(captcha.image);
388 }; 444 };
  445 +*/
This diff could not be displayed because it is too large.
1 'use strict'; 1 'use strict';
  2 +const _ = require('lodash');
2 const aes = require('./aes-pwd'); 3 const aes = require('./aes-pwd');
3 const sign = global.yoho.sign; 4 const sign = global.yoho.sign;
4 const api = global.yoho.API; 5 const api = global.yoho.API;
@@ -87,10 +88,17 @@ class Auth { @@ -87,10 +88,17 @@ class Auth {
87 domain: 'yohobuy.com', 88 domain: 'yohobuy.com',
88 expires: new Date(Date.now() + 2592000000) // 有效期一年 89 expires: new Date(Date.now() + 2592000000) // 有效期一年
89 }); 90 });
  91 +
  92 + req.session.AVATAR = data.head_ico;
  93 + _.set(req.session, 'USER.AVATAR', data.head_ico);
  94 + _.set(req.session, 'USER.NAME', data.profile_name);
90 } 95 }
91 96
92 req.session.TOKEN = publicToken; 97 req.session.TOKEN = publicToken;
93 req.session.LOGIN_UID = uid; 98 req.session.LOGIN_UID = uid;
  99 +
  100 + _.set(req.session, 'USER.ENCRYPTION_UID', encryptionUid);
  101 +
94 res.cookie('_TOKEN', publicToken, { 102 res.cookie('_TOKEN', publicToken, {
95 httpOnly: true, 103 httpOnly: true,
96 domain: 'yohobuy.com', 104 domain: 'yohobuy.com',
1 'use strict'; 1 'use strict';
  2 +const _ = require('lodash');
  3 +let captchaData = require('../data/captcha.json');
2 4
3 -let api = global.yoho.API;  
4 - 5 +// let api = global.yoho.API;
5 /** 6 /**
6 * 获取图形旋转验证码 7 * 获取图形旋转验证码
7 * @return Promise 8 * @return Promise
@@ -24,9 +25,16 @@ let api = global.yoho.API; @@ -24,9 +25,16 @@ let api = global.yoho.API;
24 *} 25 *}
25 */ 26 */
26 exports.gen = () => { 27 exports.gen = () => {
27 - let params = {  
28 - method: 'web.register.getVerifiedGraphicCode'  
29 - }; 28 + // let params = {
  29 + // method: 'web.register.getVerifiedGraphicCode'
  30 + // };
  31 +
  32 + // return api.get('', params);
  33 +
  34 + let random = _.random(0, captchaData.length);
30 35
31 - return api.get('', params); 36 + return Promise.resolve({
  37 + code: 200,
  38 + data: captchaData[random]
  39 + });
32 }; 40 };
@@ -96,13 +96,16 @@ const RegService = { @@ -96,13 +96,16 @@ const RegService = {
96 96
97 return api.post('', params); 97 return api.post('', params);
98 }, 98 },
99 - regMobileAes(area, mobile, password, shoppingKey, smsCode) { 99 + regMobileAes(area, mobile, password, shoppingKey, smsCode, isFromMy) {
  100 + isFromMy = isFromMy || '0';
  101 +
100 let params = { 102 let params = {
101 method: 'app.passport.registerAES', 103 method: 'app.passport.registerAES',
102 area: area, 104 area: area,
103 profile: mobile, 105 profile: mobile,
104 password: aes.aesPwd(password), 106 password: aes.aesPwd(password),
105 - verifyCode: smsCode 107 + verifyCode: smsCode,
  108 + isFromMy
106 }; 109 };
107 110
108 if (shoppingKey) { 111 if (shoppingKey) {
@@ -41,6 +41,7 @@ router.post('/passport/login/auth', login.local.login); @@ -41,6 +41,7 @@ router.post('/passport/login/auth', login.local.login);
41 // SMS 短信 41 // SMS 短信
42 router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn); 42 router.use('/passport/sms_login', login.common.beforeLogin, smsLogin.beforeIn);
43 router.get('/passport/sms_login', smsLogin.loginPage); 43 router.get('/passport/sms_login', smsLogin.loginPage);
  44 +router.post('/passport/sms_login/step1_check', smsLogin.indexCheck);
44 router.get('/passport/sms_login/token.json', 45 router.get('/passport/sms_login/token.json',
45 smsLogin.tokenBefore, 46 smsLogin.tokenBefore,
46 smsLogin.token); // only ajax; 47 smsLogin.token); // only ajax;
@@ -48,7 +49,6 @@ router.get('/passport/sms_login/check.json', @@ -48,7 +49,6 @@ router.get('/passport/sms_login/check.json',
48 smsLogin.checkBefore, 49 smsLogin.checkBefore,
49 smsLogin.check); // only ajax 50 smsLogin.check); // only ajax
50 router.post('/passport/sms_login/password.json', smsLogin.password); 51 router.post('/passport/sms_login/password.json', smsLogin.password);
51 -router.get('/passport/sms_login/captcha.png', smsLogin.genCaptcha);  
52 52
53 // 微信登录 53 // 微信登录
54 router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login); 54 router.get('/passport/login/wechat', login.common.beforeLogin, login.wechat.login);
@@ -126,4 +126,9 @@ router.get('/passport/newpower', agreement.newpower);// 新力传媒 @@ -126,4 +126,9 @@ router.get('/passport/newpower', agreement.newpower);// 新力传媒
126 router.get('/passport/yohobuy', agreement.aboutYoho);// 关于有货 126 router.get('/passport/yohobuy', agreement.aboutYoho);// 关于有货
127 router.get('/passport/agreement', agreement.agreement);// 服务条款 127 router.get('/passport/agreement', agreement.agreement);// 服务条款
128 128
  129 +// 验证码
  130 +let captcha = require(`${cRoot}/captcha`);
  131 +
  132 +router.get('/passport/captcha/get', captcha.get);
  133 +
129 module.exports = router; 134 module.exports = router;
@@ -6,12 +6,11 @@ @@ -6,12 +6,11 @@
6 <span id="area-code" class="area-code">{{areaCode}}</span> 6 <span id="area-code" class="area-code">{{areaCode}}</span>
7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号"> 7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
8 </div> 8 </div>
9 - <div class="passport-captcha row">  
10 - <div class="passport-captcha-img"><img id="verify-code-img" src="{{verifySrc}}" alt="verify code"></div>  
11 - <div class="passport-captcha-input">  
12 - <input id="verify-code" type="text" placeholder="验证码">  
13 - </div> 9 + {{!--图片验证 start--}}
  10 + <div id="js-img-check">
  11 + <input type="hidden" name="captsrc" value="{{captsrc}}">
14 </div> 12 </div>
  13 + {{!--图片验证 end--}}
15 <span id="btn-next" class="btn btn-next disable row">下一步</span> 14 <span id="btn-next" class="btn btn-next disable row">下一步</span>
16 </div> 15 </div>
17 </div> 16 </div>
@@ -9,6 +9,8 @@ @@ -9,6 +9,8 @@
9 <div class="input-container row has-eye"> 9 <div class="input-container row has-eye">
10 <input id="pwd" class="pwd input" type="password" placeholder="密码"> 10 <input id="pwd" class="pwd input" type="password" placeholder="密码">
11 </div> 11 </div>
  12 + <div id="js-img-check" {{#captchaShow }}data-init{{/captchaShow}}></div>
  13 +
12 <span id="btn-login" class="btn btn-login disble row">登录</span> 14 <span id="btn-login" class="btn btn-login disble row">登录</span>
13 </div> 15 </div>
14 </div> 16 </div>
@@ -8,9 +8,10 @@ @@ -8,9 +8,10 @@
8 <div class="input-container row has-eye"> 8 <div class="input-container row has-eye">
9 <input id="pwd" class="pwd input" type="password" placeholder="密码"> 9 <input id="pwd" class="pwd input" type="password" placeholder="密码">
10 </div> 10 </div>
  11 + <div id="js-img-check" {{#captchaShow }}data-init{{/captchaShow}}></div>
11 <span id="btn-login" class="btn btn-login disable">登录</span> 12 <span id="btn-login" class="btn btn-login disable">登录</span>
12 <p class="op-container"> 13 <p class="op-container">
13 - {{!--<a class="sms-login" href={{smsLoginUrl}}>手机号码快捷登录</a>--}} 14 + <a class="sms-login" href={{smsLoginUrl}}>手机号码快捷登录</a>
14 <span id="forget-pwd" class="forget-pwd">忘记密码</span> 15 <span id="forget-pwd" class="forget-pwd">忘记密码</span>
15 </p> 16 </p>
16 <div class="third-party-login"> 17 <div class="third-party-login">
@@ -43,4 +44,4 @@ @@ -43,4 +44,4 @@
43 </li> 44 </li>
44 </ul> 45 </ul>
45 </div> 46 </div>
46 -</div>  
  47 +</div>
@@ -6,16 +6,13 @@ @@ -6,16 +6,13 @@
6 <span id="area-code" class="area-code">{{areaCode}}</span> 6 <span id="area-code" class="area-code">{{areaCode}}</span>
7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号"> 7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
8 </div> 8 </div>
9 - <!-- 验证码: start-->  
10 - <div class="passport-captcha row">  
11 - <div class="passport-captcha-img">  
12 - <img class="passport-captcha-png" src="{{captchaUrl}}">  
13 - </div>  
14 - <div class="passport-captcha-input">  
15 - <input id="js-captcha" type="text" placeholder="验证码">  
16 - </div> 9 +
  10 + {{!--图片验证 start--}}
  11 + <div id="js-img-check">
  12 + <input type="hidden" name="captsrc" value="{{captsrc}}">
17 </div> 13 </div>
18 - <!-- 验证码: end--> 14 + {{!--图片验证 end--}}
  15 +
19 <span id="btn-next" class="btn btn-next disable row">下一步</span> 16 <span id="btn-next" class="btn btn-next disable row">下一步</span>
20 <p class="register-tip">Yoho!Family账号可登录Yoho!Buy有货、Yoho!Now、mars及SHOW</p> 17 <p class="register-tip">Yoho!Family账号可登录Yoho!Buy有货、Yoho!Now、mars及SHOW</p>
21 </div> 18 </div>
@@ -7,12 +7,11 @@ @@ -7,12 +7,11 @@
7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号"> 7 <input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
8 <button class="clear-input" type="button"></button> 8 <button class="clear-input" type="button"></button>
9 </div> 9 </div>
10 - <div class="passport-captcha row">  
11 - <div class="passport-captcha-img"><img src="{{captchaUrl}}" alt=""></div>  
12 - <div class="passport-captcha-input">  
13 - <input id="js-captcha" type="text" placeholder="验证码">  
14 - </div> 10 + {{!--图片验证 start--}}
  11 + <div id="js-img-check">
  12 + <input type="hidden" name="captsrc" value="{{captsrc}}">
15 </div> 13 </div>
  14 + {{!--图片验证 end--}}
16 <button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button> 15 <button id="btn-next" class="btn btn-next disable row" disabled>获取短信验证码</button>
17 </div> 16 </div>
18 </div> 17 </div>
@@ -15,6 +15,7 @@ module.exports = { @@ -15,6 +15,7 @@ module.exports = {
15 port: 6001, 15 port: 6001,
16 siteUrl: '//m.yohobuy.com', 16 siteUrl: '//m.yohobuy.com',
17 assetUrl: '//127.0.0.1:5001', 17 assetUrl: '//127.0.0.1:5001',
  18 + testCode: 'yoho4946abcdef#$%&!@',
18 domains: { 19 domains: {
19 // api: 'http://api-test3.yohops.com:9999/', 20 // api: 'http://api-test3.yohops.com:9999/',
20 // service: 'http://service-test3.yohops.com:9999/', 21 // service: 'http://service-test3.yohops.com:9999/',
@@ -6,7 +6,7 @@ const headerModel = require('../models/header'); @@ -6,7 +6,7 @@ const headerModel = require('../models/header');
6 const logger = global.yoho.logger; 6 const logger = global.yoho.logger;
7 7
8 const forceNoCache = (res) => { 8 const forceNoCache = (res) => {
9 - if (res) { 9 + if (res && !res.finished) {
10 res.set({ 10 res.set({
11 'Cache-Control': 'no-cache', 11 'Cache-Control': 'no-cache',
12 Pragma: 'no-cache', 12 Pragma: 'no-cache',
@@ -47,6 +47,8 @@ exports.notFound = () => { @@ -47,6 +47,8 @@ exports.notFound = () => {
47 */ 47 */
48 exports.serverError = () => { 48 exports.serverError = () => {
49 return (err, req, res, next) => { 49 return (err, req, res, next) => {
  50 + console.log(err);
  51 +
50 forceNoCache(res); 52 forceNoCache(res);
51 53
52 logger.error(`error at path: ${req.url}`); 54 logger.error(`error at path: ${req.url}`);
1 { 1 {
2 "name": "m-yohobuy-node", 2 "name": "m-yohobuy-node",
3 - "version": "5.3.5", 3 + "version": "5.3.6",
4 "private": true, 4 "private": true,
5 "description": "A New Yohobuy Project With Express", 5 "description": "A New Yohobuy Project With Express",
6 "repository": { 6 "repository": {
@@ -24,9 +24,9 @@ @@ -24,9 +24,9 @@
24 "cheerio": "^0.22.0", 24 "cheerio": "^0.22.0",
25 "client-sessions": "^0.7.0", 25 "client-sessions": "^0.7.0",
26 "compression": "^1.6.2", 26 "compression": "^1.6.2",
  27 + "connect-memcached": "^0.2.0",
27 "connect-multiparty": "^2.0.0", 28 "connect-multiparty": "^2.0.0",
28 "cookie-parser": "^1.4.3", 29 "cookie-parser": "^1.4.3",
29 - "cookie-session": "^1.2.0",  
30 "express": "^4.14.0", 30 "express": "^4.14.0",
31 "feed": "^0.3.0", 31 "feed": "^0.3.0",
32 "lodash": "^4.17.2", 32 "lodash": "^4.17.2",
@@ -43,6 +43,7 @@ @@ -43,6 +43,7 @@
43 "request-promise": "^3.0.0", 43 "request-promise": "^3.0.0",
44 "serve-favicon": "^2.3.2", 44 "serve-favicon": "^2.3.2",
45 "uuid": "^2.0.3", 45 "uuid": "^2.0.3",
  46 + "yoho-express-session": "^2.0.0",
46 "yoho-node-lib": "0.2.2", 47 "yoho-node-lib": "0.2.2",
47 "yoho-zookeeper": "^1.0.4" 48 "yoho-zookeeper": "^1.0.4"
48 }, 49 },
@@ -12,4 +12,6 @@ @@ -12,4 +12,6 @@
12 <li class="img-check-pic" data-val="0" style="background-image:url('{{imgSrc}}');"></li> 12 <li class="img-check-pic" data-val="0" style="background-image:url('{{imgSrc}}');"></li>
13 </ul> 13 </ul>
14 </div> 14 </div>
  15 +
  16 + <input id="yohobuy" type="text" style="display:none;">
15 </div> 17 </div>
@@ -19,6 +19,18 @@ var tip = require('../../plugin/tip'); @@ -19,6 +19,18 @@ var tip = require('../../plugin/tip');
19 var trim = $.trim; 19 var trim = $.trim;
20 var showErrTip = tip.show; 20 var showErrTip = tip.show;
21 21
  22 +// 图片验证码
  23 +let ImgCheck = require('plugin/img-check');
  24 +
  25 +let imgCheck = new ImgCheck('#js-img-check', {
  26 + useREM: {
  27 + rootFontSize: 40,
  28 + picWidth: 150
  29 + }
  30 +});
  31 +
  32 +imgCheck.init();
  33 +
22 api.selectCssHack($('#country-select')); 34 api.selectCssHack($('#country-select'));
23 35
24 api.bindClearEvt(); 36 api.bindClearEvt();
@@ -45,12 +57,13 @@ $verifyCodeImg.on('touchstart', function() { @@ -45,12 +57,13 @@ $verifyCodeImg.on('touchstart', function() {
45 $btnNext.on('touchstart', function() { 57 $btnNext.on('touchstart', function() {
46 var pn = trim($phoneNum.val()), 58 var pn = trim($phoneNum.val()),
47 area = trim($countrySelect.val()), 59 area = trim($countrySelect.val()),
48 - verify = trim($verifyCode.val()); 60 + verify = trim(imgCheck.getResults());
49 61
50 if ($btnNext.hasClass('disable')) { 62 if ($btnNext.hasClass('disable')) {
51 return; 63 return;
52 } 64 }
53 65
  66 +
54 if (verify && area && pn && api.phoneRegx[area].test(pn)) { 67 if (verify && area && pn && api.phoneRegx[area].test(pn)) {
55 $.ajax({ 68 $.ajax({
56 url: '/passport/back/sendcode', 69 url: '/passport/back/sendcode',
@@ -58,23 +71,25 @@ $btnNext.on('touchstart', function() { @@ -58,23 +71,25 @@ $btnNext.on('touchstart', function() {
58 data: { 71 data: {
59 areaCode: area.replace('+', ''), 72 areaCode: area.replace('+', ''),
60 phoneNum: pn, 73 phoneNum: pn,
61 - verifyCode: verify 74 + verifyCode: verify,
  75 + yohobuy: $('#yohobuy').val()
62 }, 76 },
63 success: function(data) { 77 success: function(data) {
64 if (data.code === 200) { 78 if (data.code === 200) {
65 location.href = data.data; 79 location.href = data.data;
  80 + return;
66 } else if (data.code === 409) { 81 } else if (data.code === 409) {
67 showErrTip(data.message); 82 showErrTip(data.message);
68 location.href = data.refer; 83 location.href = data.refer;
69 } else { 84 } else {
70 showErrTip(data.message); 85 showErrTip(data.message);
71 } 86 }
  87 +
  88 + data.changeCaptcha && imgCheck.refresh();
72 } 89 }
73 }); 90 });
74 } else if (!area) { 91 } else if (!area) {
75 showErrTip('出错了,请重新刷新页面'); 92 showErrTip('出错了,请重新刷新页面');
76 - } else if (!verify) {  
77 - showErrTip('请输入验证码');  
78 } else { 93 } else {
79 showErrTip('手机号格式不正确,请重新输入'); 94 showErrTip('手机号格式不正确,请重新输入');
80 } 95 }
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 * @date: 2015/10/8 4 * @date: 2015/10/8
5 */ 5 */
6 var $ = require('yoho-jquery'); 6 var $ = require('yoho-jquery');
  7 +var ImgCheck = require('plugin/img-check');
7 8
8 var $phoneNum = $('#phone-num'), 9 var $phoneNum = $('#phone-num'),
9 $countrySelect = $('#country-select'), 10 $countrySelect = $('#country-select'),
@@ -11,6 +12,8 @@ var $phoneNum = $('#phone-num'), @@ -11,6 +12,8 @@ var $phoneNum = $('#phone-num'),
11 $pwd = $('#pwd'), 12 $pwd = $('#pwd'),
12 $loginBtn = $('#btn-login'), 13 $loginBtn = $('#btn-login'),
13 14
  15 + $captcha = $('#js-img-check'),
  16 +
14 pnPass = false, 17 pnPass = false,
15 pwdPass = false; 18 pwdPass = false;
16 19
@@ -20,13 +23,28 @@ var tip = require('../../plugin/tip'); @@ -20,13 +23,28 @@ var tip = require('../../plugin/tip');
20 var trim = $.trim; 23 var trim = $.trim;
21 var showErrTip = tip.show; 24 var showErrTip = tip.show;
22 25
  26 +var imgCheck = new ImgCheck($captcha, {
  27 + useREM: {
  28 + rootFontSize: 40,
  29 + picWidth: 150
  30 + }
  31 +});
  32 +
  33 +if ($captcha.data('init') != null) { //eslint-disable-line
  34 + imgCheck.init();
  35 +}
  36 +
  37 +
23 // 登录按钮状态切换 38 // 登录按钮状态切换
24 function switchLoginBtnStatus() { 39 function switchLoginBtnStatus() {
25 - if (pnPass && pwdPass) {  
26 - $loginBtn.removeClass('disable');  
27 - } else {  
28 - $loginBtn.addClass('disable');  
29 - } 40 + var bool = !(pnPass && pwdPass);
  41 +
  42 + $loginBtn.toggleClass('disable', bool);
  43 +}
  44 +
  45 +function resetForm() {
  46 + $pwd.val('').focus();
  47 + $loginBtn.text('登录').addClass('disable');
30 } 48 }
31 49
32 // Android-UC下显示select的direction:rtl无效的临时解决办法 50 // Android-UC下显示select的direction:rtl无效的临时解决办法
@@ -67,23 +85,39 @@ $countrySelect.change(function() { @@ -67,23 +85,39 @@ $countrySelect.change(function() {
67 $loginBtn.on('touchstart', function() { 85 $loginBtn.on('touchstart', function() {
68 var pn = trim($phoneNum.val()), 86 var pn = trim($phoneNum.val()),
69 areaCode = $countrySelect.val(), 87 areaCode = $countrySelect.val(),
70 - pwd = trim($pwd.val()); 88 + pwd = trim($pwd.val()),
  89 + captcha = null;
71 90
72 if ($loginBtn.hasClass('disable')) { 91 if ($loginBtn.hasClass('disable')) {
73 return; 92 return;
74 } 93 }
75 94
  95 + if (imgCheck.atWorking) {
  96 + captcha = imgCheck.getResults();
  97 +
  98 + if (captcha === '0000') {
  99 + return tip.show(' 请将图片旋转到正确方向');
  100 + }
  101 + }
  102 +
  103 +
76 $loginBtn.text('正在登录...').addClass('disable'); 104 $loginBtn.text('正在登录...').addClass('disable');
77 105
78 if ((api.phoneRegx[areaCode].test(pn) || areaCode !== '+86') && api.pwdValidate(pwd)) { 106 if ((api.phoneRegx[areaCode].test(pn) || areaCode !== '+86') && api.pwdValidate(pwd)) {
  107 + let data = {
  108 + areaCode: areaCode.replace('+', ''),
  109 + account: pn,
  110 + password: pwd
  111 + };
  112 +
  113 + if (imgCheck.atWorking) {
  114 + $.extend(data, {captcha});
  115 + }
  116 +
79 $.ajax({ 117 $.ajax({
80 type: 'POST', 118 type: 'POST',
81 url: '/passport/login/auth', 119 url: '/passport/login/auth',
82 - data: {  
83 - areaCode: areaCode.replace('+', ''),  
84 - account: pn,  
85 - password: pwd  
86 - }, 120 + data,
87 success: function(data) { 121 success: function(data) {
88 var res, 122 var res,
89 time; 123 time;
@@ -110,21 +144,27 @@ $loginBtn.on('touchstart', function() { @@ -110,21 +144,27 @@ $loginBtn.on('touchstart', function() {
110 location.href = res.href; 144 location.href = res.href;
111 }, 3000); 145 }, 3000);
112 146
  147 + $loginBtn.text('登录成功').off();
113 showErrTip('登录成功'); 148 showErrTip('登录成功');
114 } else { 149 } else {
  150 + if (data.captchaShow) {
  151 + imgCheck.atWorking ? imgCheck.refresh() : imgCheck.init();
  152 + }
  153 +
115 showErrTip(data.message); 154 showErrTip(data.message);
  155 + resetForm();
116 } 156 }
117 }, 157 },
118 error: function() { 158 error: function() {
119 showErrTip('网络断开连接啦~'); 159 showErrTip('网络断开连接啦~');
120 - },  
121 - complete: function() {  
122 - $loginBtn.text('登录').removeClass('disable'); 160 + $loginBtn.text('登录');
  161 +
  162 + imgCheck.atWorking && imgCheck.refresh();
123 } 163 }
124 }); 164 });
125 } else { 165 } else {
126 showErrTip('账号或密码有错误,请重新输入'); 166 showErrTip('账号或密码有错误,请重新输入');
127 - $loginBtn.text('登录').removeClass('disable'); 167 + $loginBtn.text('登录').addClass('disable');
128 } 168 }
129 }); 169 });
130 170
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 * @date: 2015/9/30 4 * @date: 2015/9/30
5 */ 5 */
6 var $ = require('yoho-jquery'); 6 var $ = require('yoho-jquery');
  7 +var ImgCheck = require('plugin/img-check');
7 8
8 var $account = $('#account'), 9 var $account = $('#account'),
9 $pwd = $('#pwd'), 10 $pwd = $('#pwd'),
@@ -12,6 +13,8 @@ var $account = $('#account'), @@ -12,6 +13,8 @@ var $account = $('#account'),
12 $mask = $('#retrive-pwd-mask'), 13 $mask = $('#retrive-pwd-mask'),
13 $ways = $('#retrive-pwd-ways'), 14 $ways = $('#retrive-pwd-ways'),
14 15
  16 + $captcha = $('#js-img-check'),
  17 +
15 accPass = false, 18 accPass = false,
16 pwdPass = false; 19 pwdPass = false;
17 20
@@ -21,13 +24,30 @@ var tip = require('../../plugin/tip'); @@ -21,13 +24,30 @@ var tip = require('../../plugin/tip');
21 var trim = $.trim; 24 var trim = $.trim;
22 var showErrTip = tip.show; 25 var showErrTip = tip.show;
23 26
  27 +
  28 +var imgCheck = new ImgCheck($captcha, {
  29 + useREM: {
  30 + rootFontSize: 40,
  31 + picWidth: 150
  32 + }
  33 +});
  34 +
  35 +if ($captcha.data('init') != null) { //eslint-disable-line
  36 + imgCheck.init();
  37 +}
  38 +
24 // 登录按钮状态切换 39 // 登录按钮状态切换
25 function switchLoginBtnStatus() { 40 function switchLoginBtnStatus() {
26 - if (accPass && pwdPass) {  
27 - $loginBtn.removeClass('disable');  
28 - } else {  
29 - $loginBtn.addClass('disable');  
30 - } 41 + var bool = true;
  42 +
  43 + bool = !(accPass && pwdPass);
  44 +
  45 + $loginBtn.toggleClass('disable', bool);
  46 +}
  47 +
  48 +function resetForm() {
  49 + $pwd.val('').focus();
  50 + $loginBtn.text('登录').addClass('disable');
31 } 51 }
32 52
33 // 显示找回密码面板 53 // 显示找回密码面板
@@ -70,23 +90,39 @@ $pwd.bind('input', function() { @@ -70,23 +90,39 @@ $pwd.bind('input', function() {
70 // Login 90 // Login
71 $loginBtn.on('touchstart', function() { 91 $loginBtn.on('touchstart', function() {
72 var acc = trim($account.val()), 92 var acc = trim($account.val()),
73 - pwd = trim($pwd.val()); 93 + pwd = trim($pwd.val()),
  94 + captcha = null;
74 95
75 if ($loginBtn.hasClass('disable')) { 96 if ($loginBtn.hasClass('disable')) {
76 return; 97 return;
77 } 98 }
78 99
  100 + // if (imgCheck.atWorking) {
  101 + captcha = imgCheck.getResults();
  102 +
  103 + // if (captcha === '0000') {
  104 + // return tip.show(' 请将图片旋转到正确方向');
  105 + // }
  106 + // }
  107 +
79 $loginBtn.text('正在登录...').addClass('disable'); 108 $loginBtn.text('正在登录...').addClass('disable');
80 109
81 // 验证账号(数字或者邮箱)和密码合理性 110 // 验证账号(数字或者邮箱)和密码合理性
82 if ((/^[0-9]+$/.test(acc) || api.emailRegx.test(acc)) && api.pwdValidate(pwd)) { 111 if ((/^[0-9]+$/.test(acc) || api.emailRegx.test(acc)) && api.pwdValidate(pwd)) {
  112 + let data = {
  113 + account: acc,
  114 + password: pwd,
  115 + yohobuy: $('#yohobuy').val()
  116 + };
  117 +
  118 + if (imgCheck.atWorking) {
  119 + $.extend(data, {captcha});
  120 + }
  121 +
83 $.ajax({ 122 $.ajax({
84 type: 'POST', 123 type: 'POST',
85 url: '/passport/login/auth', 124 url: '/passport/login/auth',
86 - data: {  
87 - account: acc,  
88 - password: pwd  
89 - }, 125 + data,
90 success: function(data) { 126 success: function(data) {
91 var res; 127 var res;
92 128
@@ -95,12 +131,22 @@ $loginBtn.on('touchstart', function() { @@ -95,12 +131,22 @@ $loginBtn.on('touchstart', function() {
95 131
96 showErrTip('登录成功'); 132 showErrTip('登录成功');
97 location.href = res.href; 133 location.href = res.href;
  134 + $loginBtn.text('登录成功').off();
98 } else { 135 } else {
  136 + if (data.captchaShow) {
  137 + imgCheck.atWorking ? (data.changeCaptcha && imgCheck.refresh()) : imgCheck.init();
  138 + }
  139 +
99 showErrTip(data.message); 140 showErrTip(data.message);
  141 + resetForm();
100 } 142 }
  143 +
  144 + return data;
101 }, 145 },
102 error: function() { 146 error: function() {
103 showErrTip('网络断开连接啦~'); 147 showErrTip('网络断开连接啦~');
  148 +
  149 + imgCheck.atWorking && imgCheck.refresh();
104 }, 150 },
105 complete: function() { 151 complete: function() {
106 $loginBtn.text('登录').removeClass('disable'); 152 $loginBtn.text('登录').removeClass('disable');
@@ -35,7 +35,7 @@ $pwd.bind('input', function() { @@ -35,7 +35,7 @@ $pwd.bind('input', function() {
35 }); 35 });
36 36
37 $btnSure.toggleClass('disable', !bool); 37 $btnSure.toggleClass('disable', !bool);
38 -}) 38 +});
39 39
40 40
41 qs = window.queryString; 41 qs = window.queryString;
@@ -137,4 +137,4 @@ $('.agreement-detail').on('click', function() { @@ -137,4 +137,4 @@ $('.agreement-detail').on('click', function() {
137 // 如果有值, 立刻校验 137 // 如果有值, 立刻校验
138 if ($pwd.val()) { 138 if ($pwd.val()) {
139 $pwd.triggerHandler('input'); 139 $pwd.triggerHandler('input');
140 -}  
  140 +}
@@ -24,17 +24,29 @@ api.selectCssHack($('#country-select')); @@ -24,17 +24,29 @@ api.selectCssHack($('#country-select'));
24 24
25 api.bindClearEvt(); 25 api.bindClearEvt();
26 26
  27 +
  28 +// 图片验证码
  29 +let ImgCheck = require('plugin/img-check');
  30 +
  31 +let imgCheck = new ImgCheck('#js-img-check', {
  32 + useREM: {
  33 + rootFontSize: 40,
  34 + picWidth: 150
  35 + }
  36 +});
  37 +
  38 +imgCheck.init();
  39 +
27 /** 40 /**
28 * 必填校验 41 * 必填校验
29 */ 42 */
30 function checkEnableNext() { 43 function checkEnableNext() {
31 var phone = trim($phoneNum.val()); 44 var phone = trim($phoneNum.val());
32 var area = trim($countrySelect.val()); 45 var area = trim($countrySelect.val());
33 - var captcha = trim($captcha.val());  
34 46
35 var ret = true; 47 var ret = true;
36 48
37 - $.each([phone, area, captcha], function(i, val) { 49 + $.each([phone, area], function(i, val) {
38 if (!val) { 50 if (!val) {
39 ret = false; 51 ret = false;
40 return ret; 52 return ret;
@@ -44,24 +56,13 @@ function checkEnableNext() { @@ -44,24 +56,13 @@ function checkEnableNext() {
44 return ret; 56 return ret;
45 } 57 }
46 58
47 -  
48 -/**  
49 - * 刷新 校验码  
50 - */  
51 -function refreshCaptcha() {  
52 - $captcha.val('').focus();  
53 - $captchaPNG.attr('src', ['//m.yohobuy.com/passport/reg/captcha.png', '?t=', Date.now()].join(''));  
54 -}  
55 -  
56 -  
57 /* 59 /*
58 Event bind 60 Event bind
59 */ 61 */
60 $('.reg-page') 62 $('.reg-page')
61 - .on('input', '.phone-num, #js-captcha', function() { 63 + .on('input', '.phone-num', function() {
62 $btnNext.toggleClass('disable', !checkEnableNext()); 64 $btnNext.toggleClass('disable', !checkEnableNext());
63 - })  
64 - .on('click', '.passport-captcha-png', refreshCaptcha); 65 + });
65 66
66 $countrySelect.change(function() { 67 $countrySelect.change(function() {
67 $areaCode.text($countrySelect.val()); 68 $areaCode.text($countrySelect.val());
@@ -70,10 +71,10 @@ $countrySelect.change(function() { @@ -70,10 +71,10 @@ $countrySelect.change(function() {
70 $btnNext.on('touchstart', function() { 71 $btnNext.on('touchstart', function() {
71 var pn = trim($phoneNum.val()), 72 var pn = trim($phoneNum.val()),
72 areaCode = $countrySelect.val(), 73 areaCode = $countrySelect.val(),
73 - captcha = $captcha.val().trim(); 74 + captcha = imgCheck.getResults();
74 75
75 - if (!captcha) {  
76 - tip.show('请输入验证码'); 76 + if (captcha === '0000') {
  77 + tip.show('请将图片旋转到正确位置');
77 return false; 78 return false;
78 } 79 }
79 80
@@ -102,7 +103,7 @@ $btnNext.on('touchstart', function() { @@ -102,7 +103,7 @@ $btnNext.on('touchstart', function() {
102 if (data.code === 200) { 103 if (data.code === 200) {
103 location.href = data.data; 104 location.href = data.data;
104 } else { 105 } else {
105 - refreshCaptcha(); 106 + imgCheck.refresh();
106 107
107 showErrTip(data.message); 108 showErrTip(data.message);
108 requested = false; 109 requested = false;
@@ -110,7 +111,7 @@ $btnNext.on('touchstart', function() { @@ -110,7 +111,7 @@ $btnNext.on('touchstart', function() {
110 }, 111 },
111 error: function() { 112 error: function() {
112 showErrTip('出错了,请重试'); 113 showErrTip('出错了,请重试');
113 - refreshCaptcha(); 114 + imgCheck.refresh();
114 requested = false; 115 requested = false;
115 } 116 }
116 }); 117 });
@@ -17,10 +17,26 @@ tip = require('plugin/tip'); @@ -17,10 +17,26 @@ tip = require('plugin/tip');
17 api = require('./api'); 17 api = require('./api');
18 checkPoint = require('./smslogin/check-point'); 18 checkPoint = require('./smslogin/check-point');
19 19
  20 +
  21 +// 图片验证码
  22 +let ImgCheck = require('plugin/img-check');
  23 +
  24 +let imgCheck = new ImgCheck('#js-img-check', {
  25 + useREM: {
  26 + rootFontSize: 40,
  27 + picWidth: 150
  28 + }
  29 +});
  30 +
  31 +imgCheck.init();
  32 +
  33 +
  34 +
20 page = { 35 page = {
21 init: function() { 36 init: function() {
22 this.domInit(); 37 this.domInit();
23 this.bindEvent(); 38 this.bindEvent();
  39 + this.toggleNextBtn();
24 }, 40 },
25 domInit: function() { 41 domInit: function() {
26 $countrySelect = $('#country-select'); 42 $countrySelect = $('#country-select');
@@ -28,8 +44,6 @@ page = { @@ -28,8 +44,6 @@ page = {
28 $nextBtn = $('#btn-next'); 44 $nextBtn = $('#btn-next');
29 $phoneNum = $('#phone-num'); 45 $phoneNum = $('#phone-num');
30 $resetBtn = $('.clear-input'); 46 $resetBtn = $('.clear-input');
31 - $captcha = $('.passport-captcha input');  
32 - $captchaPNG = $('.passport-captcha-img img');  
33 }, 47 },
34 bindEvent: function() { 48 bindEvent: function() {
35 var self = this; 49 var self = this;
@@ -41,12 +55,6 @@ page = { @@ -41,12 +55,6 @@ page = {
41 self.toggleNextBtn(); 55 self.toggleNextBtn();
42 }); 56 });
43 57
44 - $captcha.on('input', function() {  
45 - self.toggleNextBtn();  
46 - });  
47 -  
48 - $captchaPNG.on('click', $.proxy(this.refreshCapatch, this));  
49 -  
50 $nextBtn.on('click', function() { 58 $nextBtn.on('click', function() {
51 self.goNext(); 59 self.goNext();
52 }); 60 });
@@ -62,7 +70,7 @@ page = { @@ -62,7 +70,7 @@ page = {
62 70
63 // 切换$nextBtn disable状态 71 // 切换$nextBtn disable状态
64 toggleNextBtn: function() { 72 toggleNextBtn: function() {
65 - var bool = Boolean($.trim($phoneNum.val())) && Boolean($.trim($captcha.val())); 73 + var bool = Boolean($.trim($phoneNum.val()));
66 74
67 $nextBtn 75 $nextBtn
68 .toggleClass('disable', !bool) 76 .toggleClass('disable', !bool)
@@ -71,17 +79,11 @@ page = { @@ -71,17 +79,11 @@ page = {
71 $resetBtn.toggle(bool); 79 $resetBtn.toggle(bool);
72 }, 80 },
73 81
74 - refreshCapatch: function() {  
75 - $captchaPNG.attr('src', '/passport/sms_login/captcha.png?t=' + Date.now());  
76 - $captcha.val('');  
77 - },  
78 -  
79 // 提交按钮 82 // 提交按钮
80 goNext: function() { 83 goNext: function() {
81 - var self = this;  
82 var areaCode = $countrySelect.val(); 84 var areaCode = $countrySelect.val();
83 var phone = $.trim($phoneNum.val()); 85 var phone = $.trim($phoneNum.val());
84 - var captcha = $.trim($captcha.val()); 86 + var captcha = $.trim(imgCheck.getResults());
85 87
86 if ($nextBtn.prop('disabled')) { 88 if ($nextBtn.prop('disabled')) {
87 return; 89 return;
@@ -92,11 +94,17 @@ page = { @@ -92,11 +94,17 @@ page = {
92 return; 94 return;
93 } 95 }
94 96
  97 + // if (captcha === '0000') {
  98 + // tip.show('请将图片旋转到正确位置');
  99 + // return;
  100 + // }
  101 +
95 $nextBtn.prop('disabled', true); 102 $nextBtn.prop('disabled', true);
96 - $.get('/passport/sms_login/token.json', { 103 + $.post('/passport/sms_login/step1_check', {
97 area: areaCode.replace('+', ''), 104 area: areaCode.replace('+', ''),
98 mobile: phone, 105 mobile: phone,
99 - captcha: captcha 106 + captcode: captcha,
  107 + yohobuy: $('#yohobuy').val()
100 }) 108 })
101 .done(function(data) { 109 .done(function(data) {
102 if (data.code === 200) { 110 if (data.code === 200) {
@@ -104,11 +112,12 @@ page = { @@ -104,11 +112,12 @@ page = {
104 $nextBtn.off(); 112 $nextBtn.off();
105 location.href = data.redirect; 113 location.href = data.redirect;
106 } else { 114 } else {
107 - self.refreshCapatch(); 115 + data.changeCaptcha && imgCheck.refresh();
108 tip.show(data.message); 116 tip.show(data.message);
109 } 117 }
110 }) 118 })
111 .fail(function() { 119 .fail(function() {
  120 + imgCheck.refresh();
112 tip.show('出错了, 请重试'); 121 tip.show('出错了, 请重试');
113 }) 122 })
114 .always(function() { 123 .always(function() {
@@ -12,10 +12,12 @@ var sendInfo = function(eventName) { @@ -12,10 +12,12 @@ var sendInfo = function(eventName) {
12 channel = channelMap[channel] || 1; 12 channel = channelMap[channel] || 1;
13 param = JSON.stringify({C_ID: channel}); 13 param = JSON.stringify({C_ID: channel});
14 14
15 - yas && yas.sendCustomInfo({  
16 - op: eventName,  
17 - param: param  
18 - }, true); 15 + if (yas && yas.sendCustomInfo) {
  16 + yas.sendCustomInfo({
  17 + op: eventName,
  18 + param: param
  19 + }, true);
  20 + }
19 }; 21 };
20 22
21 module.exports = sendInfo; 23 module.exports = sendInfo;