Authored by ccbikai(👎🏻🍜)

Merge branch 'master' into release/5.4.1

... ... @@ -294,6 +294,8 @@ const index = (req, res, next) => {
isWeibo = req.yoho.isWeibo,
isShare;
res.locals.appPath = `yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.h5","params":{"id":"${id}","share":"/guang/api/v1/share/guang?id=${id}","shareparam":{"id":"${id}"},"islogin":"N","type":1,"url":"http://guang.m.yohobuy.com/info/index","param":{"id":"${id}"}}}`;
// pagecache 前端做
// userAgent = req.get('User-Agent'),
// isWeixin = userAgent.includes('MicroMessenger'); // 标识是否是微信访问
... ...
... ... @@ -11,12 +11,18 @@ exports.index = (req, res, next) => {
if (Number(appversion.substr(0, 1) < 5) || (Number(appversion.substr(0, 1)) === 5 && Number(appversion.substr(2, 1)) < 2)) {
esc = true;
}
let uname;
try {
uname = esc ? decodeURIComponent(params.uname) : decodeURIComponent(params.uname.replace(/\%/g, escape('%')));
} catch (e) {
uname = params.uname;
}
model.getQr({
token: params.token,
}).then(result => {
params.token = result;
params.uname = esc ? decodeURIComponent(params.uname) : decodeURIComponent(params.uname.replace(/\%/g, escape('%')));
params.uname = uname;
params.icon = params.icon || 'https://img11.static.yhbimg.com/yhb-img01/2016/07/05/13/017ec560b82c132ab2fdb22f7cf6f42b83.png?imageView/2/w/{width}/h/{height}';
res.render('myqrcode', {
title: '查看二维码',
... ...
... ... @@ -12,6 +12,8 @@ const RegService = require('../models/reg-service');
const BindService = require('../models/bind-service');
const AuthHelper = require('../models/auth-helper');
const _ = require('lodash');
const config = global.yoho.config;
const moment = require('moment');
const Sources = {
qq: 'QQ',
... ... @@ -87,32 +89,57 @@ const bind = {
let openId = req.body.openId;
let areaCode = req.body.areaCode || '86';
let sourceType = req.body.sourceType;
let verify = req.body.verify || '';
let testCode = req.body.yohobuy;
if (_.isNumber(parseInt(phoneNum, 0)) && openId && areaCode && sourceType) {
BindService.bindCheck(phoneNum, openId, sourceType, areaCode).then(result => {
let data = {
code: result.code,
message: result.message,
data: {}
};
if (result.code === 200) {
let nextUrl = helpers.urlFormat('/passport/bind/code', {
isReg: result.data.is_register, // esline-disable-line
openId: openId,
sourceType: sourceType,
areaCode: areaCode,
phoneNum: phoneNum
});
data.data.isReg = result.data.is_register;
data.data.next = nextUrl;
if (verify) {
let captcha = _.get(req, 'session.captcha');
if ((captcha && verify.toString() === captcha) || (testCode === config.testCode)) {
BindService.bindCheck(phoneNum, openId, sourceType, areaCode).then(result => {
let data = {
code: result.code,
message: result.message,
data: {}
};
if (result.code === 200) {
let nextUrl = helpers.urlFormat('/passport/bind/code', {
isReg: result.data.is_register, // esline-disable-line
openId: openId,
sourceType: sourceType,
areaCode: areaCode,
phoneNum: phoneNum
});
data.data.isReg = result.data.is_register;
data.data.next = nextUrl;
_.set(req.session, 'bind.area', areaCode);
_.set(req.session, 'bind.phoneNum', phoneNum);
} else {
data.data = result.data;
}
res.json(data);
}).catch(next);
} else {
data.data = result.data;
let jsonData = {
code: 400,
message: '请将图片旋转到正确位置'
};
if (req.session.captchaValidCount === 0) {
req.session.captcha = null; // 验证码 用过就扔
jsonData.changeCaptcha = true;
}
return res.json(jsonData);
}
res.json(data);
}).catch(next);
_.set(req.session, 'captcha', null);
}
} else {
res.json({
code: 400,
... ... @@ -122,13 +149,62 @@ const bind = {
}
},
// 防刷
sendBefore: (req, res, next) => {
let count = _.get(req.session, 'bind.count');
let interval = _.get(req.session, 'bind.interval');
let now = Date.now();
// // 重发次数用完了, 会冻结5min
// // 1. 过了冻结期, count 重设为 5次
// // 2. 没过冻结期, end
// // 没有用完, 判断是否请求太频繁
let during = moment.duration(interval - now, 'ms').minutes();
let message = `请${during}分钟后再试`;
if (!count) {
if (interval > now) {
return res.json({
code: 400,
message: message,
during: Math.ceil((interval - now) / 1000)
});
} else {
_.set(req.session, 'bind.count', 5);
}
} else if (interval > now) {
return res.json({
code: 429,
message: message
});
}
next();
},
sendBindMsg: (req, res, next) => {
let phoneNum = req.body.phoneNum;
let areaCode = req.body.areaCode;
let phoneNum = _.get(req.session, 'bind.phoneNum');
let areaCode = _.get(req.session, 'bind.area');
if (req.xhr && _.isNumber(parseInt(phoneNum, 0)) && areaCode) {
BindService.sendBindMsg(areaCode, phoneNum).then(result => {
if (result && result.code) {
if (result.code === 200) {
_.set(req.session, 'bind.area', areaCode);
_.set(req.session, 'bind.phoneNum', phoneNum);
--req.session.bind.count;
if (!req.session.bind.count) {
_.set(req.session, 'bind.interval', Date.now() + 5 * 60 * 1000);
} else {
_.set(req.session, 'bind.interval', Date.now() + 60 * 1000);
}
}
res.json(result);
} else {
res.json({ code: 400, message: '', data: '' });
... ...
... ... @@ -94,6 +94,13 @@ const local = {
// res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800);
// 清除cookie
if (req.session && req.session.destroy) {
req.session.destroy();
}
if (req.session2 && req.session2.reset) {
req.session2.reset();
}
res.clearCookie('_UID', {
domain: 'yohobuy.com'
});
... ... @@ -121,7 +128,8 @@ const local = {
emailRetriveUrl: '/passport/back/email', // 通过邮箱找回密码的URL链接
module: 'passport',
page: 'login',
title: '登录'
title: '登录',
reg: true
});
},
international: (req, res) => {
... ... @@ -134,6 +142,13 @@ const local = {
// res.cookie('LE' + md5('_LOGIN_EXPIRE'), (new Date()).getTime() / 1000 + 1800);
// 清除cookie
if (req.session && req.session.destroy) {
req.session.destroy();
}
if (req.session2 && req.session2.reset) {
req.session2.reset();
}
res.clearCookie('_UID', {
domain: 'yohobuy.com'
});
... ...
... ... @@ -77,7 +77,9 @@ router.get('/login/alipay/callback', login.alipay.callback);
router.get('/passport/bind/index', bind.indexPage);
router.post('/passport/bind/bindCheck', bind.bindCheck);
router.get('/passport/bind/code', bind.codePage);
router.post('/passport/bind/sendBindMsg', bind.sendBindMsg);
router.post('/passport/bind/sendBindMsg',
bind.sendBefore,
bind.sendBindMsg);
router.post('/passport/bind/bindMobile', bind.bindMobile);
router.post('/passport/bind/relateMobile', bind.relateMobile);
... ...
... ... @@ -14,6 +14,13 @@
<span id="area-code" class="area-code">{{areaCode}}</span>
<input id="phone-num" class="input phone-num" type="text" placeholder="手机号">
</div>
{{!--图片验证 start--}}
<div id="js-img-check">
<input type="hidden" name="captsrc" value="{{captsrc}}">
</div>
{{!--图片验证 end--}}
<span id="btn-next" class="btn btn-next disable row">发送验证码</span>
{{#if isWechatLogin}}
... ...
... ... @@ -11,8 +11,9 @@
<div id="js-img-check" {{#captchaShow }}data-init{{/captchaShow}}></div>
<span id="btn-login" class="btn btn-login disable">登录</span>
<p class="op-container">
<a class="sms-login" href={{smsLoginUrl}}>手机号码快捷登录</a>
<span id="forget-pwd" class="forget-pwd">忘记密码</span>
<a class="op-item internat" href={{internationalUrl}}>海外手机</a>
<a class="op-item sms-login" href={{smsLoginUrl}}>快速登录</a>
<span id="forget-pwd" class="op-item forget-pwd">忘记密码</span>
</p>
<div class="third-party-login">
<div class="tp-link">
... ... @@ -22,15 +23,12 @@
<a class="alipay" href={{aliLoginUrl}}></a>
</div>
</div>
<a class="international" href={{internationalUrl}}>International Customer</a>
<div class="go-register">
<i class="iconfont">&#xe610;</i>
<a href={{registerUrl}}>注册Yoho!Family</a>
</div>
<div class="login-tip">
<div class="info-icon"></div>
Yoho!Family账号可登录Yoho!Buy有货
</div>
<div id="retrive-pwd-mask" class="mask"></div>
<ul id="retrive-pwd-ways" class="retrive-pwd-ways">
<li>
... ...
... ... @@ -6,4 +6,7 @@
{{#headerText}}
<p class="title">{{.}}</p>
{{/headerText}}
{{#reg}}
<a href="{{registerUrl}}" class="opts register">注册</a>
{{/reg}}
</div>
\ No newline at end of file
... ...
... ... @@ -10,6 +10,7 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta content="telephone=no" name="format-detection" />
<meta content="email=no" name="format-detection" />
<meta name="referrer" content="always">
{{# cononical}}
<link rel="cononical" href="{{currentHref}}"/>
{{/ cononical}}
... ...
... ... @@ -12,7 +12,7 @@
a.async = 1;
a.src = j;
m.parentNode.insertBefore(a, m);
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.2.5/yas.js', '_yas'));
}(window, document, 'script', (document.location.protocol === 'https:' ? 'https:' : 'http:') + '//cdn.yoho.cn/yas-jssdk/2.3.0/yas.js', '_yas'));
var _hmt = _hmt || [];
... ... @@ -56,7 +56,7 @@
uid = uid === 0 ? '' : uid;
window._ozuid = uid; // 暴露ozuid
if (window._yas) {
window._yas(1 * new Date(), '2.2.5', 'yohobuy_m', uid, '', '');
window._yas(1 * new Date(), '2.3.0', 'yohobuy_m', uid, '', '');
}
setTimeout(function() {
... ...
{
"name": "m-yohobuy-node",
"version": "5.4.9",
"version": "5.4.13",
"private": true,
"description": "A New Yohobuy Project With Express",
"repository": {
... ...
... ... @@ -280,7 +280,7 @@ function ajaxResource() {
$.ajax({
method: 'get',
url: location.protocol + '//m.yohobuy.com/product/opt/favoriteBrand',
url: '/product/opt/favoriteBrand',
data: {
id: self.parent().attr('shopId'),
opt: opt,
... ... @@ -323,7 +323,7 @@ function ajaxResource() {
// vip专属等级查询
$.ajax({
method: 'POST',
url: location.protocol + '//m.yohobuy.com/channel/userVip',
url: '/channel/userVip',
data: {
channel: 1,
},
... ...
... ... @@ -3,17 +3,57 @@
*/
const qs = require('yoho-qs');
const u = navigator.userAgent;
const isFromYOHO = /m\.yohobuy\.com/i.test(document.referrer);
const isApp = /yohobuy/i.test(u) || !!window.yohoInterface || /app_version=/i.test(location.search) || /openrefer=/i.test(location.search);
const isiOS = /(iPhone|iPad|iPod|iOS)/i.test(u); // ios终端
const isAndroid = /Android/i.test(u); // android终端
const iOSVersion = parseInt((u.match(/OS (\d+)_(\d+)_?(\d+)?/i) || [])[1], 10); // iOS 版本
const nodownload = document.getElementById('no-download'); // 页面不需要下载
const urlBlacklist = ['m.yohobuy.com/brands', 'm.yohobuy.com/passport'];
const blackCheck = urlBlacklist.some(function (url) {
return new RegExp(url, 'i').test(location.href);
});
const canOpenApp = () => {
if (isApp || isFromYOHO || nodownload || qs.nodownload || qs.no_openapp || blackCheck) {
return false;
}
return isAndroid || iOSVersion < 9 || qs.openapp;
};
const getAppPath = () => {
return document.getElementById('main-wrap').dataset.apppath || 'yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.home","params":{"gender":"1","channel":"2"}}';
let appPath = document.getElementById('main-wrap').dataset.apppath || 'yohobuy://yohobuy.com/goapp?openby:yohobuy={"action":"go.home","params":{"gender":"1","channel":"2"}}';
let ct = qs.mkt_code || qs.union_type;
if (ct) {
appPath = appPath.replace('goapp?', 'goapp?ct=' + ct + '&');
}
return appPath;
};
if (qs.openapp) {
const u = navigator.userAgent.toLowerCase();
const isiOS = u.indexOf('os') > -1 || u.indexOf('iphone') > -1 || u.indexOf('mac') > -1 || u.indexOf('ipad') > -1;
if (canOpenApp()) {
let appPath = getAppPath();
let ifr;
if (window._yas && window._yas.sendCustomInfo) {
window._yas.sendCustomInfo({
op: 'YB_H5_AWAKE_APP',
param: JSON.stringify({
PAGE_NAME: encodeURIComponent(document.title),
PAGE_URL: encodeURIComponent(location.href)
})
}, true);
}
if (window._hmt && window._hmt.push) {
window._hmt.push(['_trackEvent', 'H5唤起APP', isiOS ? 'Apple' : 'Android', document.title, location.href]);
}
if (isiOS) {
window.location.href = appPath;
} else {
... ... @@ -22,14 +62,4 @@ if (qs.openapp) {
ifr.style.display = 'none';
document.body.appendChild(ifr);
}
// let time = Date.now();
// window.setTimeout(function() {
// document.body.removeChild(ifr);
// if (Date.now() - time < 2200) {
// window.location.href = 'http://a.app.qq.com/o/simple.jsp?pkgname=com.yoho';
// }
// }, 2000);
}
... ...
... ... @@ -24,6 +24,17 @@ var requested = false;
require('../../common');
var ImgCheck = require('plugin/img-check');
var imgCheck = new ImgCheck('#js-img-check', {
useREM: {
rootFontSize: 40,
picWidth: 150
}
});
imgCheck.init();
function nextStep(url, mobileNo, areaCode) {
if (requested) {
return false;
... ... @@ -31,7 +42,6 @@ function nextStep(url, mobileNo, areaCode) {
requested = true;
$btnNext.addClass('disable').html('绑定中...');
$.ajax({
type: 'POST',
url: '/passport/bind/sendBindMsg',
... ... @@ -85,7 +95,8 @@ $btnNext.on('touchstart', function() {
openId = trim($openId.val()),
nickname = trim($nickname.val()),
sourceType = trim($sourceType.val()),
areaCode = $countrySelect.val();
areaCode = $countrySelect.val(),
verify = trim(imgCheck.getResults());
if ($btnNext.hasClass('disable')) {
return;
... ... @@ -100,12 +111,11 @@ $btnNext.on('touchstart', function() {
phoneNum: pn,
openId: openId,
sourceType: sourceType,
nickname: nickname
nickname: nickname,
verify: verify
},
success: function(res) {
// console.log(res);
// res : {
// code: 'xxx',
// data: {
... ...
... ... @@ -5,6 +5,8 @@
*/
var $ = require('yoho-jquery');
require('js/common');
module.exports = function(useInRegister, useForBind, useForRelate) {
var $captcha = $('#captcha'),
$btnNext = $('#btn-next'),
... ... @@ -79,8 +81,8 @@ module.exports = function(useInRegister, useForBind, useForRelate) {
});
}
function countDown() {
var count = 59,
function countDown(during) {
var count = during || 59,
itime;
itime = setInterval(function() {
... ... @@ -89,6 +91,11 @@ module.exports = function(useInRegister, useForBind, useForRelate) {
clearInterval(itime);
} else {
$captchaTip.text('重新发送 (' + count-- + '秒)');
window.setCookie('count', count);
if (during && parseInt(during) !== 0) {
$captchaTip.addClass('disable');
}
}
}, 1000);
}
... ... @@ -121,6 +128,7 @@ module.exports = function(useInRegister, useForBind, useForRelate) {
$captchaTip.text('重发验证码 (60秒)').addClass('disable');
countDown();
} else {
data.during && countDown(data.during);
// 验证码不正确,显示提示
showErrTip(data.message);
... ... @@ -148,5 +156,10 @@ module.exports = function(useInRegister, useForBind, useForRelate) {
}
});
countDown();
if (window.cookie('count') && parseInt(window.cookie('count')) > 0) {
countDown(window.cookie('count'));
} else {
countDown();
}
};
... ...
... ... @@ -67,6 +67,22 @@ body.passport-body {
background-size: 100% 100%;
margin: 0 auto;
}
.opts {
display: block;
background: transparent;
border: solid 1PX #fff;
width: auto;
height: 30PX;
line-height: 30PX;
border-radius: 30PX;
color: #fff;
padding-left: 15PX;
padding-right: 15PX;
position: absolute;
right: 0;
top: 5PX;
}
}
.input-container,
... ...
... ... @@ -17,19 +17,21 @@
position: relative;
width: 100%;
margin: 20PX 0;
text-align: left;
text-align: center;
font-size: 16PX;
display: flex;
.sms-login {
text-decoration: underline;
color: #858585;
.op-item {
flex: 1;
color: #fff;
}
.internat {
text-align: left;
}
.forget-pwd {
position: absolute;
right: 0;
text-decoration: underline;
color: #858585;
text-align: right;
}
}
... ... @@ -96,7 +98,7 @@
}
.login-tip {
font-size: 16PX;
font-size: 14PX;
position: relative;
color: #d8d8d8;
margin: 15PX 0;
... ...
... ... @@ -11,7 +11,13 @@ const url = require('url');
* @return referer
*/
exports.refererLimit = (referer, blacklist) => { // eslint-disable-line
let result = decodeURIComponent(referer || '/home');
let result;
try {
result = decodeURIComponent(referer || '/home');
} catch (e) {
result = referer || '/home';
}
let urlObj = url.parse(result, false, true);
... ...