Authored by yyq

Merge branch 'feature/captcha' into release/0912

... ... @@ -135,16 +135,15 @@ const exchangeDetail = (req, res, next) => {
* 我的订单-获取换货方式
*/
const getDelivery = (req, res, next) => {
let orderCode = req.body.orderCode;
let areaCode = req.body.areaCode;
let skns = req.body.skns;
// 获取必要参数
let uid = req.user.uid;
let gender = req.yoho.gender;
let channel = req.yoho.channel;
// 调用接口获得该用户支持的换货方式(白金会员可享受上门换货,偏远地区不支持上门换货)
req.ctx(returnsModel).getDelivery(areaCode, uid, gender, channel).then(result => {
req.ctx(returnsModel).getDelivery(orderCode, areaCode, uid, skns).then(result => {
res.send(result);
}).catch(next);
};
... ...
... ... @@ -203,14 +203,15 @@ module.exports = class extends global.yoho.BaseModel {
* @param $yhChannel
* @return mixed
*/
getDeliveryAsync(areaCode, uid, gender, channel) {
getDeliveryAsync(orderCode, areaCode, uid, skns) {
skns = skns || [];
let options = {
method: 'app.change.getDelivery',
method: 'app.change.refreshDelivery',
uid: uid,
order_code: orderCode,
area_code: areaCode,
gender: gender,
yh_channel: channel
skns: JSON.stringify(skns)
};
return this.post({data: options});
... ...
... ... @@ -677,8 +677,16 @@ module.exports = class extends global.yoho.BaseModel {
}
// 获取换货方式
getDelivery(areaCode, uid, gender, channel) {
return new ReturnAPI(this.ctx).getDeliveryAsync(areaCode, uid, gender, channel);
getDelivery(orderCode, areaCode, uid, skns) {
return new ReturnAPI(this.ctx).getDeliveryAsync(orderCode, areaCode, uid, _.split(skns, ',')).then(result => {
if (+result.code === 200) {
_.remove(result.data, n => {
return n.is_support !== 'Y';
});
}
return result;
});
}
// 取消退货申请
... ...
... ... @@ -73,7 +73,7 @@ const bind = {
let openId = req.body.openId;
let area = req.body.area;
if (req.session.verifyCode !== 'relateStep1') {
if (req.session.type !== 'relateStep1') {
return next();
}
... ... @@ -140,10 +140,10 @@ const bind = {
return {code: 201, message: result.message, data: {user: user}};
});
} else if (result.code === 200 && result.data.is_register === 3) {
let nextUrl = helpers.urlFormat('/passport/thirdlogin/relate');
// 关联流程
return {code: 203, message: result.message, data: {next: nextUrl}};
return userService.getUserInfo(area, mobile).then(user => {
return {code: 203, message: result.message, data: {user: user}};
});
} else if (result.code === 506 || result.code === 505) {
return userService.getUserInfo(area, mobile).then(user => {
// 绑定流程:code=506 手机号码注册过,而且该手机号码也已经绑定过该类型第三方
... ...
... ... @@ -139,10 +139,11 @@ const cert = {
if (_.get(result, 'data.isCanBind') === 'Y') {
nextUrl = helpers.urlFormat('/passport/cert/cert');
return {code: 200, message: result.message, data: {next: nextUrl}};
} else {
nextUrl = helpers.urlFormat('/passport/cert/relate');
// 不可以关联
return {code: 403, message: '绑定失败,该手机号已注册,请更换或使用该手机号直接登录'};
}
return {code: 200, message: result.message, data: {next: nextUrl}};
} else {
return {code: result.code, message: result.message, data: result.data ? result.data : ''};
}
... ...
... ... @@ -2,99 +2,64 @@
* Created by TaoHuang on 2016/6/18.
*/
'use strict';
/**
* 验证码的形式: xxxx|page
*/
const captchaService = require('../models/captcha-img-service');
const CAPTCHA = global.yoho.config.UNIVERSAL_CAPTCHA;
const CaptchaServiceModel = require('../models/captcha-img-service');
const request = require('request');
const logger = global.yoho.logger;
const CAPTCHATIME = 1 * 60000; // 默认1分钟
// 对比函数
const _mustEqual = (req) => {
let result = req.session.captcha && (req.body.verifyCode === req.session.captcha ||
req.body.verifyCode === CAPTCHA);
const _mustEqualAsync = (req) => {
let id = req.session.id;
let verifyCode = req.body.verifyCode;
logger.info(`img captcha auth [${result ? 'success' : 'fail'}]`,
`CLIENT [${req.body.verifyCode}] SERVER [${req.session.captcha}]`);
if (!id || !verifyCode) {
return Promise.resolve({
code: 405,
message: '请将所有图片点击翻转至正向朝上'
});
}
return result;
return req.ctx(CaptchaServiceModel).check(id, verifyCode);
};
// 中间件
const requiredAPI = (req, res, next) => {
let count = req.session.captchaCount;
let time = new Date().getTime();
let firstTime = req.session.captchaTime;
if (count >= 4 || firstTime && (time - firstTime > CAPTCHATIME)) {
req.session.captcha = CAPTCHA;
return res.json({
code: 405,
message: '该验证码已失效,请刷新验证码',
data: {
needCaptcha: true
}
});
}
req.session.captchaCount = count + 1;
if (_mustEqual(req)) {
return next();
} else {
return res.json({
code: 405,
message: '请将图形验证码翻转至正确方向',
data: {
needCaptcha: true
}
});
}
_mustEqualAsync(req).then((result) => {
if (result.code === 200) {
return next();
} else {
return res.json({
code: 405,
message: result.message,
data: {
needCaptcha: true
}
});
}
}).catch(next);
};
// 七牛验证码
const generate = (req, res, next) => {
captchaService.generateCaptcha().then((result) => {
req.session.captcha = result.data.text;
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.images).pipe(res);
request(result.data.url).pipe(res);
}
}).catch(next);
};
// 端到端检查
const checkAPI = (req, res) => {
let count = req.session.captchaCount;
let time = new Date().getTime();
let firstTime = req.session.captchaTime;
if (count >= 4 || firstTime && (time - firstTime > CAPTCHATIME)) {
req.session.captcha = CAPTCHA;
return res.json({
code: 405,
message: '该验证码已失效,请刷新验证码'
});
}
req.session.captchaCount = count + 1;
if (_mustEqual(req)) {
return res.json({
code: 200,
message: '验证成功'
});
} else {
return res.json({
code: 405,
message: '请将图形验证码翻转至正确方向'
});
}
const checkAPI = (req, res, next) => {
_mustEqualAsync(req).then(result => {
res.json(result);
}).catch(next);
};
module.exports = {
... ...
... ... @@ -264,6 +264,8 @@ let mobileRegister = (req, res, next) => {
let mobile = req.body.mobile;
let code = req.body.code; // 短信验证码
let password = req.body.password;
let inviteCode = req.body.inviteCode;
let clientIp = req.yoho.clientIp;
let result = yield regService.validMobileCode(area, mobile, code); // 验证注册的标识码是否有效
if (!result.code || result.code !== 200) {
... ... @@ -272,7 +274,9 @@ let mobileRegister = (req, res, next) => {
}
/* 手机注册: 调用注册接口*/
let regResult = yield regService.regMobileAes(area, mobile, password, code, cookie.getShoppingKey(req), req.body); // eslint-disable-line
let regResult = yield regService.regMobileAes(
area, mobile, password, code, cookie.getShoppingKey(req), inviteCode, clientIp
);
if (!regResult.code || regResult.code !== 200) {
data.message = '注册失败';
... ...
... ... @@ -4,20 +4,39 @@
'use strict';
const _ = require('lodash');
const CAPTCHA = require('../data/captcha.json');
const length = CAPTCHA.length - 1 || -1;
const apiUrl = global.yoho.config.domains.service;
exports.gen = () => {
if (length !== -1) {
return Promise.resolve({
code: 200,
data: CAPTCHA[_.random(0, length)]
});
} else {
return Promise.reject({
code: 400,
message: '验证码错误'
const PAGE = 'pc';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
}
gen(id) {
if (id) {
return Promise.resolve({
code: 200,
data: {
url: `${apiUrl}passport/img-check.jpg?udid=${id}&fromPage=${PAGE}`
}
});
} else {
return Promise.reject({
code: 400,
message: '生成二维码失败,请重新刷新!'
});
}
}
check(id, captcha) {
return this.get({
data: {
method: 'app.verified.graphic',
udid: id,
fromPage: PAGE,
degrees: captcha
}
});
}
};
... ...
/**
* Created by TaoHuang on 2016/7/1.
*/
const CaptchaApi = require('./captcha-api');
const logger = global.yoho.logger;
'use strict';
module.exports = class extends global.yoho.BaseModel {
constructor(ctx) {
super(ctx);
const api = require('./captcha-api');
const uuid = require('uuid');
this.api = new CaptchaApi(ctx);
}
generateCaptcha(id) {
return this.api.gen(id)
.then(result => {
logger.info('get captcha from ', result.data.url);
return result;
});
}
check(id, captcha) {
return this.api.check(id, captcha).then((result) => {
if (result.code === 200) {
return {
code: 200,
message: '验证成功'
};
} else if (result.code === 503 || result.code === 504 || result.code === 501) {
return {
code: 403,
message: result.message
};
} else {
return {
code: 405,
message: result.message,
data: {
needCaptcha: true
}
};
}
});
}
exports.generateCaptcha = () => {
return api.gen().then((result) => {
if (result.code === 200) {
let codeStr = result.data.degrees.map((rotate) => {
return (4 - rotate / 90 % 4) % 4;
}).join('');
return {
code: 200,
data: {
text: codeStr,
images: `${result.data.verifiedGraphicCode}` +
`?imageView2/2/w/240/q/70/watermark/2/text/${uuid.v4()}/fontsize/120/dissolve/10`
}
};
} else {
return {
code: 400,
message: '生成二维码失败,请重新刷新!',
data: {
text: 'yoho9636'
}
};
}
});
};
... ...
... ... @@ -10,7 +10,7 @@ const logger = global.yoho.logger;
const signinByPasswordWithAes = (area, profile, password, shoppingKey, clientIp) => {
let param = {
method: 'app.passport.signinAES',
method: 'sesame.flowering.higher',
area: area,
profile: profile,
password: aes.aesPwd(password)
... ...
... ... @@ -31,7 +31,7 @@ let validMobileCode = (area, mobile, code) => {
return api.post('', params);
};
let regMobileAes = (area, mobile, password, code, shoppingKey, extParam)=> {
let regMobileAes = (area, mobile, password, code, shoppingKey, inviteCode, clientIp)=> {
let params = {
method: 'app.passport.registerAES',
area: area,
... ... @@ -44,13 +44,16 @@ let regMobileAes = (area, mobile, password, code, shoppingKey, extParam)=> {
params.shopping_key = shoppingKey;
}
if (extParam) {
if (extParam.inviteCode) {
params.inviteCode = extParam.inviteCode;
}
if (inviteCode) {
params.inviteCode = inviteCode;
}
return api.post('', params);
return api.post('', params, {
headers: {
'user-agent': 'yoho/nodejs',
'X-YOHO-IP': clientIp
}
});
};
module.exports = {
... ...
... ... @@ -133,4 +133,27 @@
<div class="backdrop" style="display:none"></div>
</div>
<div id="norelate" style="display:none">
<div class="mask">
<div class="bindconfrimwrapper">
<div class="topwrapper">
<img src="" alt="" class="userphoto" id="userphoto-relate">
<span class="username">
用户名: <i id="username-relate"></i>
</span>
</div>
<h2 class="usertaginfo">
手机号
<span id="registphone-relate"></span>
已经被以上账户注册。
</h2>
<h1 class="usertagremind">您可以更换一个新的手机号码绑定该账号,也可以使用该手机号码直接登录</h1>
<div class="gobindbottomwrapper">
<a href="javascript:;" class="logindirectly" id="yohobindbtn3">绑定其他手机号</a>
<a href="http://www.yohobuy.com/signin.html" class="logindirectly" id="logindirectly3">使用手机号直接登录</a>
</div>
</div>
</div>
</div>
{{> gee-captcha}}
... ...
... ... @@ -12,30 +12,10 @@
已经被以上账户注册,点击
<a href="{{bindLogin}}" target="_blank">登录该账号</a>
</h3>
<p>您可以使用此号码进行账户关联或更换一个新的手机号码</p>
<p>您可以更换一个新的手机号码绑定该账号,</p><p>也可以使用该手机号码直接登录</p>
</div>
<div class="option-btn">
<a id="next-step-btn">关联此手机号</a>
<a href="{{changeHref}}">更换新手机号</a>
</div>
<p class="remind-tips">注:关联的手机号码不能用来登录此账户</p>
</div>
<div id="code-validate" class="code-validate hide">
<div class="action-link">短信验证码已发送至<span>{{phoneNum}}</span></div>
<div class="validate-wrapper action-link">
<div class="code-name">短信验证码</div>
<input type="text" class="msg-code">
<label class="get-code">免费获取短信验证码</label>
<label class="count-down"><span>60</span>秒后可重新操作</label>
<div class="code-error hide">
<i></i>
验证码错误
</div>
</div>
<div class="action-link">
<button id="relate-btn" class="relate-btn left">确定</button>
<a class="perv-step" href="javascript:void(0)">返回上一步</a>
</div>
</div>
<div id="hide-info" data-mobile="{{phoneNum}}" data-area="{{areaCode}}" data-refer="{{refer}}"></div>
</div>
... ...
<div class="login-page passport-page yoho-page clearfix">
<div style="font-size: 12px;text-align: center">
<div style="display: inline-block;width: 990px; height: 25px; background-color: #f5f5f5; line-height: 25px; overflow: hidden; margin-top: 10px;">
<i class="iconfont" style="font-size: 12px;">&#xe6c9;</i>&nbsp;&nbsp;为保障账户安全与正常使用,依《网络安全法》相关要求,会员账号需绑定手机号。<span style="color: red;">如您尚未绑定手机号,请尽快完成,</span>感谢您对Yoho!Buy有货的理解与支持!
</div>
</div>
{{# passport}}
{{> login/cover}}
<form method='post' onsubmit='return false;'>
... ...
... ... @@ -136,7 +136,6 @@ module.exports = {
id: '356b333091cdb78cd788e7bdd5f05c9f',
key: '6fef8ee77e41429de68455eeb052ce37'
},
UNIVERSAL_CAPTCHA: 'yoho4946abcdef#$%&!@',
apiCache: {
cache: false
},
... ...
{
"name": "yohobuy-node",
"version": "6.0.5",
"version": "6.0.11",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ...
No preview for this file type
This diff could not be displayed because it is too large.
No preview for this file type
No preview for this file type
... ... @@ -2,7 +2,8 @@ var $ = require('yoho-jquery'),
Captcha = require('../plugins/captcha');
var captcha = new Captcha('.captcha-wrap', {
checkURI: '/3party/check'
checkURI: '/3party/check',
page: 'robot'
}).init();
require('../common');
... ...
... ... @@ -303,6 +303,9 @@ deliveryWay = {
unsupport: $this.parent().hasClass('unsp-way')
};
// 设置默认支持状态
that.deliveryType[data.id].defaultSupport = !that.deliveryType[data.id].unsupport;
// 更新订单配送方式数据
if ($this.hasClass('checked')) {
that.updateOrder({way: data.id});
... ... @@ -370,7 +373,7 @@ deliveryWay = {
dt = this.deliveryType[id];
if (support && !dt.unsupport) {
if (support && dt.defaultSupport) {
dt.dom.parent().removeClass('unsp-way');
dt.unsupport = false;
} else {
... ...
... ... @@ -120,12 +120,24 @@ function getRefundCompute() {
});
}
function syncRefundMode(code) {
function syncRefundMode() {
var skns = [];
if (!defaultArea) {
return;
}
$goodsTable.find('input[type="checkbox"]:checked').each(function() {
skns.push($(this).siblings('input[name="skn"]').val());
});
$.ajax({
type: 'POST',
url: '/home/returns/getDelivery',
data: {
areaCode: code
orderCode: orderCode,
areaCode: defaultArea,
skns: skns.join(',')
}
}).then(function(jsonData) {
var _html = '';
... ... @@ -224,7 +236,7 @@ if ($refundInfo.length) {
}
});
} else if (defaultArea) {
syncRefundMode(defaultArea);
syncRefundMode();
}
defaultArea = defaultArea ? defaultArea : '';
... ... @@ -282,6 +294,7 @@ $checkBox.change(function() {
$par.next().hide();
}
syncRefundMode();
getRefundCompute();
});
... ... @@ -373,11 +386,9 @@ function fileChangeEvent() {
fileChangeEvent();// 初始化上传图片事件
$exchange.on('change', '#streets', function() {
var code = $(this).val() * 1;
defaultArea = $(this).val() * 1;
if (code) {
syncRefundMode(code);
}
syncRefundMode();
});
$refundType.change(function() {
... ...
... ... @@ -21,6 +21,8 @@ var $wrapper = $('.bindwrapper'),
var captcha = new Captcha('#captcha').init();
var captcha2;
var Alert = require('../../common/dialog').Alert;
require('../../simple-header');
/**
... ... @@ -381,8 +383,7 @@ function nextStep() {
circleTime($('#mobile').val());
} else if (data.code === 203) {
// 已注册 可关联
$('#bindmobileform').attr('action', data.data.next);
$('#bindmobileform').submit();
new Alert('绑定失败,该手机号已注册,请更换或使用该手机号直接登录').show();
} else if (data.code === 205) {
// 未注册 不可关联
username = data.data.user.username;
... ...
... ... @@ -11,6 +11,8 @@ var $wrapper = $('.bindwrapper'),
$phoneTip = $wrapper.find('.phone-err-tip'),
$nextBtn = $wrapper.find('.yohobindbtn');
var Alert = require('../../common/dialog').Alert;
require('../../simple-header');
/**
... ... @@ -151,7 +153,7 @@ function nextStep() {
$phoneTip.removeClass('hide');
} else {
if (data && data.message) {
alert(data.message); // eslint-disable-line
new Alert(data.message).show();
}
}
}
... ...
... ... @@ -640,10 +640,6 @@ function sendCaptchaSmsAsync() {
/* 短信验证图形验证 */
/** ************************************************************************/
function validateSmsCaptchaImg() {
return smsCaptchaImg.check();
}
function refreshSmsCaptchaImg() {
return smsCaptchaImg.refresh();
}
... ... @@ -1008,7 +1004,6 @@ $captchaSmsBtn.on('click', function() {
hideAccountTip2();
validateAccount()
.then(validateSmsCaptchaImg)
.then(function() {
return sendCaptchaSmsAsync().then(function(res) {
if (res.code === 200) {
... ...
... ... @@ -193,7 +193,7 @@ Captcha.prototype = {
result.push(this.$_____trojanYohobuy.val());
}
return result.join('') === '0000' ? '' : result.join('');
return result.join('') === '0000' ? '' : result.join(',');
},
/**
... ...
... ... @@ -70,7 +70,7 @@ var couponPickConfig = {
}]
},
over: {
content: '<i class="iconfont">&#xe61f;</i>优惠券已光',
content: '<i class="iconfont">&#xe61f;</i>优惠券已光',
subContents: ['尝试领取其它优惠券吧'],
className: 'top-coupon-dialog',
btns: [{
... ... @@ -103,7 +103,7 @@ function getCouponInfo() {
money: data.money || 0,
name: data.name || '',
time: data.time || '',
status: 1 // 1:可领取,2:已光,3:已领取
status: 1 // 1:可领取,2:已光,3:已领取
};
});
}
... ... @@ -137,18 +137,18 @@ function syncCouponStatus() {
for (i = 0; i < info.length; i++) {
asyncObj[info[i].coupon_id] = info[i];
}
}
for (i in couponObj) {
if (couponObj.hasOwnProperty(i)) {
coup = asyncObj[i];
for (i in couponObj) {
if (couponObj.hasOwnProperty(i)) {
coup = asyncObj[i];
if (coup) {
couponObj[i].status = coup.status;
coup.status === 3 ? setPicked(couponObj[i]) : false;
} else {
couponObj[i].status = 2; // 券不存在设置领取状态为已领光
couponObj[i].dom.text('已领光');
}
if (coup && (coup.status === 1 || coup.status === 3)) {
couponObj[i].status = coup.status;
coup.status === 3 ? setPicked(couponObj[i]) : false;
} else {
couponObj[i].status = 2; // 券不存在设置领取状态为已抢光
couponObj[i].dom.text('已抢光');
}
}
}
... ... @@ -245,7 +245,7 @@ if ($couponWrap && $couponWrap.length) {
if (!couponInfo) { // 优惠券号异常错误提示
return couponAlert(couponPickConfig.failed);
} else if (couponInfo.status === 2) { // 优惠券已光提示
} else if (couponInfo.status === 2) { // 优惠券已光提示
return couponAlert(couponPickConfig.over);
} else if (couponInfo.status === 3) { // 优惠券已领取提示
return couponAlert(couponPickConfig.got);
... ...