//(function(){ /** * @description 基础方法 * @param {String | Object} n dom元素的id,或者dom元素 * @class */ var $ = window.Simple = function(n) { return typeof(n) == "string" ? document.getElementById(n) : n; } /** * @description cookie相关 * @class */ $.cookie = { /** * @description 读取cookie * @public * @param {String} n 名称 * @returns {String} cookie值 * @example * $.cookie.get('id_test'); */ get: function (b) { var filterXSS = function (e) { if (!e) return e; for (; e != unescape(e);) e = unescape(e); for (var r = ["<", ">", "'", '"', "%3c", "%3e", "%27", "%22", "%253c", "%253e", "%2527", "%2522"], n = ["<", ">", "'", """, "%26%23x3c%3B", "%26%23x3e%3B", "%26%23x27%3B", "%26%23x22%3B", "%2526%2523x3c%253B", "%2526%2523x3e%253B", "%2526%2523x27%253B", "%2526%2523x22%253B"], a = 0; a < r.length; a++) e = e.replace(new RegExp(r[a], "gi"), n[a]); return e }; var a; return filterXSS((a = document.cookie.match(RegExp("(^|;\\s*)" + b + "=([^;]*)(;|$)"))) ? unescape(a[2]) : ''); }, /** * @description 设置cookie * @public * * @param {String} name cookie名称 * @param {String} value cookie值 * @param {String} [domain = ""] 所在域名 * @param {String} [path = "/"] 所在路径 * @param {Number} [hour = 30] 存活时间,单位:小时;不设置默认为回话cookie * @example * $.cookie.set('value1','cookieval',"id.qq.com","/test",24); //设置cookie */ set: function(name, value, domain, path, hour) { var expire = new Date(); if (hour) { expire.setTime(expire.getTime() + 3600000 * hour); document.cookie = name + "=" + value + "; " + "expires=" + expire.toGMTString() + "; path=" + (path ? path : "/") + "; " + (domain ? ("domain=" + domain + ";") : ""); } else { document.cookie = name + "=" + value + "; " + "path=" + (path ? path : "/") + "; " + (domain ? ("domain=" + domain + ";") : ""); } }, /** * @description 删除指定cookie,复写为过期 !!注意path要严格匹配, /id 不同于/id/ * @public * * @param {String} name cookie名称 * @param {String} [domain] 所在域 * @param {String} [path = "/"] 所在路径 * @example * $.cookie.del('id_test'); //删除cookie */ del: function(name, domain, path) { document.cookie = name + "=; expires=Mon, 26 Jul 1997 05:00:00 GMT; path=" + (path ? path : "/") + "; " + (domain ? ("domain=" + domain + ";") : ""); }, /** * 获取uin,针对业务,对外开源请删除 * @public * * @return {String} uin值 * @example * $.cookie.uin(); */ uin: function() { var u = $.cookie.get("uin"); return !u ? null : parseInt(u.substring(1, u.length), 10); } }; /** * @description 加载iframe * @class */ $.iframe = function(){ function receiveMessageFromIframePage(event) { console.log('receiveMessageFromIframePage', event) var msg = event && event.data && event.data.msg || '' switch (msg) { case 'exit': this.opt.onClose && this.opt.onClose(event) this.reset(event) break; case 'success': this.opt.success && this.opt.success(event) break; case this.opt.heartBeat: this.opt.onload && this.opt.onload(event) this._hasHeartBeat = true break; case 'pt_smsSubmit': this.opt.smsSubmitEvent && this.opt.smsSubmitEvent() break; default: break; } } return new function () { this.id = '' this.parent = null this.parentID = '' /** * 初始化入口 * @param {[type]} opt [description] * @return {[type]} [description] */ this.init = function (opt) { var opt = opt || {} this.opt = opt opt.initTime = +new Date() opt.heartBeatTime = opt.heartBeatTime || 10000 opt.heartBeat = opt.heartBeat || 'heartBeat' if (this.__hasinit) { return } this.__hasinit = true var iframe = document.createElement('iframe') console.log('createElement iFrame opt:',opt); console.trace(); iframe.name = opt.name || 'iframe' this.id = iframe.id = opt.id || 'iframeid'; this.parentID = opt.parentID iframe.style.cssText = opt.iframeStyle || 'z-index:999;height:100%;width:100%;position:fixed;left:0;top:0;right:0;bottom:0' iframe.src = opt.url var iframe_mask = null; if(this.parentID){ iframe_mask = document.createElement('div'); if(opt.parentStyle){ iframe_mask.setAttribute('style',opt.parentStyle) } iframe_mask.setAttribute('id',opt.parentID) if(opt.bgFilter){ var filter = document.createElement('div') filter.setAttribute('style',"width:100%;height:100%;position: absolute;left:0;top:0;background: inherit;filter: blur(15px);") iframe_mask.appendChild(filter) } iframe_mask.appendChild(iframe) document.body.append(iframe_mask) }else{ document.body.appendChild(iframe) } this.receiveMessageFromIframePage = receiveMessageFromIframePage.bind(this) this.heartBeat(opt) this.addListener(opt) }; this.__hasinit = false this._hasHeartBeat = false this.addListener = function (opt) { //监听message事件 window.addEventListener("message", this.receiveMessageFromIframePage, false); } this.postMessage = function (opt) { var iframeChild = document.getElementById(this.id);//获取iframe iframeChild.contentWindow.postMessage(opt,'https://ui.ptlogin2.qq.com');//childDomain是子页面的源(协议+主机+端口号) } this.heartBeat = function (opt) { var self = this var time = opt.heartBeatTime || 10000 setTimeout(function () { if (self._hasHeartBeat) { //有心跳,继续 console.log('子页面调起成功') } else { console.log('子页面调起失败') //self.reset() opt.fail && opt.fail({ msg: '子页面调起失败,timeout' }) } }, time) } this.reset = function () { var self = this self.__hasinit = false var iFrame = document.getElementById(self.id) var parent = document.getElementById(self.parentID) if(parent){ document.body.removeChild(parent) }else if(iFrame) { document.body.removeChild(iFrame) } window.removeEventListener("message", this.receiveMessageFromIframePage, false); } }; } /** * @description url相关 */ $.url = { getParam: function (name, url) { url = url || window.location.href var r = new RegExp('(\\?|#|&)' + name + '=(.*?)(&|#|$)') var m = url.match(r) if (m){ return decodeURIComponent(m[2]) } return '' } } /** *@description http相关 *@class */ $.http = { /** * @description jsonp获取回调函数-- 可以支持跨域 * * @param {String} url 请求路径 * @example * $.http.jsonp('http://webryan.net/cgi-bin/test'); //cgi的返回值应该是 fnCallback({'data':''})的形式 */ jsonp: function(url) { var s = document.createElement("script"); s.src = url; document.getElementsByTagName("head")[0].appendChild(s); }, /** * @description 异步加载script脚本,并回调 * * @param {String} src 请求路径 * @param {Function} callback 加载文档后的回调函数 * @param {Function} err 加载失败后回调 * @example * $.http.loadScript('http://webryan.net/js/index.js',function(){alert()}); //callback通常为函数名,非字符串 */ loadScript: function(src, callback, err) { var tag = document.createElement("script"); /** * Attach handlers for all browsers * @ignore */ tag.onload = tag.onreadystatechange = function() { if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") { // 执行回调 if (typeof callback == "function") { callback(); } // Handle memory leak in IE tag.onload = tag.onreadystatechange = null; if (tag.parentNode) { tag.parentNode.removeChild(tag); } } }; tag.src = src; document.getElementsByTagName("head")[0].appendChild(tag); }, /** * @description发出ajax请求 * * @param {String} url 请求路径--不能跨域 * @param {Object} [para] 参数列表 * @param {Function} cb 回调函数 * @param {String} method 请求方式: [post|get] * @param {String} [type = json] 数据类型:[json|text] --默认为json * @example * $.http.ajax('/cgi-bin/info',{'uin':10001},fnCallBack,'get'); */ ajax: function(url, para, cb, method, type) { var xhr = new XMLHttpRequest(); xhr.open(method, url); /** * onreadystatechange * @ignore */ xhr.onreadystatechange = function() { if (xhr.readyState == 4) { //ie error with 1223 and opera with 304 or 0 if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || xhr.status === 1223 || xhr.status === 0) { if (typeof(type) == "undefined" && xhr.responseText) { cb(eval("(" + xhr.responseText + ")")); //不容错,以便于排查json错误 } else { cb(xhr.responseText); } } xhr = null; } }; xhr.send(para); return xhr; }, /** * @description 通过ajax发出get请求 * * @param {String} url 请求路径--不能跨域 * @param {Object} [para] 参数列表 * @param {Function} cb 回调函数 * @param {String} [type = "json"] 数据类型:[json|text] --默认为json * @example * $.http.get('/cgi-bin/info',{'uin':10001},fnCallBack); */ get: function(url, para, cb, type) { if (para) { var params = []; for (var p in para) { if (para.hasOwnProperty(p)) params.push(p + "=" + para[p]); } if (url.indexOf("?") == -1) { url += "?"; } url += params.join('&'); } return $.http.ajax(url, null, cb, "GET", type); }, /** * @description 预加载某个文件,包括图片,js,flash --可以用于上报 * * @param {String} url 请求路径 * @example * $.http.preload('http://webryan.net/swf/friends.swf'); */ preload: function(url) { var s = document.createElement("img"); s.src = url; s = null; } }; /** * @description 通过ajax发出get请求 * * @param {String} url 请求路径--不能跨域 * @param {Object} [para] 参数列表 * @param {Function} cb 回调函数 * @param {String} [type = "json"] 数据类型:[json|text] --默认为json * @example * $.get('/cgi-bin/info',{'uin':10001},fnCallBack); */ $.get = $.http.get; /** * @description 通过ajax发出post请求 * * @param {String} url 请求路径--不能跨域 * @param {Object} para 参数列表 * @param {Function} cb 回调函数 * @param {String} [type = "json"] 数据类型:[json|text] --默认为json * @example * $.post('/cgi-bin/info_mod',{'uin':10001},fnCallBack); */ $.post = $.http.post; /** * @description jsonp获取回调函数-- 可以支持跨域 * * @param {String} url 请求路径 * @example * $.http.jsonp('http://webryan.net/cgi-bin/test'); //cgi的返回值应该是 fnCallback({'data':''})的形式 */ $.jsonp = $.http.jsonp; /** * @description 获取浏览器的版本等信息 * @class * @param {String} name [type-类型1.msie.2.ff.3.opera.4.webkit|version--版本号] * * @example * $.browser("type"); $.browser("version"); */ $.browser = function(name) { if (typeof $.browser.info == "undefined") { var ret = { type: "" }; var ua = navigator.userAgent.toLowerCase(); if (/chrome/.test(ua)) { ret = { type: "chrome", version: /chrome[\/ ]([\w.]+)/ }; } else if (/opera/.test(ua)) { ret = { type: "opera", version: /version/.test(ua) ? /version[\/ ]([\w.]+)/ : /opera[\/ ]([\w.]+)/ }; } else if (/msie/.test(ua)) { ret = { type: "msie", version: /msie ([\w.]+)/ }; } else if (/mozilla/.test(ua) && !/compatible/.test(ua)) { ret = { type: "ff", version: /rv:([\w.]+)/ }; } else if (/safari/.test(ua)) { ret = { type: "safari", version: /safari[\/ ]([\w.]+)/ }; } ret.version = (ret.version && ret.version.exec(ua) || [0, "0"])[1]; $.browser.info = ret; } return $.browser.info[name] }; /** * 事件相关 -- 绑定,解绑,触发 */ $.e = { // Private utility to generate unique handler ids _counter: 0, _uid: function() { return "h" + $.e._counter++; }, add: function(element, eventType, handler) { if (typeof element != "object") { element = $(element); } if (document.addEventListener) { element.addEventListener(eventType, handler, false); } else if (document.attachEvent) { if ($.e._find(element, eventType, handler) != -1) return; // To invoke the handler function as a method of the // element, we've got to define this nested function and register // it instead of the handler function itself. var wrappedHandler = function(e) { if (!e) e = window.event; // Create a synthetic event object with partial compatibility // with DOM events. var event = { _event: e, // In case we really want the IE event object type: e.type, // Event type target: e.srcElement, // Where the event happened currentTarget: element, // Where we're handling it relatedTarget: e.fromElement ? e.fromElement : e.toElement, eventPhase: (e.srcElement == element) ? 2 : 3, // Mouse coordinates clientX: e.clientX, clientY: e.clientY, screenX: e.screenX, screenY: e.screenY, // Key state --fix:keyCode altKey: e.altKey, ctrlKey: e.ctrlKey, shiftKey: e.shiftKey, keyCode: e.keyCode, data: e.data, origin: e.origin, // Event-management functions stopPropagation: function() { this._event.cancelBubble = true; }, preventDefault: function() { this._event.returnValue = false; } } // Invoke the handler function as a method of the element, passing // the synthetic event object as its single argument. // Use Function.call( ) if defined; otherwise do a hack if (Function.prototype.call) handler.call(element, event); else { // If we don't have Function.call, fake it like this. element._currentHandler = handler; element._currentHandler(event); element._currentHandler = null; } }; // Now register that nested function as our event handler. element.attachEvent("on" + eventType, wrappedHandler); // Now we must do some record keeping to associate the user-supplied // handler function and the nested function that invokes it. // We have to do this so that we can deregister the handler with the // remove( ) method and also deregister it automatically on page unload. // Store all info about this handler into an object. var h = { element: element, eventType: eventType, handler: handler, wrappedHandler: wrappedHandler }; // Figure out what document this handler is part of. // If the element has no "document" property, it is not // a window or a document element, so it must be the document // object itself. var d = element.document || element; // Now get the window associated with that document. var w = d.parentWindow; // We have to associate this handler with the window, // so we can remove it when the window is unloaded. var id = $.e._uid(); // Generate a unique property name if (!w._allHandlers) w._allHandlers = {}; // Create object if needed w._allHandlers[id] = h; // Store the handler info in this object // And associate the id of the handler info with this element as well. if (!element._handlers) element._handlers = []; element._handlers.push(id); // If there is not an onunload handler associated with the window, // register one now. if (!w._onunloadHandlerRegistered) { w._onunloadHandlerRegistered = true; w.attachEvent("onunload", $.e._removeAllHandlers); } } }, remove: function(element, eventType, handler) { if (document.addEventListener) { element.removeEventListener(eventType, handler, false); } else if (document.attachEvent) { // Find this handler in the element._handlers[] array. var i = $.e._find(element, eventType, handler); if (i == -1) return; // If the handler was not registered, do nothing // Get the window of this element. var d = element.document || element; var w = d.parentWindow; // Look up the unique id of this handler. var handlerId = element._handlers[i]; // And use that to look up the handler info. var h = w._allHandlers[handlerId]; // Using that info, we can detach the handler from the element. element.detachEvent("on" + eventType, h.wrappedHandler); // Remove one element from the element._handlers array. element._handlers.splice(i, 1); // And delete the handler info from the per-window _allHandlers object. delete w._allHandlers[handlerId]; } }, // A utility function to find a handler in the element._handlers array // Returns an array index or -1 if no matching handler is found _find: function(element, eventType, handler) { var handlers = element._handlers; if (!handlers) return -1; // if no handlers registered, nothing found // Get the window of this element var d = element.document || element; var w = d.parentWindow; // Loop through the handlers associated with this element, looking // for one with the right type and function. // We loop backward because the most recently registered handler // is most likely to be the first removed one. for (var i = handlers.length - 1; i >= 0; i--) { var handlerId = handlers[i]; // get handler id var h = w._allHandlers[handlerId]; // get handler info // If handler info matches type and handler function, we found it. if (h.eventType == eventType && h.handler == handler) return i; } return -1; // No match found }, _removeAllHandlers: function() { // This function is registered as the onunload handler with // attachEvent. This means that the this keyword refers to the // window in which the event occurred. var w = this; // Iterate through all registered handlers for (id in w._allHandlers) { // Get handler info for this handler id var h = w._allHandlers[id]; // Use the info to detach the handler h.element.detachEvent("on" + h.eventType, h.wrappedHandler); // Delete the handler info from the window delete w._allHandlers[id]; } }, /** * 获取时间发生的元素 * @param {Object} e 事件 */ src: function(e) { return e ? e.target : event.srcElement; }, /** * 阻止冒泡 * */ stopPropagation: function(e) { e ? e.stopPropagation() : event.cancelBubble = true; } }; /** * @description BOM相关,toolkit * @class */ $.bom = { /** * @description 读取location.search * * @param {String} n 名称 * @return {String} search值 * @example * $.bom.query('mod'); */ query: function(n) { var m = window.location.search.match(new RegExp("(\\?|&)" + n + "=([^&]*)(&|$)")); return !m ? "" : decodeURIComponent(m[2]); } }; /** * 用来设置window.name的属性 * name的形式: ;a=xxxxxxx;b=xxxxxxx;c=xxxxxxx */ $.winName = { set: function(n, v) { var name = window.name || ""; if (name.match(new RegExp(";" + n + "=([^;]*)(;|$)"))) { //先验证是否存在 window.name = name.replace(new RegExp(";" + n + "=([^;]*)"), ";" + n + "=" + v); } else { window.name = name + ";" + n + "=" + v; } }, get: function(n) { var name = window.name || ""; var v = name.match(new RegExp(";" + n + "=([^;]*)(;|$)")); return v ? v[1] : ""; }, clear: function(n) { var name = window.name || ""; window.name = name.replace(new RegExp(";" + n + "=([^;]*)"), ""); } }; //本地存储 $.localStorage = { //有些浏览器禁用cookie后会导致这个报错 isSupport:function(){ try{ return window.localStorage ? true : false; }catch(e){ return false; } } , get: function(key) { var v = ""; try { v = window.localStorage.getItem(key); } catch (e) { v = "" } return v; }, set: function(key, value) { try { window.localStorage.setItem(key, value); } catch (e) {} }, remove: function(key) { try { window.localStorage.removeItem(key); } catch (e) {} } }; /** * @description 字符串常用操作 * @date 2011.11.30 * @author knightli * @class */ $.str = (function() { var htmlDecodeDict = { "quot": '"', "lt": "<", "gt": ">", "amp": "&", "nbsp": " ", "#34": '"', "#60": "<", "#62": ">", "#38": "&", "#160": " " }; //var htmlEncodeDict = { '"': "quot", "<": "lt", ">": "gt", "&": "amp", " ": "nbsp" }; var htmlEncodeDict = { '"': "#34", "<": "#60", ">": "#62", "&": "#38", " ": "#160" }; return { /** * @description 将字符串里entity解码成对应的符号,如<对应< * @param {String} s 原始字符串 * @return {String} 处理后字符串 * @example * $.str.decodeHtml('<script></script>'); 返回结果为:"" */ decodeHtml: function(s) { s += ''; return s.replace(/&(quot|lt|gt|amp|nbsp);/ig, function(all, key) { return htmlDecodeDict[key]; }).replace(/&#u([a-f\d]{4});/ig, function(all, hex) { return String.fromCharCode(parseInt("0x" + hex)); }).replace(/&#(\d+);/ig, function(all, number) { return String.fromCharCode(+number); }); }, /** * @description 将字符串里的"<"、"&"等转成对应entity * @param {String} s 原始字符串 * @return {String} 处理后字符串 * @example * $.str.encodeHtml(''); 返回结果为:"<script></script>" */ encodeHtml: function(s) { s += ''; return s.replace(/["<>& ]/g, function(all) { return "&" + htmlEncodeDict[all] + ";"; }); }, /** * @description 删除首尾空格 * @param {String} str 原始字符串 * @return {String} 处理后字符串 * @example * $.str.trim(' somestring... '); */ trim: function(str) { str += ''; var str = str.replace(/^\s+/, ''), ws = /\s/, end = str.length; while (ws.test(str.charAt(--end))); return str.slice(0, end + 1); }, /** * [uin2hex 将uin转换成加盐需要的那种字符串] * @param {[type]} str [description] * @return {[type]} [description] */ uin2hex: function(str) { var maxLength = 16; str = parseInt(str); var hex = str.toString(16); var len = hex.length; for (var i = len; i < maxLength; i++) { hex = '0' + hex; } var arr = []; for (var j = 0; j < maxLength; j += 2) { arr.push("\\x" + hex.substr(j, 2)) } var result = arr.join(""); eval('result="' + result + '"'); return result; }, /** * [bin2String 将后台check的uin序列还原] * @param {[type]} str [description] * @return {[type]} [description] */ bin2String: function(a) { var arr = []; for (var i = 0, len = a.length; i < len; i++) { var temp = a.charCodeAt(i).toString(16); if (temp.length == 1) { temp = "0" + temp; } arr.push(temp); } arr = '0x' + arr.join(''); arr = parseInt(arr, 16); return arr; }, /** * [utf8ToUincode utf-8编码转unicode字符] * @param {[type]} s [description] * @return {[type]} [description] */ utf8ToUincode: function(s) { var result = ""; try { var length = s.length; var arr = []; for (i = 0; i < length; i += 2) { arr.push("%" + s.substr(i, 2)); } result = decodeURIComponent(arr.join("")); result = $.str.decodeHtml(result); } catch (e) { result = ""; } return result; }, json2str: function(obj) { var result = ""; if (typeof JSON != "undefined") { result = JSON.stringify(obj); } else { var arr = []; for (var i in obj) { arr.push("'" + i + "':" + "'" + obj[i] + "'"); } result = '{' + arr.join(',') + '}'; } return result; }, //可能会溢出 time33: function(str) { var hash = 0; for (var i = 0, length = str.length; i < length; i++) { hash = hash * 33 + str.charCodeAt(i); } return hash % 4294967296 }, //建议使用这个 hash33: function(str) { var hash = 0; for (var i = 0, length = str.length; i < length; ++i) { hash += (hash << 5) + str.charCodeAt(i); } return hash & 0x7fffffff; } }; })(); /** * @description 计算节点的样式,大小,位置等 * @author avenwu * @date 2011.11.30 * @class */ $.css = function() { return { /** * @description 显示某个元素 * * @param {Object} element dom元素 * @example * $.css.show(dom); */ show: function(element) { if (typeof element == "string") { element = $(element); } element.style.display = "block"; }, /** * @description 隐藏某个元素 * * @param {Object} element dom元素 * @example * $.css.hide(dom); */ hide: function(element) { if (typeof element == "string") { element = $(element); } element.style.display = "none"; }, getElementViewTop: function(elementId) { var element = $(elementId); var actualTop = element.offsetTop; var current = element.offsetParent; while (current !== null) { actualTop += current.offsetTop; current = current.offsetParent; } if (document.compatMode == "BackCompat") { var elementScrollTop = document.body.scrollTop; } else { var elementScrollTop = document.documentElement.scrollTop; } return actualTop - elementScrollTop; } } }(); /** * [check 检查相关的] * @return {[type]} [description] */ $.check = { //是否为https isHttps: function() { return document.location.protocol == "https:"; }, isSsl: function() { var host = document.location.host; return /^ssl./i.test(host); }, //是否为pad isIpad: function() { var u = navigator.userAgent.toLowerCase(); return /ipad/i.test(u); }, //检查QQ isQQ: function(n) { return /^[1-9]{1}\d{4,9}$/.test(n); }, //非法qq isNullQQ: function(n) { return /^\d{1,4}$/.test(n); }, //检查微博短昵称 isNick: function(n) { return /^[a-zA-Z]{1}([a-zA-Z0-9]|[-_]){0,19}$/.test(n); }, //检查微博中文帐号,1-8位 isName: function(n) { if (n == "<请输入帐号>") return false; return /[\u4E00-\u9FA5]{1,8}/.test(n); }, //检查手机号码(微博支持所有手机号码) //isPhone:function(n){return /^(?:86|886|)1(?:(?:3\d{1})|44|(?:5[012789356]{1})|(?:8[065879]{1}))\d{8}$/.test(n);}, isPhone: function(n) { return /^(?:86|886|)1\d{10}\s*$/.test(n); }, //检查海外手机帐号(香港,台湾和澳门),微博专用 isSeaPhone: function(n) { return /^(00)?(?:852|853|886(0)?\d{1})\d{8}$/.test(n); }, //检查邮箱 isMail: function(n) { return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(n); }, //检测合法密码(非空长度不超过16位) isPassword: function(p) { return p && p.length >= 16; }, //国外的手机号码,00开头,至少10位 isForeignPhone: function(n) { return /^00\d{7,}/.test(n) }, needVip: function(appid) { var blankAppid = ["21001601", "21000110", "21000121", "46000101", "716027609", "716027610", "549000912", "717016513"]; var flag = true; for (var i = 0, length = blankAppid.length; i < length; i++) { if (blankAppid[i] == appid) { flag = false; break; } } return flag; }, isPaipai: function() { return /paipai.com$/.test(window.location.hostname); }, //拍拍多客服账号, none@518810189, 用户名+@+一串数字 isPaipaiDuokefu: function(n) { return /^.+@.+$/.test(n); }, /** * [is_weibo_appid 区分微博帐号的appid]558032501笔记使用微博帐号 * @param {[type]} appid [description] * @return {Boolean} [description] */ is_weibo_appid: function(appid) { if (appid == 46000101 || appid == 607000101 || appid == 558032501 || appid == 682023901) { return true; } return false; } }; /** * [report description] * @return {[type]} [description] */ $.report = { /** * [monitor description] * @param {String} id [monitor上报id] * @param {Number} probability [上报概率] */ monitor: function(id, probability) { if (Math.random() > (probability || 1)) return; var url = location.protocol + '//ui.ptlogin2.qq.com/cgi-bin/report?id=' + id; $.http.preload(url); }, /** * [nlog nlog日志上报] * @param {String} msg [description] * @param {Number|String} mid id1-id2-id3... * @param {String} uin */ nlog: function(msg, mid, uin) { var reportUrl = "//ui.ptlogin2.qq.com/cgi-bin/report?"; var e_info = encodeURIComponent(msg + '|_|' + window.location.href + '|_|' + window.navigator.userAgent); mid = mid ? mid : 0; if (uin) reportUrl += 'u=' + uin + '&'; reportUrl += ('id=' + mid + '&msg=' + e_info + '&v=' + Math.random()); $.http.preload(reportUrl); }, log: function(msg) { // 这是一个不存在的域名,我只是为了在fiddler上打log $.http.preload('http://console.log?msg=' + encodeURIComponent(typeof msg == 'string' ? msg : JSON.stringify(msg))); } }; /** * [检测浏览器类型, 以及打开APP的方式] * @return [browser, openStyle] */ $.detectBrowser = function() { if(window.MzJavascriptInterface && typeof window.MzJavascriptInterface.isMzBrowser === 'function' && window.MzJavascriptInterface.isMzBrowser()){ return ["meizu", "location"]; } var ua=window.navigator.userAgent; var matched; if (/android/i.test(ua)) { if (matched = ua.match(/OppoBrowser|SamsungBrowser|MQQBrowser|baidubrowser|baiduboxapp|QihooBrowser|UCBrowser|2345Browser|Firefox|MicroMessenger/i)) { matched[1] = "location"; } else if (matched = ua.match(/SogouMobileBrowser|LieBaoFast|XiaoMi\/MiuiBrowser|opr|vivo/i)) { matched[1] = "iframe"; } else if (matched = ua.match(/Chrome/i)) { var version = ua.match(/chrome\/([\d]+)/i); if (version) version = version[1]; if (version != 40) matched[1] = "open"; } } else if (/iphone|ipod/ig.test(ua)) { if (matched = ua.match(/MQQBrowser|UCBrowser|SogouMobileBrowser|baidubrowser|baiduboxapp|QihooBrowser|Opera|2345Browser|LieBao/i)){ }else if (matched = ua.match(/CriOS|Chrome/i)) (matched[0].toLowerCase() == "crios") && (matched[0] = "Chrome"); } return matched || ["others", ""]; }; //调用微信api通用接口 $.invokeWXAPI = function(name, param, callback) { var api = function() { WeixinJSBridge.invoke(name, param, callback); }; if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") { api(); } else { if (document.addEventListener) { document.addEventListener("WeixinJSBridgeReady", api, false); } else if (document.attachEvent) { document.attachEvent("WeixinJSBridgeReady", api); document.attachEvent("onWeixinJSBridgeReady", api); } } }; // //接入nohost // (function() { // var _sname = 'nohost_guid'; // var _src = '/nohost_htdocs/js/SwitchHost.js'; // if ($.cookie.get(_sname) != '') { // $.http.loadScript(_src, function() { // var init = window['SwitchHost'] && window['SwitchHost'].init; // init && init(); // }); // } // })(); // setTimeout(function() { // var url = "http://isdspeed.qq.com/cgi-bin/r.cgi?"; // if ($.check.isHttps()) { // url = "https://huatuospeed.weiyun.com/cgi-bin/r.cgi?"; // } // url += "flag1=7808&flag2=1&flag3=9"; // var percent = 0.01; // if (Math.random() < (percent || 1)) { // if (typeof window.postMessage != "undefined") // url += ("&2=" + 2000); // else // url += ("&2=" + 1000); // url += "&v=" + Math.random(); // $.http.preload(url); // } // }, 500); if(typeof process!=='undefined' && process.env && process.env.UNITTEST==1){ module.exports = $ } /** * [Encryption rsa算法封装] */ $ = window.$ || {}; $pt = window.$pt || {}; $.RSA = $pt.RSA =function(){ // Depends on jsbn.js and rng.js // Version 1.1: support utf-8 encoding in pkcs1pad2 // convert a (hex) string to a bignum object function parseBigInt(str,r) { return new BigInteger(str,r); } function linebrk(s,n) { var ret = ""; var i = 0; while(i + n < s.length) { ret += s.substring(i,i+n) + "\n"; i += n; } return ret + s.substring(i,s.length); } function byte2Hex(b) { if(b < 0x10) return "0" + b.toString(16); else return b.toString(16); } // PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint function pkcs1pad2(s,n) { if(n < s.length + 11) { // TODO: fix for utf-8 uv_alert("Message too long for RSA"); return null; } var ba = new Array(); var i = s.length - 1; while(i >= 0 && n > 0) { var c = s.charCodeAt(i--); ba[--n] = c; /* if(c < 128) { // encode using utf-8 ba[--n] = c; } else if((c > 127) && (c < 2048)) { ba[--n] = (c & 63) | 128; ba[--n] = (c >> 6) | 192; } else { ba[--n] = (c & 63) | 128; ba[--n] = ((c >> 6) & 63) | 128; ba[--n] = (c >> 12) | 224; }*/ } ba[--n] = 0; var rng = new SecureRandom(); var x = new Array(); while(n > 2) { // random non-zero pad x[0] = 0; while(x[0] == 0) rng.nextBytes(x); ba[--n] = x[0]; } ba[--n] = 2; ba[--n] = 0; return new BigInteger(ba); } // "empty" RSA key constructor function RSAKey() { this.n = null; this.e = 0; this.d = null; this.p = null; this.q = null; this.dmp1 = null; this.dmq1 = null; this.coeff = null; } // Set the public key fields N and e from hex strings function RSASetPublic(N,E) { if(N != null && E != null && N.length > 0 && E.length > 0) { this.n = parseBigInt(N,16); this.e = parseInt(E,16); } else uv_alert("Invalid RSA public key"); } // Perform raw public operation on "x": return x^e (mod n) function RSADoPublic(x) { return x.modPowInt(this.e, this.n); } // Return the PKCS#1 RSA encryption of "text" as an even-length hex string function RSAEncrypt(text) { var m = pkcs1pad2(text,(this.n.bitLength()+7)>>3); if(m == null) return null; var c = this.doPublic(m); if(c == null) return null; var h = c.toString(16); if((h.length & 1) == 0) return h; else return "0" + h; } // Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string //function RSAEncryptB64(text) { // var h = this.encrypt(text); // if(h) return hex2b64(h); else return null; //} // protected RSAKey.prototype.doPublic = RSADoPublic; // public RSAKey.prototype.setPublic = RSASetPublic; RSAKey.prototype.encrypt = RSAEncrypt; //RSAKey.prototype.encrypt_b64 = RSAEncryptB64; //==================================================jsbn.js======================================================================// // Copyright (c) 2005 Tom Wu // All Rights Reserved. // See "LICENSE" for details. // Basic JavaScript BN library - subset useful for RSA encryption. // Bits per digit var dbits; // JavaScript engine analysis var canary = 0xdeadbeefcafe; var j_lm = ((canary&0xffffff)==0xefcafe); // (public) Constructor function BigInteger(a,b,c) { if(a != null) if("number" == typeof a) this.fromNumber(a,b,c); else if(b == null && "string" != typeof a) this.fromString(a,256); else this.fromString(a,b); } // return new, unset BigInteger function nbi() { return new BigInteger(null); } // am: Compute w_j += (x*this_i), propagate carries, // c is initial carry, returns final carry. // c < 3*dvalue, x < 2*dvalue, this_i < dvalue // We need to select the fastest one that works in this environment. // am1: use a single mult and divide to get the high bits, // max digit bits should be 26 because // max internal value = 2*dvalue^2-2*dvalue (< 2^53) function am1(i,x,w,j,c,n) { while(--n >= 0) { var v = x*this[i++]+w[j]+c; c = Math.floor(v/0x4000000); w[j++] = v&0x3ffffff; } return c; } // am2 avoids a big mult-and-extract completely. // Max digit bits should be <= 30 because we do bitwise ops // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31) function am2(i,x,w,j,c,n) { var xl = x&0x7fff, xh = x>>15; while(--n >= 0) { var l = this[i]&0x7fff; var h = this[i++]>>15; var m = xh*l+h*xl; l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff); c = (l>>>30)+(m>>>15)+xh*h+(c>>>30); w[j++] = l&0x3fffffff; } return c; } // Alternately, set max digit bits to 28 since some // browsers slow down when dealing with 32-bit numbers. function am3(i,x,w,j,c,n) { var xl = x&0x3fff, xh = x>>14; while(--n >= 0) { var l = this[i]&0x3fff; var h = this[i++]>>14; var m = xh*l+h*xl; l = xl*l+((m&0x3fff)<<14)+w[j]+c; c = (l>>28)+(m>>14)+xh*h; w[j++] = l&0xfffffff; } return c; } if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) { BigInteger.prototype.am = am2; dbits = 30; } else if(j_lm && (navigator.appName != "Netscape")) { BigInteger.prototype.am = am1; dbits = 26; } else { // Mozilla/Netscape seems to prefer am3 BigInteger.prototype.am = am3; dbits = 28; } BigInteger.prototype.DB = dbits; BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i]; r.t = this.t; r.s = this.s; } // (protected) set from integer value x, -DV <= x < DV function bnpFromInt(x) { this.t = 1; this.s = (x<0)?-1:0; if(x > 0) this[0] = x; else if(x < -1) this[0] = x+DV; else this.t = 0; } // return bigint initialized to value function nbv(i) { var r = nbi(); r.fromInt(i); return r; } // (protected) set from string and radix function bnpFromString(s,b) { var k; if(b == 16) k = 4; else if(b == 8) k = 3; else if(b == 256) k = 8; // byte array else if(b == 2) k = 1; else if(b == 32) k = 5; else if(b == 4) k = 2; else { this.fromRadix(s,b); return; } this.t = 0; this.s = 0; var i = s.length, mi = false, sh = 0; while(--i >= 0) { var x = (k==8)?s[i]&0xff:intAt(s,i); if(x < 0) { if(s.charAt(i) == "-") mi = true; continue; } mi = false; if(sh == 0) this[this.t++] = x; else if(sh+k > this.DB) { this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh)); } else this[this.t-1] |= x<= this.DB) sh -= this.DB; } if(k == 8 && (s[0]&0x80) != 0) { this.s = -1; if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t; } // (public) return string representation in given radix function bnToString(b) { if(this.s < 0) return "-"+this.negate().toString(b); var k; if(b == 16) k = 4; else if(b == 8) k = 3; else if(b == 2) k = 1; else if(b == 32) k = 5; else if(b == 4) k = 2; else return this.toRadix(b); var km = (1< 0) { if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); } while(i >= 0) { if(p < k) { d = (this[i]&((1<>(p+=this.DB-k); } else { d = (this[i]>>(p-=k))&km; if(p <= 0) { p += this.DB; --i; } } if(d > 0) m = true; if(m) r += int2char(d); } } return m?r:"0"; } // (public) -this function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; } // (public) |this| function bnAbs() { return (this.s<0)?this.negate():this; } // (public) return + if this > a, - if this < a, 0 if equal function bnCompareTo(a) { var r = this.s-a.s; if(r != 0) return r; var i = this.t; r = i-a.t; if(r != 0) return r; while(--i >= 0) if((r=this[i]-a[i]) != 0) return r; return 0; } // returns bit length of the integer x function nbits(x) { var r = 1, t; if((t=x>>>16) != 0) { x = t; r += 16; } if((t=x>>8) != 0) { x = t; r += 8; } if((t=x>>4) != 0) { x = t; r += 4; } if((t=x>>2) != 0) { x = t; r += 2; } if((t=x>>1) != 0) { x = t; r += 1; } return r; } // (public) return the number of bits in "this" function bnBitLength() { if(this.t <= 0) return 0; return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM)); } // (protected) r = this << n*DB function bnpDLShiftTo(n,r) { var i; for(i = this.t-1; i >= 0; --i) r[i+n] = this[i]; for(i = n-1; i >= 0; --i) r[i] = 0; r.t = this.t+n; r.s = this.s; } // (protected) r = this >> n*DB function bnpDRShiftTo(n,r) { for(var i = n; i < this.t; ++i) r[i-n] = this[i]; r.t = Math.max(this.t-n,0); r.s = this.s; } // (protected) r = this << n function bnpLShiftTo(n,r) { var bs = n%this.DB; var cbs = this.DB-bs; var bm = (1<= 0; --i) { r[i+ds+1] = (this[i]>>cbs)|c; c = (this[i]&bm)<= 0; --i) r[i] = 0; r[ds] = c; r.t = this.t+ds+1; r.s = this.s; r.clamp(); } // (protected) r = this >> n function bnpRShiftTo(n,r) { r.s = this.s; var ds = Math.floor(n/this.DB); if(ds >= this.t) { r.t = 0; return; } var bs = n%this.DB; var cbs = this.DB-bs; var bm = (1<>bs; for(var i = ds+1; i < this.t; ++i) { r[i-ds-1] |= (this[i]&bm)<>bs; } if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB; } if(a.t < this.t) { c -= a.s; while(i < this.t) { c += this[i]; r[i++] = c&this.DM; c >>= this.DB; } c += this.s; } else { c += this.s; while(i < a.t) { c -= a[i]; r[i++] = c&this.DM; c >>= this.DB; } c -= a.s; } r.s = (c<0)?-1:0; if(c < -1) r[i++] = this.DV+c; else if(c > 0) r[i++] = c; r.t = i; r.clamp(); } // (protected) r = this * a, r != this,a (HAC 14.12) // "this" should be the larger one if appropriate. function bnpMultiplyTo(a,r) { var x = this.abs(), y = a.abs(); var i = x.t; r.t = i+y.t; while(--i >= 0) r[i] = 0; for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t); r.s = 0; r.clamp(); if(this.s != a.s) BigInteger.ZERO.subTo(r,r); } // (protected) r = this^2, r != this (HAC 14.16) function bnpSquareTo(r) { var x = this.abs(); var i = r.t = 2*x.t; while(--i >= 0) r[i] = 0; for(i = 0; i < x.t-1; ++i) { var c = x.am(i,x[i],r,2*i,0,1); if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) { r[i+x.t] -= x.DV; r[i+x.t+1] = 1; } } if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1); r.s = 0; r.clamp(); } // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20) // r != q, this != m. q or r may be null. function bnpDivRemTo(m,q,r) { var pm = m.abs(); if(pm.t <= 0) return; var pt = this.abs(); if(pt.t < pm.t) { if(q != null) q.fromInt(0); if(r != null) this.copyTo(r); return; } if(r == null) r = nbi(); var y = nbi(), ts = this.s, ms = m.s; var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); } else { pm.copyTo(y); pt.copyTo(r); } var ys = y.t; var y0 = y[ys-1]; if(y0 == 0) return; var yt = y0*(1<1)?y[ys-2]>>this.F2:0); var d1 = this.FV/yt, d2 = (1<= 0) { r[r.t++] = 1; r.subTo(t,r); } BigInteger.ONE.dlShiftTo(ys,t); t.subTo(y,y); // "negative" y so we can replace sub with am later while(y.t < ys) y[y.t++] = 0; while(--j >= 0) { // Estimate quotient digit var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2); if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out y.dlShiftTo(j,t); r.subTo(t,r); while(r[i] < --qd) r.subTo(t,r); } } if(q != null) { r.drShiftTo(ys,q); if(ts != ms) BigInteger.ZERO.subTo(q,q); } r.t = ys; r.clamp(); if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder if(ts < 0) BigInteger.ZERO.subTo(r,r); } // (public) this mod a function bnMod(a) { var r = nbi(); this.abs().divRemTo(a,null,r); if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r); return r; } // Modular reduction using "classic" algorithm function Classic(m) { this.m = m; } function cConvert(x) { if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m); else return x; } function cRevert(x) { return x; } function cReduce(x) { x.divRemTo(this.m,null,x); } function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); } Classic.prototype.convert = cConvert; Classic.prototype.revert = cRevert; Classic.prototype.reduce = cReduce; Classic.prototype.mulTo = cMulTo; Classic.prototype.sqrTo = cSqrTo; // (protected) return "-1/this % 2^DB"; useful for Mont. reduction // justification: // xy == 1 (mod m) // xy = 1+km // xy(2-xy) = (1+km)(1-km) // x[y(2-xy)] = 1-k^2m^2 // x[y(2-xy)] == 1 (mod m^2) // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2 // should reduce x and y(2-xy) by m^2 at each step to keep size bounded. // JS multiply "overflows" differently from C/C++, so care is needed here. function bnpInvDigit() { if(this.t < 1) return 0; var x = this[0]; if((x&1) == 0) return 0; var y = x&3; // y == 1/x mod 2^2 y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4 y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8 y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16 // last step - calculate inverse mod DV directly; // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits // we really want the negative inverse, and -DV < y < DV return (y>0)?this.DV-y:-y; } // Montgomery reduction function Montgomery(m) { this.m = m; this.mp = m.invDigit(); this.mpl = this.mp&0x7fff; this.mph = this.mp>>15; this.um = (1<<(m.DB-15))-1; this.mt2 = 2*m.t; } // xR mod m function montConvert(x) { var r = nbi(); x.abs().dlShiftTo(this.m.t,r); r.divRemTo(this.m,null,r); if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r); return r; } // x/R mod m function montRevert(x) { var r = nbi(); x.copyTo(r); this.reduce(r); return r; } // x = x/R mod m (HAC 14.32) function montReduce(x) { while(x.t <= this.mt2) // pad x so am has enough room later x[x.t++] = 0; for(var i = 0; i < this.m.t; ++i) { // faster way of calculating u0 = x[i]*mp mod DV var j = x[i]&0x7fff; var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM; // use am to combine the multiply-shift-add into one call j = i+this.m.t; x[j] += this.m.am(0,u0,x,i,0,this.m.t); // propagate carry while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; } } x.clamp(); x.drShiftTo(this.m.t,x); if(x.compareTo(this.m) >= 0) x.subTo(this.m,x); } // r = "x^2/R mod m"; x != r function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); } // r = "xy/R mod m"; x,y != r function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); } Montgomery.prototype.convert = montConvert; Montgomery.prototype.revert = montRevert; Montgomery.prototype.reduce = montReduce; Montgomery.prototype.mulTo = montMulTo; Montgomery.prototype.sqrTo = montSqrTo; // (protected) true iff this is even function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; } // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79) function bnpExp(e,z) { if(e > 0xffffffff || e < 1) return BigInteger.ONE; var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1; g.copyTo(r); while(--i >= 0) { z.sqrTo(r,r2); if((e&(1< 0) z.mulTo(r2,g,r); else { var t = r; r = r2; r2 = t; } } return z.revert(r); } // (public) this^e % m, 0 <= e < 2^32 function bnModPowInt(e,m) { var z; if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m); return this.exp(e,z); } // protected BigInteger.prototype.copyTo = bnpCopyTo; BigInteger.prototype.fromInt = bnpFromInt; BigInteger.prototype.fromString = bnpFromString; BigInteger.prototype.clamp = bnpClamp; BigInteger.prototype.dlShiftTo = bnpDLShiftTo; BigInteger.prototype.drShiftTo = bnpDRShiftTo; BigInteger.prototype.lShiftTo = bnpLShiftTo; BigInteger.prototype.rShiftTo = bnpRShiftTo; BigInteger.prototype.subTo = bnpSubTo; BigInteger.prototype.multiplyTo = bnpMultiplyTo; BigInteger.prototype.squareTo = bnpSquareTo; BigInteger.prototype.divRemTo = bnpDivRemTo; BigInteger.prototype.invDigit = bnpInvDigit; BigInteger.prototype.isEven = bnpIsEven; BigInteger.prototype.exp = bnpExp; // public BigInteger.prototype.toString = bnToString; BigInteger.prototype.negate = bnNegate; BigInteger.prototype.abs = bnAbs; BigInteger.prototype.compareTo = bnCompareTo; BigInteger.prototype.bitLength = bnBitLength; BigInteger.prototype.mod = bnMod; BigInteger.prototype.modPowInt = bnModPowInt; // "constants" BigInteger.ZERO = nbv(0); BigInteger.ONE = nbv(1); //====================================================rng.js===================================================================// // Random number generator - requires a PRNG backend, e.g. prng4.js // For best results, put code like // // in your main HTML document. var rng_state; var rng_pool; var rng_pptr; // Mix in a 32-bit integer into the pool function rng_seed_int(x) { rng_pool[rng_pptr++] ^= x & 255; rng_pool[rng_pptr++] ^= (x >> 8) & 255; rng_pool[rng_pptr++] ^= (x >> 16) & 255; rng_pool[rng_pptr++] ^= (x >> 24) & 255; if(rng_pptr >= rng_psize) rng_pptr -= rng_psize; } // Mix in the current time (w/milliseconds) into the pool function rng_seed_time() { rng_seed_int(new Date().getTime()); } // Initialize the pool with junk if needed. if(rng_pool == null) { rng_pool = new Array(); rng_pptr = 0; var t; if(navigator.appName == "Netscape" && navigator.appVersion < "5" && window.crypto && window.crypto.random) { // Extract entropy (256 bits) from NS4 RNG if available var z = window.crypto.random(32); for(t = 0; t < z.length; ++t) rng_pool[rng_pptr++] = z.charCodeAt(t) & 255; } while(rng_pptr < rng_psize) { // extract some randomness from Math.random() t = Math.floor(65536 * Math.random()); rng_pool[rng_pptr++] = t >>> 8; rng_pool[rng_pptr++] = t & 255; } rng_pptr = 0; rng_seed_time(); //rng_seed_int(window.screenX); //rng_seed_int(window.screenY); } function rng_get_byte() { if(rng_state == null) { rng_seed_time(); rng_state = prng_newstate(); rng_state.init(rng_pool); for(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) rng_pool[rng_pptr] = 0; rng_pptr = 0; //rng_pool = null; } // TODO: allow reseeding after first request return rng_state.next(); } function rng_get_bytes(ba) { var i; for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte(); } function SecureRandom() {} SecureRandom.prototype.nextBytes = rng_get_bytes; //===============================================prng4==========================================================================// // prng4.js - uses Arcfour as a PRNG function Arcfour() { this.i = 0; this.j = 0; this.S = new Array(); } // Initialize arcfour context from key, an array of ints, each from [0..255] function ARC4init(key) { var i, j, t; for(i = 0; i < 256; ++i) this.S[i] = i; j = 0; for(i = 0; i < 256; ++i) { j = (j + this.S[i] + key[i % key.length]) & 255; t = this.S[i]; this.S[i] = this.S[j]; this.S[j] = t; } this.i = 0; this.j = 0; } function ARC4next() { var t; this.i = (this.i + 1) & 255; this.j = (this.j + this.S[this.i]) & 255; t = this.S[this.i]; this.S[this.i] = this.S[this.j]; this.S[this.j] = t; return this.S[(t + this.S[this.i]) & 255]; } Arcfour.prototype.init = ARC4init; Arcfour.prototype.next = ARC4next; // Plug in your RNG constructor here function prng_newstate() { return new Arcfour(); } // Pool size must be a multiple of 4 and greater than 32. // An array of bytes the size of the pool will be passed to init() var rng_psize = 256; //rsa加密 function rsa_encrypt(rawValue,key,mod){ //公钥 key = "e9a815ab9d6e86abbf33a4ac64e9196d5be44a09bd0ed6ae052914e1a865ac8331fed863de8ea697e9a7f63329e5e23cda09c72570f46775b7e39ea9670086f847d3c9c51963b131409b1e04265d9747419c635404ca651bbcbc87f99b8008f7f5824653e3658be4ba73e4480156b390bb73bc1f8b33578e7a4e12440e9396f2552c1aff1c92e797ebacdc37c109ab7bce2367a19c56a033ee04534723cc2558cb27368f5b9d32c04d12dbd86bbd68b1d99b7c349a8453ea75d1b2e94491ab30acf6c46a36a75b721b312bedf4e7aad21e54e9bcbcf8144c79b6e3c05eb4a1547750d224c0085d80e6da3907c3d945051c13c7c1dcefd6520ee8379c4f5231ed"; mod="10001"; var _RSA = new RSAKey();//生成rsa加密对象 _RSA.setPublic(key, mod);//设置公钥和mod,PublicKey是1(2)中打印的hex值 return _RSA.encrypt(rawValue); }; return { rsa_encrypt:rsa_encrypt } }(); (function(global) { /* 此加密算法是一个16次的迭代过程,并且是反馈的,每一个加密单元是8字节,输出也是8字节,密钥是16字节 我们以prePlain表示前一个明文块,plain表示当前明文块,crypt表示当前明文块加密得到的密文块,preCrypt表示前一个密文块 f表示加密算法,d表示解密算法 那么从plain得到crypt的过程是: crypt = f(plain ^ preCrypt) ^ prePlain 所以,从crypt得到plain的过程自然是 plain = d(crypt ^ prePlain) ^ preCrypt 此外,算法有它的填充机制,其会在明文前和明文后分别填充一定的字节数,以保证明文长度是8字节的倍数 填充的字节数与原始明文长度有关,填充的方法是: ------- 消息填充算法 ----------- a = (明文长度 + 10) mod 8 if(a 不等于 0) a = 8 - a; b = 随机数 & 0xF8 | a; 这个的作用是把a的值保存了下来, a的值小于8 plain[0] = b; 然后把b做为明文的第0个字节,这样第0个字节就保存了a的信息,这个信息在解密时就要用来找到真正明文的起始位置 plain[1..a+2] = 随机数 & 0xFF; 这里用随机数填充明文的第1到第a+2个字节 plain[a+3..a+3+明文长度-1] = 明文; 从a+3字节开始才是真正的明文 plain[a+3+明文长度, 最后] = 0; 在最后,填充0,填充到总长度为8的整数为止。到此为止,结束了,这就是最后得到的要加密的明文内容 ------- 消息填充算法 ------------ @author 马若劼 @author notXX @author 唐浩宸 */ var __key = '', __pos = 0, __plain = [], __prePlain = [], __cryptPos = 0, // 当前密文块位置 __preCryptPos = 0, // 上一个密文块位置 __out = [], // 保存加密/解密的输出 __cipher = [], // 输出的密文 /*用于加密时,表示当前是否是第一个8字节块,因为加密算法是反馈的, 但是最开始的8个字节没有反馈可用,所有需要标明这种情况*/ __header = true; function __rand() { return Math.round(Math.random()*0xffffffff); } /** * 将数据转化为无符号整形 */ function __getUInt(data, offset, len) { if (!len || len > 4) len = 4; var ret = 0; for (var i=offset; i>> 0; // 无符号化 } /** 把整形数据填充到数组里,要注意端序 */ function __intToBytes(data, offset, value) { data[offset+3] = (value >> 0) & 0xff; data[offset+2] = (value >> 8) & 0xff; data[offset+1] = (value >> 16) & 0xff; data[offset+0] = (value >> 24) & 0xff; } function __bytesInStr(data) { if (!data) return ""; var outInHex = ""; for (var i=0; i 0x0 && code <= 0x7f){ //单字节 //UTF-16 0000 - 007F //UTF-8 0xxxxxxx ret.push(s.charAt(i)); }else if(code >= 0x80 && code <= 0x7ff){ //双字节 //UTF-16 0080 - 07FF //UTF-8 110xxxxx 10xxxxxx ret.push( //110xxxxx String.fromCharCode(0xc0 | ((code >> 6) & 0x1f)), //10xxxxxx String.fromCharCode(0x80 | (code & 0x3f)) ); }else if(code >= 0x800 && code <= 0xffff){ //三字节 //UTF-16 0800 - FFFF //UTF-8 1110xxxx 10xxxxxx 10xxxxxx ret.push( //1110xxxx String.fromCharCode(0xe0 | ((code >> 12) & 0xf)), //10xxxxxx String.fromCharCode(0x80 | ((code >> 6) & 0x3f)), //10xxxxxx String.fromCharCode(0x80 | (code & 0x3f)) ); } } return ret.join(''); } function __encrypt(data) { __plain = new Array(8); __prePlain = new Array(8); __cryptPos = __preCryptPos = 0; __header = true; __pos = 0; var len = data.length; var padding = 0; __pos = (len + 0x0A) % 8; if (__pos != 0) __pos = 8 - __pos; __out = new Array(len + __pos + 10); __plain[0] = ((__rand() & 0xF8) | __pos ) & 0xFF; for (var i=1; i<=__pos; i++) __plain[i] = __rand() & 0xFF; __pos++; for (var i=0; i<8; i++) __prePlain[i] = 0; padding = 1; while (padding <= 2) { if (__pos < 8) { __plain[__pos++] = __rand() & 0xFF; padding++; } if (__pos == 8) __encrypt8bytes(); } var i = 0; while (len > 0) { if (__pos < 8) { __plain[__pos++] = data[i++]; len--; } if (__pos == 8) __encrypt8bytes(); } padding = 1; while (padding <= 7) { if (__pos < 8) { __plain[__pos++] = 0; padding++; } if (__pos == 8) __encrypt8bytes(); } return __out; } function __decrypt(data) { var count = 0; var m = new Array(8); var len = data.length; __cipher = data; if (len % 8 != 0 || len < 16) return null; /* 第一个8字节,加密的时候因为prePlain是全0,所以可以直接解密,得到消息的头部, 关键是可以得到真正明文开始的位置 */ __prePlain = __decipher(data); __pos = __prePlain[0] & 0x7; count = len - __pos - 10; // 真正的明文长度 if (count < 0) return null; // 临时的preCrypt, 与加密时对应,全0的prePlain 对应 全0的preCrypt for (var i=0; i>> 0; while (loop-- > 0) { sum += delta; sum = (sum & 0xFFFFFFFF) >>> 0; y += ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b); y = (y & 0xFFFFFFFF) >>> 0; z += ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d); z = (z & 0xFFFFFFFF) >>> 0; } var bytes = new Array(8); __intToBytes(bytes, 0, y); __intToBytes(bytes, 4, z); return bytes; } function __decipher(data) { var loop = 16; var y = __getUInt(data, 0, 4); var z = __getUInt(data, 4, 4); var a = __getUInt(__key, 0, 4); var b = __getUInt(__key, 4, 4); var c = __getUInt(__key, 8, 4); var d = __getUInt(__key, 12, 4); var sum = 0xE3779B90 >>> 0; var delta = 0x9E3779B9 >>> 0; while (loop-- > 0) { z -= ((y << 4) + c) ^ (y + sum) ^ ((y >>> 5) + d); z = (z & 0xFFFFFFFF) >>> 0; y -= ((z << 4) + a) ^ (z + sum) ^ ((z >>> 5) + b); y = (y & 0xFFFFFFFF) >>> 0; sum -= delta; sum = (sum & 0xFFFFFFFF) >>> 0; } var bytes = new Array(8); __intToBytes(bytes, 0, y); __intToBytes(bytes, 4, z); return bytes; } function __decrypt8Bytes() { var len = __cipher.length; for (var i=0; i<8; i++) { __prePlain[i] ^= __cipher[__cryptPos + i]; } __prePlain = __decipher(__prePlain); __cryptPos += 8; __pos = 0; return true; } /** * 把输入字符串转换为javascript array */ function __dataFromStr(str, isASCII) { var data = []; if (isASCII) { for (var i=0; i> 16, (b10 >> 8) & 0xff, b10 & 0xff)); } switch (pads) { case 1: b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12) | (getbyte64(s,i+2) << 6) x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 0xff)); break; case 2: b10 = (getbyte64(s,i) << 18) | (getbyte64(s,i+1) << 12); x.push(String.fromCharCode(b10 >> 16)); break; } return x.join(''); } */ base64.getbyte = function(s,i) { var x = s.charCodeAt(i); if (x > 255) { throw "INVALID_CHARACTER_ERR: DOM Exception 5"; } return x; } base64.encode = function(s) { if (arguments.length != 1) { throw "SyntaxError: Not enough arguments"; } var padchar = base64.PADCHAR; var alpha = base64.ALPHA; var getbyte = base64.getbyte; var i, b10; var x = []; // convert to string s = "" + s; var imax = s.length - s.length % 3; if (s.length == 0) { return s; } for (i = 0; i < imax; i += 3) { b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8) | getbyte(s,i+2); x.push(alpha.charAt(b10 >> 18)); x.push(alpha.charAt((b10 >> 12) & 0x3F)); x.push(alpha.charAt((b10 >> 6) & 0x3f)); x.push(alpha.charAt(b10 & 0x3f)); } switch (s.length - imax) { case 1: b10 = getbyte(s,i) << 16; x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) + padchar + padchar); break; case 2: b10 = (getbyte(s,i) << 16) | (getbyte(s,i+1) << 8); x.push(alpha.charAt(b10 >> 18) + alpha.charAt((b10 >> 12) & 0x3F) + alpha.charAt((b10 >> 6) & 0x3f) + padchar); break; } return x.join(''); } if (!window.btoa) window.btoa = base64.encode; //if (!window.atob) window.atob = base64.decode; })(window); $ = window.$ || {}; $pt = window.$pt || {}; // login_div 被嵌在其它页面中,有可能$被覆盖 $.Encryption = $pt.Encryption=function(){ /******************************************** * * 加密及算法相关,算法这个地方,很多函数可能没用,看微博的测试结果再处理。 * *******************************************/ var hexcase = 1; var b64pad = ""; var chrsz = 8; var mode = 32; function md5(s){ return hex_md5(s); } function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz)); } function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz)); } function hex_hmac_md5(key, data){ return binl2hex(core_hmac_md5(key, data)); } function b64_hmac_md5(key, data){ return binl2b64(core_hmac_md5(key, data)); } function str_hmac_md5(key, data){ return binl2str(core_hmac_md5(key, data)); } //function md5_vm_test()//此方法只是测试是否运行正常 //{ // return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; //} function core_md5(x, len){ x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a = 1732584193; var b = - 271733879; var c = - 1732584194; var d = 271733878; for (var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = md5_ff(a, b, c, d, x[i + 0], 7, - 680876936); d = md5_ff(d, a, b, c, x[i + 1], 12, - 389564586); c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); b = md5_ff(b, c, d, a, x[i + 3], 22, - 1044525330); a = md5_ff(a, b, c, d, x[i + 4], 7, - 176418897); d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); c = md5_ff(c, d, a, b, x[i + 6], 17, - 1473231341); b = md5_ff(b, c, d, a, x[i + 7], 22, - 45705983); a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); d = md5_ff(d, a, b, c, x[i + 9], 12, - 1958414417); c = md5_ff(c, d, a, b, x[i + 10], 17, - 42063); b = md5_ff(b, c, d, a, x[i + 11], 22, - 1990404162); a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); d = md5_ff(d, a, b, c, x[i + 13], 12, - 40341101); c = md5_ff(c, d, a, b, x[i + 14], 17, - 1502002290); b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); a = md5_gg(a, b, c, d, x[i + 1], 5, - 165796510); d = md5_gg(d, a, b, c, x[i + 6], 9, - 1069501632); c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); b = md5_gg(b, c, d, a, x[i + 0], 20, - 373897302); a = md5_gg(a, b, c, d, x[i + 5], 5, - 701558691); d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); c = md5_gg(c, d, a, b, x[i + 15], 14, - 660478335); b = md5_gg(b, c, d, a, x[i + 4], 20, - 405537848); a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); d = md5_gg(d, a, b, c, x[i + 14], 9, - 1019803690); c = md5_gg(c, d, a, b, x[i + 3], 14, - 187363961); b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); a = md5_gg(a, b, c, d, x[i + 13], 5, - 1444681467); d = md5_gg(d, a, b, c, x[i + 2], 9, - 51403784); c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); b = md5_gg(b, c, d, a, x[i + 12], 20, - 1926607734); a = md5_hh(a, b, c, d, x[i + 5], 4, - 378558); d = md5_hh(d, a, b, c, x[i + 8], 11, - 2022574463); c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); b = md5_hh(b, c, d, a, x[i + 14], 23, - 35309556); a = md5_hh(a, b, c, d, x[i + 1], 4, - 1530992060); d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); c = md5_hh(c, d, a, b, x[i + 7], 16, - 155497632); b = md5_hh(b, c, d, a, x[i + 10], 23, - 1094730640); a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); d = md5_hh(d, a, b, c, x[i + 0], 11, - 358537222); c = md5_hh(c, d, a, b, x[i + 3], 16, - 722521979); b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); a = md5_hh(a, b, c, d, x[i + 9], 4, - 640364487); d = md5_hh(d, a, b, c, x[i + 12], 11, - 421815835); c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); b = md5_hh(b, c, d, a, x[i + 2], 23, - 995338651); a = md5_ii(a, b, c, d, x[i + 0], 6, - 198630844); d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); c = md5_ii(c, d, a, b, x[i + 14], 15, - 1416354905); b = md5_ii(b, c, d, a, x[i + 5], 21, - 57434055); a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); d = md5_ii(d, a, b, c, x[i + 3], 10, - 1894986606); c = md5_ii(c, d, a, b, x[i + 10], 15, - 1051523); b = md5_ii(b, c, d, a, x[i + 1], 21, - 2054922799); a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); d = md5_ii(d, a, b, c, x[i + 15], 10, - 30611744); c = md5_ii(c, d, a, b, x[i + 6], 15, - 1560198380); b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); a = md5_ii(a, b, c, d, x[i + 4], 6, - 145523070); d = md5_ii(d, a, b, c, x[i + 11], 10, - 1120210379); c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); b = md5_ii(b, c, d, a, x[i + 9], 21, - 343485551); a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd); } if (mode == 16) { return Array(b, c); }else{ return Array(a, b, c, d); } } function md5_cmn(q, a, b, x, s, t){ return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); } function md5_ff(a, b, c, d, x, s, t){ return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); } function md5_gg(a, b, c, d, x, s, t){ return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); } function md5_hh(a, b, c, d, x, s, t){ return md5_cmn(b ^ c ^ d, a, b, x, s, t); } function md5_ii(a, b, c, d, x, s, t){ return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); } function core_hmac_md5(key, data){ var bkey = str2binl(key); if (bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); var ipad = Array(16), opad = Array(16); for (var i = 0; i < 16; i++){ ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = core_md5(ipad.concat(str2binl(data)), 512+data.length * chrsz); return core_md5(opad.concat(hash), 512+128); } function safe_add(x, y){ var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); } function bit_rol(num, cnt){ return (num << cnt) | (num >>> (32-cnt)); } function str2binl(str){ var bin = Array(); var mask = (1 << chrsz) - 1; for (var i = 0; i < str.length * chrsz; i += chrsz) bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << (i % 32); return bin; } function binl2str(bin){ var str = ""; var mask = (1 << chrsz) - 1; for (var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i >> 5] >>> (i % 32)) & mask); return str; } function binl2hex(binarray){ var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for (var i = 0; i < binarray.length * 4; i++){ str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8+4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF); } return str; } function binl2b64(binarray){ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var str = ""; for (var i = 0; i < binarray.length * 4; i += 3){ var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16) | (( (binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8) | ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF); for (var j = 0; j < 4; j++){ if (i * 8+j * 6 > binarray.length * 32) str += b64pad; else str += tab.charAt((triplet >> 6 * (3-j)) & 0x3F); } } return str; } function hexchar2bin(str){ var arr = []; for(var i=0;i (probability || 1)) return; try { var url = location.protocol + '//ui.ptlogin2.qq.com/cgi-bin/report?id=' + mid; var s = document.createElement("img"); s.src = url; } catch (e) {} } /** * encrypt user password with salt * @param {String} password 原始密码 * @param {String} salt check 返回的序列 * @param {String} vcode 验证码 * @param {Boolean} isMd5 传入的密码是否MD5 * @return {String} PtA1 返回的加密字符串 */ function getEncryption(password, salt, vcode, isMd5) { vcode = vcode || ""; password = password || ""; var md5Pwd = isMd5 ? password : md5(password), h1 = hexchar2bin(md5Pwd), s2 = md5(h1 + salt), hexVcode = TEA.strToBytes(vcode.toUpperCase(), true), vcodeLen = Number(hexVcode.length/2).toString(16); while (vcodeLen.length < 4) vcodeLen = "0" + vcodeLen; TEA.initkey(s2); var rawContent = TEA.encrypt(md5Pwd + TEA.strToBytes(salt) + vcodeLen + hexVcode); TEA.initkey(""); // reset key var rawLength = Number(rawContent.length / 2).toString(16); while (rawLength.length < 4) rawLength = '0' + rawLength; var result = $pt.RSA.rsa_encrypt(hexchar2bin(rawLength + rawContent)); setTimeout(function() { // IE6 下报权限错误! __monitor(488358, 1); }, 0); return btoa(hexchar2bin(result)).replace(/[\/\+=]/g, function(a) {return {'/':'-', '+':'*', '=':'_'}[a];}); } function getRSAEncryption(password,vcode, isMd5){ var str1 = isMd5 ? password : md5(password); var str2 = str1+vcode.toUpperCase(); var str3=$.RSA.rsa_encrypt(str2); return str3; } return { getEncryption:getEncryption, getRSAEncryption:getRSAEncryption, md5: md5 }; }(); try { /** * MTT QQ浏览器API * @type {{version, isAndroid, isIPhone, canQlogin, QLogin4PT, canOneKey, refreshToken}} */ // console.log(window) window.MTT = (function() { var version = 0, platform = ""; try { if (typeof window.browser != 'undefined') version = browser.env && browser.env.version; else window.browser = { env: {}, app: {}, login: {} }; platform = browser.env && browser.env.platForm; } catch (e) { $.report.nlog("browser_env:" + "ver(" + window.ptui_pt_version + ")" + e.message, "647126"); } var isAndroid = (platform == "ADR"); var isIPhone = (platform == "I"); var isIPad = (platform == "IP"); function canQlogin() { try { if (!version) return false; var ua = navigator.userAgent; var isWPMTT = /msie/i.test(ua) && ("notify" in window.external); if (isWPMTT) return true; var isIphoneQQBrowser = isIPhone && version >= 42; var isIpadQQBrowser = isIPad && version >= 32; var isAndoidQQBrowser = isAndroid && version >= 42; return isIphoneQQBrowser || isIpadQQBrowser || isAndoidQQBrowser; } catch (e) { return false; } } function QLogin4PT(callbackFunc) { var canQlogin = ($.cookie.get("pt_qlogincode") != 5) && MTT.canQlogin(); if ("function" != typeof(callbackFunc)) { return; } if (canQlogin) { if (/msie/i.test(window.navigator.userAgent)) { window.external.notify("#@getUserInfoWT@#pt.qqBrowserCallback"); } else { if (isAndroid) if (browser.login.getLoginInfo) browser.login.getLoginInfo(callbackFunc, callbackFunc); else callbackFunc(""); else if (isIPhone || isIPad) if (browser.login.getUinAndSidInfo) browser.login.getUinAndSidInfo(callbackFunc, callbackFunc); else callbackFunc(""); } } else { callbackFunc(""); if ($.cookie.get("pt_qlogincode") == 5) { $.report.nlog("快速登录异常:pt_qlogincode=5", "276650"); } } } function canOneKey(success, fail) { if (!version) { // 非QQ浏览器直接返回false fail && fail(); return false; } if (isAndroid) { if (!browser.app.getApkInfo) return fail && fail(); browser.app.getApkInfo(function(info) { try { info = JSON.parse(JSON.parse(info)); if (version >= 51 && info && info.versionname >= "4.7") success && success(); else fail && fail(); } catch (e) { fail && fail(); } }, "com.tencent.mobileqq"); } else if (isIPhone || isIPad) { window.x5 && x5.exec(function(app) { if (app && app.isSupportApp) success && success(); else fail && fail(); }, fail, "app", "getMobileAppSupport", [{ "scheme": "wtloginmqq2://" }]); } return false; } function refreshToken(uin, callback) { // 刷新QQ浏览器的stweb票据 if (isAndroid && browser.login.refreshToken) { browser.login.refreshToken({ "uin": uin }, callback); } else if (isIPad || isIPhone) { window.x5 && x5.exec(callback, callback, "login", "refreshToken", [{ "uin": uin }]); } } return { version: version, isAndroid: isAndroid, isIPhone: isIPhone, canQlogin: canQlogin, QLogin4PT: QLogin4PT, canOneKey: canOneKey, refreshToken: refreshToken }; }()); } catch (e) { // console.log(e) $.report.nlog("QB Exception:" + "ver(" + window.ptui_pt_version + ")" + e.message, "647127"); window.MTT = {}; } /////////////////////////////////////////////////////登录逻辑 var pt = { pageState: 1, login_href: window.g_href, domain: window.ptui_domain, isHttps: $.check.isHttps(), errTipClock: 0, //错误提示定时器 lang: window.STR_LANG, submit_o: {}, //登录提交参数对象 auto_login: false, //下次自动登录 switch_position_x: 0, //滑动开关位置(应该是手指的位置) touchstartTime: 0, //按住开始的时间,用于计算长按 longTouchTime: 500, //长按时间 default_face_url: "", //默认头像地址 is_qlogin: false, //是否快速登录 lang_num: window.ptui_lang, //语言 action: [0, 0], //动作 vcode: "", //验证码 verifysession: "", //验证码cookie deviceType: 2, //0 pc ;1 android;2 iphone;3 wp;4 symbian;5 blackberry;其它认为是pc login_uin: "", login_pwd: "", //3-md5 needAt: "", //特殊帐号前加@符号 //////////////////////////////// url中自定义参数 appid: "", //appid 必须的 s_url: "", //登录成功跳转的url low_login_enable: window.ptui_low_login, //弱登录 style: 9, ///////////////////////////////////// t_type: 0, ///////////// isSubmiting: false, //判断是否正在提交 key_interval: 0, keyindex: 19, //qq浏览器快速登录 qqBrowserInfo: null, //qq浏览器快速登录信息,object openCookieInfo: null, //互联cookie登录信息 authInfo: null, //授权信息,object authUin: '', //授权信息 authNick: '', //授权昵称 authLoginUrl: '', //授权登录url qlogin_list_data: [], //快速登录数据(所有的出现头像的) checkUrl: '', loginUrl: '', cookieInfo: null, //互联cookie登录的信息 cookieLogin: false, //是否使用cooki中skey登录 //快速登录的头像列表 regTmp: '\
\ \
\ \
\ \
', //互联快速登录头像 hulianRegTmp: '
\ #nick#\
\
\
#nick#
\
#uin#
\
\ ', new_vcode: false, clickEvent: "touchstart", checkErr: { "2052": "网络繁忙,请稍后重试。", "1028": "網絡繁忙,請稍後重試。", "1033": "The network is busy, please try again later." }, /** * 是否互联登录框 */ isHulian: window.ptui_appid == 716027609, isOffice: window.ptui_style == 39, isWtlogin: window.ptui_style == 42, isInIframe: window.ptui_style == 38 || window.self !== window.top, //遇到了非38的iframe内嵌,这里判断一下更准确 is3gNews: window.ptui_style == 37, // 37 手腾网,最简单的版本 isMail: window.ptui_appid == 522005705, lockedAccount: window.ptui_lockuin == 1 ? window.ptui_defuin : "", // 锁定账号,比如说财付通支付场景 ua: window.navigator.userAgent.toLowerCase(), isWX: window.navigator.userAgent.match(/micromessenger\/(\d\.\d\.\d)/i), isMQQ: window.navigator.userAgent.match(/qq\/(\d\.\d\.\d)/i), isAndroid: /android/i.test(window.navigator.userAgent), isIos: (/iPad|iPhone|iPod/.test(window.navigator.platform) || (window.navigator.platform === 'MacIntel' && window.navigator.maxTouchPoints > 1)) && !window.MSStream, isIPhone: /iphone/i.test(window.navigator.userAgent), uInput: $("u"), pInput: $("p"), btnGo: $("go"), btnGo2: $("go2"), btnOnekey: $("onekey"), browser : (function(){ var browser = { //这里要注意一件时间,由于历史逻辑的存在,当在企业微信打开时,isWX=true,isWorkWX=true ,暂时保留这样,后续迭代时再处理 isWX: false, isWorkWX : false, ua : '', replaceLocation : function(url, context){ const win = context || window win.location.replace(url) }, setLocation : function(url, context){ const win = context || window win.location.assign(url) }, isOnline : function(){ return !!window.navigator.onLine }, init : function(){ browser.ua = window.navigator.userAgent.toLowerCase() || ''; browser.isWX = !!browser.ua.match(/micromessenger\/(\d\.\d\.\d)/i) browser.isWorkWX = !!browser.ua.match(/wxwork\/\d\.\d\.\d/i) } } //默认进行一次初始化 browser.init(); return browser })(), /** * [redirect 统一跳转] * @param {[type]} target [description] * @param {[type]} url [description] * @return {[type]} [description] */ redirect: function(target, url) { switch (target + '') { case '0': if (pt.isInIframe || $.bom.query("pt_replace") == "1") this.browser.replaceLocation(url); // 作为iframe. 不想留下历史记录 else this.browser.setLocation(url); //这里换成assign,方便sinon mock break; default: if ($.bom.query("pt_replace") == "1") this.browser.replaceLocation(url,window.top); else this.browser.setLocation(url, window.top); // window.location.assign(url); //这里换成assign,方便sinon mock break; } }, init: function() { if (pt.hasInit) { return; } else { pt.hasInit = true; } pt.default_face_url = "//imgcache.qq.com/ptlogin/v4/style/0/images/1.gif"; //QQ企鹅头像地址 pt.initSURL(); pt.setClickEvent(); if (pt.isOffice) { pt.open.loadAppInfo(); } //发起各种异步请求 if (!window.hlhdFlag) { pt.qqBrowserQlogin(); } pt.auth(); //绑定相关事件 pt.bindEvent(); pt.bindInput(); //隐藏地址栏 pt.hideURLBar(); //先屏蔽,等验证码准备完成了再打开 pt.setVcodeFlag(); //拉取头像 pt.setUrl(); pt.showAutoLogin(); $.winName.set("login_href", encodeURIComponent(pt.login_href)); pt.checkIframe(); pt.checkPostMessage(); if (window.ptui_style == 42) { pt.uInput && pt.uInput.focus() } window.setTimeout(function(e) { if (window.ptui_appid != "549000929") { //qzone的不上报 pt.webLoginReport(); } /* ID: 408084 名称:互联手机版不支持cookie ID: 408085 名称:互联手机版不支持cookie bug ID: 410030 名称:login_mobile.js check 总量(10%) ID: 410031 名称:login_mobile.js check后台不下发cookie */ $.report.monitor(412020, 0.05); if (!navigator.cookieEnabled) { $.report.monitor(410030); if ($.cookie.get('ptcz')) $.report.monitor(410031); } }, 2000); if (pt.lockedAccount && window.ptui_tab) { //锁定帐号的时候不展示二维码入口 pt.switchpwd(); var qlogin_entry = $('qlogin_entry'); qlogin_entry && $.css.hide(qlogin_entry); } //Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16C101 QQ/7.9.9.445 V1_IPH_SQ_8.0.8_1_APP_A Pixel/1080 Core/WKWebView Device/Apple(iPhone 7Plus) NetType/4G QBWebViewType/1 WKType/1 var capthchaJsUrl = (pt.isHttps ? 'https://ssl.captcha.qq.com/' : 'http://captcha.qq.com/') + 'template/TCapIframeApi.js?aid=' + window.ptui_appid + '&rand=' + Math.random() + '&clientype=1&lang=' + pt.lang_num + '&apptype=2' if(navigator.userAgent.indexOf('Core/WKWebView')>=-1){ //wk webview里边, 如果有任何js资源 一直没有回包, 会阻塞页面渲染, 所以放到onload之后再去 window.addEventListener('load', function(){ $.http.loadScript(capthchaJsUrl, function() {}); }) }else{ $.http.loadScript(capthchaJsUrl, function() {}); } }, VCCallback: function(data) { switch (+data.ret) { case 0: pt.submitNewVcode(data); break; case 1: pt.go_back(); break; } }, setUrl: function() { var proto = pt.isHttps ? "https://ssl." : "http://"; var protoCheck = pt.isHttps ? "https://ssl." : "http://check."; pt.checkUrl = protoCheck + "ptlogin2." + pt.domain + "/check?"; pt.loginUrl = proto + "ptlogin2." + pt.domain + "/"; }, /** * [ptui_speedReport 测速上报] * @param {Object} params [键值对象] * @return {[type]} [description] */ ptui_speedReport: function(params) { var url = 'http://isdspeed.qq.com/cgi-bin/r.cgi?flag1=7808&flag2=8'; var flag3 = 1; if (pt.isHttps) { url = 'https://huatuospeed.weiyun.com/cgi-bin/r.cgi?flag1=7808&flag2=8'; flag3 = 2; } else { //url = 'http://isdspeed.qq.com/cgi-bin/r.cgi?flag1=7808&flag2=8'; if ($.detectBrowser()[0] == "MQQBrowser") { var net = navigator.connection; if (net && net.type) { var type = net.type; if (type == 1) { //ethernet flag3 = 3; } else if (type == 2) { //wifi flag3 = 4; } else if (type == 3) { //2g flag3 = 5; } else if (type == 4) { //3g flag3 = 6; } else if (type == 5) { //4g flag3 = 7; } else { //none flag3 = 8; } } else { flag3 = 8; } } else { flag3 = 1; } } url += '&flag3=' + flag3; for (var o in params) { //除去十分不靠谱的时间(超过15秒) if (params[o] > 15000 || params[o] < 0) { continue; } url += "&" + o + "=" + (params[o] || 1); //最小赋值为1,否则会被丢弃 } var img = new Image(); img.src = url; }, /** * [webLoginReport 测速上报逻辑] * @return {[type]} [description] */ webLoginReport: function() { try { //抽样20%,QQ浏览器全部上报 if (Math.random() > 0.2 && $.detectBrowser()[0] != "MQQBrowser") { return; } var points = ["navigationStart", "unloadEventStart", "unloadEventEnd", "redirectStart", "redirectEnd", "fetchStart", "domainLookupStart", "domainLookupEnd", "connectStart", "connectEnd", "requestStart", "responseStart", "responseEnd", "domLoading", "domInteractive", "domContentLoadedEventStart", "domContentLoadedEventEnd", "domComplete", "loadEventStart", "loadEventEnd"]; var params = {}; var h5_time = window.performance ? window.performance.timing : null; if (h5_time) { var baseTime = h5_time[points[0]]; var i = 1; for (var len = points.length; i < len; i++) { if (h5_time[points[i]]) { params[i] = h5_time[points[i]] - baseTime; } } if (loadJs && loadJs.onloadTime) params[i++] = loadJs.onloadTime - baseTime; var isReasonable = h5_time['connectEnd'] >= h5_time['connectStart'] && h5_time["responseEnd"] >= h5_time["responseStart"] && h5_time['domComplete'] >= h5_time['domInteractive'] && h5_time['domInteractive'] >= h5_time['domLoading'] && h5_time['loadEventStart'] >= h5_time['domComplete'] && h5_time['loadEventEnd'] >= h5_time['loadEventStart']; if (isReasonable) { pt.ptui_speedReport(params); } } } catch (e) {} }, setClickEvent: function() { var noIosOrAndroid = !/iphone|ipad|android/.test(window.navigator.userAgent.toLowerCase()); if(noIosOrAndroid){ pt.clickEvent = "click"; }else{ pt.clickEvent = "touchstart"; } }, //存储上次登录的号码(only one),登录成功且没有选择自动登录的 saveLastUin: function(uin) { $.localStorage.set("last_uin", uin); }, //获取上次登录的号码 getLastUin: function() { return $.localStorage.get("last_uin"); }, //将一个对象转换成url后面的参数 a=b& object2param: function(obj) { var arr = []; for (var n in obj) { arr.push(n + "=" + obj[n] + "&"); } return arr.join(""); }, //ps:以下部分都是海外登录的逻辑,由于不清楚情况,先不要动 //进入海外手机登录页面 is_oversea: false, enterOverseaLogin: function() { try { pt.alert.hide(); } catch (e) {} var e = $('oversea'); e && $.css.show(e); pt.is_oversea = true; $('state').value = _areaList[0].n; $('country-code').innerHTML = '+' + _areaList[0].c; if (window.openSDK && window.openSDK.clearAllEdit) { $('password').value = ''; window.openSDK.clearAllEdit(); } }, exitOverseaLogin: function() { var e = $('oversea'); e && $.css.hide(e); pt.is_oversea = false; if (window.openSDK && window.openSDK.clearAllEdit) { pt.pInput.value = ''; window.openSDK.clearAllEdit(); } }, //进入国家选择页 enterOverseaCountry: function() { pt.initOverseaCountry(); var e = $('country'); e && $.css.show(e); var state = $('state'); state && state.blur(); }, setOverseaCountry: function(code) { for (var i in _areaList) { if (code == _areaList[i].n) { $('state').value = _areaList[i].n; $('country-code').innerHTML = '+' + _areaList[i].c; pt.exitOverseaCountry(); return; } } }, initOverseaCountry: function() { var search = $('country-search'), list = $('country-list'), html = ''; search.value = ''; if (_areaList) { for (var i in _areaList) { html += '
  • ' + _areaList[i].n + '
  • ' } } list.innerHTML = html; }, updateOverseaCountry: function() { var search = $('country-search'), list = $('country-list'), html = ''; if (_areaList) { var key = new RegExp(search.value.split('').join('.{0,}'), "i"); for (var i in _areaList) { if (key.test(_areaList[i].c) || key.test(_areaList[i].n) || key.test(_areaList[i].p)) html += '
  • ' + _areaList[i].n + '
  • ' } } list.innerHTML = html; }, countrySearchFocus: function() { var placeholder = $('country-search-placeholder'); placeholder && $.css.hide(placeholder); }, countrySearchBlur: function() { var placeholder = $('country-search-placeholder'); var input = $('country-search'); input && placeholder && input.value.length === 0 && $.css.show(placeholder); }, exitOverseaCountry: function() { var e = $('country'); e && $.css.hide(e); }, //ps:以上部分都是海外登录的逻辑,由于不清楚情况,先不要动 //显示错误 showErr: function(message, callback) { clearTimeout(pt.errTipClock); var timeout = 3000; if ((typeof callback).toLocaleLowerCase() == "number") { timeout = parseInt(callback, 10); callback = null; } $("error_message").innerHTML = message; $.css.show("error_tips"); if (pt.isHulian) { if (window.navigator.userAgent.match(/iphone/i)) { pt.btnGo.focus(); // fix ios webview 键盘无法输入问题 } pt.errTipClock = window.setTimeout(function() { pt.hideErr(callback); }, timeout); } else { callback && callback(); pt.errTipClock = window.setTimeout(function() { pt.hideErr(); }, timeout); } }, /** * [hideErr 隐藏错误] * @return {[type]} [description] */ hideErr: function(callback) { $.css.hide("error_tips"); callback && callback(); }, /** * [checkiframe description] * @return {[type]} [description] */ checkIframe: function() { try { if (top != self && !pt.isHulian) { $.report.nlog("iphone登录框被iframe;" + "referer=" + document.referrer, "347748"); } } catch (e) { } }, checkPostMessage: function() { if (typeof window.postMessage == "undefined") { $.report.nlog("iphone登录框不支持postMessage;", "350525"); } if (typeof window.JSON == "undefined") { $.report.nlog("iphone登录框不支持JSON;", "362678"); } }, /** * [setVcodeFlsg 初始化使用验证码的方式] */ setVcodeFlag: function() { if (typeof window.postMessage == "undefined" || typeof window.JSON == "undefined") { pt.new_vcode = false; } else { pt.new_vcode = true; } }, /** * [getAuthUrl 构造授权url] * @return {String} [description] */ getAuthUrl: function() { var authUrl = (pt.isHttps ? "https://ssl." : "http://") + "ptlogin2." + pt.domain + "/pt4_auth?daid=" + window.ptui_daid + "&appid=" + window.ptui_appid + "&auth_token=" + $.str.time33($.cookie.get("supertoken")); if (/^https/.test(pt.s_url)) { //成功地址为https的 authUrl += "&pt4_shttps=1"; } if (window.ptui_pt_qzone_sig == "1") { authUrl += "&pt_qzone_sig=1"; } return authUrl; }, /** * [auth 授权] * @return {[type]} [description] */ auth: function() { //获取参数列表 pt.getParam(); pt.initSURL(); var authUrl = pt.getAuthUrl(); var superuin = $.cookie.get("superuin"); //没有skey就没有superkey,这个时候可以不用去后台请求了 // APP下发superkey的时候,一般并不下发supertoken, 所以只能这里自己下发,这主要还依赖于后台对supertoken并不要求与superkey对应 var fake_supertoken = $.str.hash33(superuin); if (!parseInt($.cookie.get("supertoken")) && fake_supertoken) $.cookie.set("supertoken", $.str.hash33(superuin), "ptlogin2." + pt.domain); if (window.ptui_daid && window.ptui_noAuth != "1" && superuin != "" && !pt.isWtlogin) { $.http.loadScript(authUrl); } }, showAuth: function(url) { var params = url.substr(url.indexOf("?") + 1); var m = params.match(RegExp("(^|&)uin=([^&]*)(&|$)")); pt.authUin = !m ? "" : decodeURIComponent(m[2]); pt.authLoginUrl = url; pt.authNick = $.str.utf8ToUincode($.cookie.get("ptnick_" + pt.authUin)) || pt.authUin; if (pt.authUin) { pt.authInfo = { "uin": $.str.encodeHtml(pt.authUin), "nick": $.str.encodeHtml(pt.authNick), "authUrl": pt.authUrl, "type": 3 }; } }, // 互联使用superkey登录,包括已登录互联或者已登录其它业务两种情况 setCookieLogin: function() { //非手Q内需要superkey登录 优先使用superkey var superkey = $.cookie.get("supertoken"); var uin = $.cookie.get("superuin"); if (uin) uin = parseInt(uin.substring(1), 10); else uin = null; var nick = $.str.utf8ToUincode($.cookie.get("ptnick_" + uin)) || uin; var hasCookie = window.ptui_daid && superkey; if ((hasCookie && uin)) { pt.cookieInfo = { "uin": $.str.encodeHtml(uin), "nick": $.str.encodeHtml(nick), "superkey": superkey, "type": 4 }; return true; } //没有superkey的时候 手Q内直接可以用clientkey登录 uin = $.cookie.uin(); nick = $.str.utf8ToUincode($.cookie.get("ptnick_" + uin)) || uin; if (uin && pt.mqqCanQLogin()) { pt.cookieInfo = { "uin": $.str.encodeHtml(uin), "nick": $.str.encodeHtml(nick), "type": 4 }; return true; } return false; }, qqBrowserQlogin: function() { try { //iframe的话无法获取到qq浏览器的信息, android 还是可以的 if (self === top || MTT.isAndroid) { MTT.QLogin4PT(pt.qqBrowserCallback); } } catch (e) { $.report.nlog("快速登录异常,qqBrowserQlogin," + e.message, "276650"); } }, qqBrowserCallback: function(info) { try { if (info && typeof info === "string") info = JSON.parse(info); if (info && ($.check.isQQ(info.uin) && info.loginkey.length != 0 && info.loginkey.length > 10)) { pt.qqBrowserInfo = {}; pt.qqBrowserInfo.uin = $.str.encodeHtml(info.uin); pt.qqBrowserInfo.nick = $.str.encodeHtml(info.nickname); pt.qqBrowserInfo.loginkey = info.loginkey; pt.qqBrowserInfo.type = 2; pt.refreshQloginUI(); } else { if (info && info.uin.length == 0) { $.report.nlog("快速登录异常:数据返回异常,没有uin", "276650"); } else if (info && info.loginkey.length == 0) { $.report.nlog("快速登录异常:数据返回异常,没有loginkey", "276650"); } else if (info) { $.report.nlog("快速登录异常:数据返回异常:" + info.loginkey.length, "276650"); } } } catch (e) { $.report.nlog("快速登录异常: qqBrowserCallback " + e.message, "276650"); } }, initSURL: function() { pt.s_url = $.bom.query("s_url"); if (pt.isMail && pt.low_login_enable == 1) pt.s_url = pt.addParamToUrl(pt.s_url, "ss", 1); }, /** * [addParamToUrl 在一个url后面增加参数] * @param {String} url [description] * @param {String} name [description] * @param {String|Number} value [description] */ addParamToUrl: function(url, name, value) { var u1 = url.split('#'); var sep = u1[0].indexOf('?') > 0 ? '&' : '?'; if (u1[0].substr(u1[0].length - 1, 1) == '?') { sep = ''; // 没有更多参数,也就不用加个&了 } if (u1[1]) { u1[1] = '#' + u1[1]; } else { u1[1] = ''; } return u1[0] + sep + name + '=' + value + u1[1]; }, //获取url参数 getParam: function() { pt.appid = window.ptui_appid; if (pt.isInIframe) { //style=38支持self跳转,其他的都是top跳转 switch (window.ptui_target) { case "_self": case "0": pt.target = 0; break; case "_top": case "1": pt.target = 1; break; default: pt.target = 1; break; } } else { pt.target = 1; } //pt.low_login_enable = ($.bom.query("low_login_enable")==1 ? $.bom.query("low_login_enable") : 0) || ($.bom.query("low_login")==1 ? $.bom.query("low_login") : 0); pt.style = window.ptui_style ? window.ptui_style : 9; // 改造中,改造完成只需把这个注释去掉, skey 与 superkey 是兼容的 //if (pt.isHulian) // window.ptui_daid = window.ptui_daid || 381; // 互联登录有可能被其它业务直接引用,那么这个daid就不一定会传过来,所以自己加上 if (pt.isHulian) window.pt_skey_valid = parseInt($.bom.query("pt_skey_valid")) || 0; // 由互联跳转过来时带的标记位 }, //生成快速登录列表 build_qlogin_list: function() { var qlogin_list_data = pt.get_qlogin_list(); pt.qlogin_list_data = qlogin_list_data; var length = qlogin_list_data.length if (window.ptui_style == 35 && length > 1) length = qlogin_list_data.length = 1 if (length > 0 && !window.ptui_tab) { pt._switch(2); //指定切到快速登录页 pt.hideOneKey(); var strMessage = ""; for (var i = 0; i < length; i++) { if (qlogin_list_data[i].uin != "") { strMessage += pt.regTmp.replace(/#uin#/g, qlogin_list_data[i].uin) .replace(/#nick#/g, qlogin_list_data[i].nick) .replace(/#pwd#/g, qlogin_list_data[i].pwd) .replace(/#type#/g, qlogin_list_data[i].type) .replace(/#src#/g, pt.default_face_url); } } if (length > 1 && window.xMsg && window.xMsg.call) window.xMsg.call("connect", "userSwitch", {}, function() {}); $("q_logon_list").innerHTML = strMessage; //昵称过长的中间加... for (var i = 0; i < length; i++) { pt.getShortWord($("nick_" + qlogin_list_data[i].uin), qlogin_list_data[i].nick, 95); } pt.initFace(); $("swicth_login") && ($("swicth_login").style.display = "block"); } else { $("web_login") && ($("web_login").style.display = "block"); $("swicth_login") && ($("swicth_login").style.display = "none"); } }, fill_usernick: function() { // 手Q环境下补充昵称 if (window.mqq && window.mqq.data && window.mqq.data.getUserInfo) { window.mqq.data.getUserInfo(function(result) { var usernick = $("hl_usernick"); if (usernick && result && result.nick) usernick.innerHTML = $.str.encodeHtml(result.nick); }); } }, build_office_qlogin: function() { $.report.monitor(2123219); if (!pt.cookieInfo) pt.setCookieLogin(); if (!pt.cookieInfo) return $.report.monitor(2123220); pt.cookieLogin = true; $("hl_avatar").style.backgroundImage = "url(https://q4.qlogo.cn/g?b=qq&nk=" + pt.cookieInfo.uin + "&s=100)"; $("hl_usernick").innerHTML = pt.cookieInfo.nick || pt.cookieInfo.uin; $("hl_qqnum").innerHTML = "(" + pt.cookieInfo.uin + ")"; pt.fill_usernick(); }, //切换登录方式 _switch: function(state) { var switchqlist = function() { var switcher = $("swicth_login"); $("q_login").style.display = "block"; $("web_login").style.display = "none"; if (switcher) { switcher.innerHTML = $.str.encodeHtml('切换帐号'); //TODO 后面改多语言 switcher.classList.add('weakest') } pt.hideURLBar(); pt.pageState = 2; }, switchpwd = function() { var switcher = $("swicth_login"); pt.showOneKey.ever && pt.showOneKey(); $("q_login").style.display = "none"; $("web_login").style.display = "block"; if (switcher) { switcher.innerHTML = $.str.encodeHtml("切换账号") switcher.classList.remove('weakest'); } pt.uInput.focus(); //聚焦,调出键盘 pt.pageState = 1; window.xMsg && xMsg.call("connect", "userSwitch", {}, function() {}); } //切换到快速登录 if (typeof state === "undefined") if ($("q_login").style.display == "none") { switchqlist(); } //切换到普通登录 else { switchpwd(); } else switch (+state) { case 2: switchqlist(); break; case 1: switchpwd(); break; default: break; } pt.showAutoLogin(); if (pt.isInIframe) { //手机弹出式 window.setTimeout(function() { pt.ptui_notifySize("content"); }, 0) } }, checkNetwork: function() { if (!pt.browser.isOnline()) pt.showErr(window.STR_LANG.offline); else return pt._timer = window.setTimeout(function() { $.report.monitor(2114669); pt.showErr(window.STR_LANG.offline); try { pt.endLoading(); } catch (e) {} }, 10000); }, loadingDiv: null, isLoading: false, startLoading: function() { if (!pt.loadingDiv) { pt.loadingDiv = document.createElement("div"); pt.loadingDiv.className = 'qui-loading-mask'; } document.body.appendChild(pt.loadingDiv); pt.isloading = true; }, endLoading: function() { document.body.removeChild(pt.loadingDiv); pt.isloading = false; }, submitEvent: function(e) { pt.checkNetwork(); pt.startLoading(); // todo 办公开放添加上报 if (pt.isOffice && pt.cookieLogin) { pt.cookielogin_submit(); // 已在其它业务登录,cookie中已有superkey } else if (pt.isOffice && pt.qqBrowserInfo) { // MTT快速登录 pt.qlogin_submit(); } else { pt.check(false); } pt.qrcode.used = false; }, showOneKey: function(sure) { var btnOnekey = $("onekey"); if (!pt.showOneKey.ever) { $.e.add(btnOnekey, pt.clickEvent, pt.doOneKey); $.e.add(btnOnekey, 'blur', pt.cancelAutoOneKey); } pt.showOneKey.ever = true; if (sure) { pt.btnGo.className += ' weak'; } else { btnOnekey.className += ' weak'; } btnOnekey && $.css.show(btnOnekey); btnOnekey.focus(); $.report.monitor(414089); if (pt.isInIframe) { //手机弹出式 window.setTimeout(function() { pt.ptui_notifySize("content"); }, 0); } }, cancelAutoOneKey: function() { window.clearInterval(pt.showOneKey.tid); var btnOnekey = pt.btnOnekey; btnOnekey && (btnOnekey.innerHTML = window.STR_LANG.onekey); }, hideOneKey: function() { pt.cancelAutoOneKey(); pt.showOneKey.ever = false if (!(pt.isWtlogin || window.ptui_style == 35)) pt.btnGo.className = pt.btnGo.className.replace("weak", ""); pt.btnOnekey && $.css.hide(pt.btnOnekey); if (pt.isInIframe) { //手机弹出式 window.setTimeout(function() { pt.ptui_notifySize("content"); }, 0); } }, //绑定事件 bindEvent: function() { var u_input = pt.uInput, p_input = pt.pInput; //普通登录事件 $.e.add(pt.btnGo, pt.clickEvent, pt.submitEvent); pt.btnGo2 && $.e.add(pt.btnGo2, pt.clickEvent, function() { var list = $('q_logon_list') for (var i = 0; i < list.children.length; ++i) { if (list.children[i].onclick) { pt.clickHeader({ preventDefault: function() {}, currentTarget: list.children[i] }, true) return } } }) p_input && $.e.add(p_input, "keydown", function(e) { var keyCode = e.keyCode; if (keyCode == 13) { pt.submitEvent(); } }); //手机的前往按钮 u_input && $.e.add(u_input, "keydown", function(e) { var keyCode = e.keyCode; if (keyCode == 13) { pt.checkNetwork(); pt.startLoading(); pt.check(false); } }); var ua = navigator.userAgent.toLowerCase(), noOnekey = pt.isWX || pt.isMQQ || ua.match(/meizu_m9|IEMobile/i) || window.ptui_appid == 46000101 // 微博 || $.bom.query("pt_no_onekey") == 1 //业务主动隐藏了一键登录 || pt.s_url.indexOf('//openmobile.qq.com/api/check') >= 0; // 互联定向分享隐藏一键登录,因为是没有安装手Q才打开ptlogin登录 var btnOnekey = pt.btnOnekey; if (!noOnekey && btnOnekey) { if (pt.isHulian) { // 互联 xlogin 35 需要等授权页加载完成才判断 if (ua.match(/iphone|ipad/i)) { // fix ios webview bug: 输入框获得焦点时,滚动页面结束后再输入,将无法输入 document.addEventListener("touchmove", function() { pt.btnGo.focus() }, false); document.addEventListener("touchstart", function(e) { if (pt.uInput != e.target || pt.pInput != e.target) { pt.btnGo.focus(); } }, false); } pt.open.waiting('authlist', function() { MTT.canOneKey(function() { if (pt.get_qlogin_list().length) return; // 如果已经出现头像,以头像快速登录优先 pt.showOneKey(true); }, function() { if (window.hlhdFlag) { pt.showOneKey(); } else { pt.hideOneKey(); } }); }); } else { if (self === top && MTT.version) { // 浏览器既然可以判断,那就精确判断 MTT.canOneKey(function() { if (pt.get_qlogin_list().length) return; // 如果已经出现头像,以头像快速登录优先 // pt.showOneKey('justshow'); alice修改 pt.showOneKey(); }, function() { // pt.hideOneKey(); pt.showOneKey(); }); } else { // 否则默认显示一键登录, PC 上不显示了 var ua = navigator.userAgent; var desktop = ua.indexOf("Windows NT") > -1 || ua.indexOf("Macintosh") > -1; desktop || pt.isWtlogin || pt.showOneKey(); } } } else { pt.hideOneKey(); } $('show_pwd') && $.e.add($('show_pwd'), 'change', function(e) { var pwd = pt.pInput; if (this.checked) { pwd.setAttribute('type', 'text'); } else { pwd.setAttribute('type', 'password'); } }); $('forgetpwd') && $.e.add($('forgetpwd'), pt.clickEvent, function(e) { var uin = pt.uInput && pt.uInput.value; var url = "https://ssl.ptlogin2.qq.com/ptui_forgetpwd_mobile?ptlang=" + pt.lang_num; if (pt.lang_num != "1033") url += "&account=" + uin; window.open(url); }); $.e.add(window, "orientationchange", function(e) { //页面回复原形 pt.hideURLBar(e); }); if (pt.isMail) { var rem = $("remember"); if (!rem) return; $.e.add(rem, "change", function() { if (rem.checked) pt.s_url = pt.addParamToUrl(pt.s_url, "ss", 1); else pt.s_url = pt.s_url.replace(/&?ss=1/, ""); pt.low_login_enable = rem.checked ? 1 : 0; }); } if ($('download-link') && $('download-area')) { $.e.add($('download-area'), 'click', function(e) { if (e.target !== $('download-link')) $('download-link').click(); return false; }); var rule_cn = [ [/android/i, "market://details?id=com.tencent.mobileqq"], [/ipad|iphone/i, "itms-apps://itunes.apple.com/us/app/qq/id444934666?mt=8"] ]; var rule_i18n = [ [/android/i, "market://details?id=com.tencent.mobileqqi"], [/ipad|iphone/i, "itms-apps://itunes.apple.com/us/app/qq-international/id710380093?mt=8"] ]; switch (parseInt(ptui_lang)) { case 1033: case 1028: for (var i in rule_cn) { if (rule_i18n[i][0].test(navigator.userAgent)) { $('download-link').href = (rule_i18n[i][1]); break; } } if ($('download-link').href.length == 0) { $('download-link').href = ("http://www.imqq.com/?lang=" + ptui_lang); } break; default: for (var i in rule_cn) { if (rule_cn[i][0].test(navigator.userAgent)) { $('download-link').href = (rule_cn[i][1]); break; } } if ($('download-link').href.length == 0) { $('download-link').href = ("https://im.qq.com"); } break; } var ua = navigator.userAgent; if (/ipad/i.test(ua)) { $('download-link-pad').href = "itms-apps://itunes.apple.com/cn/app/qq-hd-2011/id453718989?mt=8"; } else if (/android/i.test(ua) && !/mobile/i.test(ua)) { $('download-link-pad').href = "market://details?id=com.tencent.minihd.qq"; } else { $('download-link-pad').href = $('download-link').href; } } if ($('qrlogin_switch')) { $.e.add($('qrlogin_switch'), 'click', function() { pt.switchpwd(); return false; }); } $('qr_invalid') && $.e.add($('qr_invalid'), 'click', function() { pt.qrcode.get(0); $.css.hide($('qr_invalid')); }); //优化移动端聚焦体验 document.body.addEventListener('focus', function(e) { if (e.target.scrollIntoViewIfNeeded) e.target.scrollIntoViewIfNeeded(); else if (e.target.scrollIntoView) e.target.scrollIntoView(); }, true); if ($('switcher_qlogin')) { $.e.add($('switcher_qlogin'), 'click', function() { pt.switchqr(); return false; }) } setTimeout(function() { if (window.ptui_tab) { //邮箱appid暂时不跳转到qr框 if (window.ptui_appid != 756044602) { //初始化二维码 pt.qrcode.get(0); } else { pt.switchpwd(); } } }, 0) }, //输入框事件绑定 bindInput: function() { if (pt.isOffice) return; // 办公互联没有输入框 //帐号框初始化值 var last_uin = window.ptui_defuin || pt.lockedAccount || pt.getLastUin(); //现在有主页面的输入框和 手机号页面的输入框 var uInput = pt.uInput, pInput = pt.pInput, uDel = $("del_touch") || $("del_u"), pDel = $("del_touch_p") || $("del_p"), //手机页面元素 phoneInput = $('phone'), passwordInput = $('password'), phoneDel = $('del_phone'), passwordDel = $('del_password'); var showDelWrapper = function(elem, isShow, outer, resize) { return function(e) { isShow ? elem && $.css.show(elem) : elem && $.css.hide(elem); if (resize) { outer && (outer.style.paddingRight = (isShow ? "20px" : "")); } } }; var showUDel = showDelWrapper(uDel, true, uDel.parentNode, ptui_style == 42), hideUDel = showDelWrapper(uDel, false, uDel.parentNode, ptui_style == 42), showPDel = showDelWrapper(pDel, true, pDel.parentNode, ptui_style == 42), hidePDel = showDelWrapper(pDel, false, pDel.parentNode, ptui_style == 42), showPhoneDel = showDelWrapper(phoneDel, true, phoneDel.parentNode, true), hidePhoneDel = showDelWrapper(phoneDel, false, phoneDel.parentNode, true), showPasswordDel = showDelWrapper(passwordDel, true, passwordDel.parentNode, true), hidePasswordDel = showDelWrapper(passwordDel, false, passwordDel.parentNode, true); if (last_uin) { if (last_uin == "0") uInput.value = ""; else uInput.value = uInput.value || last_uin; } if (pt.lockedAccount) { uInput.readOnly = true; pInput.focus(); //锁定帐号的时候不再显示删除uin的按钮 hideUDel(); showUDel = function() {}; } var inputWrapper = function(showFunction, hideFunction, password) { return function(event) { if (pt.lockedAccount && !password) return; var element = event.target; if (event.target.value != "") showFunction() else hideFunction(); if (password) { var caretPos = 0; if (element.selectionStart || element.selectionStart == '0') { caretPos = Math.max(element.selectionStart, element.selectionEnd); } if (window.openSDK && window.openSDK.curPosFromJS) { window.openSDK.curPosFromJS(caretPos); } } } } var focusWrapper = function(showFunction, password) { return function(event) { if (event.target.value != "") showFunction(); if (password) { if (window.openSDK && window.openSDK.isPasswordEdit) { window.openSDK.isPasswordEdit(1); } } } }; var blurWrapper = function(hideFunction, password, checkUin) { return function(event) { if (event.target.value == "") hideFunction(); if (password) { if (window.openSDK && window.openSDK.isPasswordEdit) { window.openSDK.isPasswordEdit(0); } } else { if (/^\+/.test(event.target.value)) { // 海外手机+号修正 event.target.value = event.target.value.replace(/^\+/, ''); if (!/^00/.test(event.target.value)) event.target.value = '00' + event.target.value; } if (event.target.value == "") { hideFunction(); } else if (checkUin) { pt.checkQQUin(event.target.value); //TODO 手机号 } } } } $.e.add(pInput, "focus", focusWrapper(showPDel, true)); $.e.add(pInput, "blur", blurWrapper(hidePDel, true)); $.e.add(pInput, "input", function(e) { window.setTimeout(function() { inputWrapper(showPDel, hidePDel, true)(e) }, 0); }); $.e.add(uInput, "focus", focusWrapper(showUDel)); $.e.add(uInput, "blur", blurWrapper(hideUDel, false, true)); $.e.add(uInput, "input", inputWrapper(showUDel, hideUDel)); $.e.add(passwordInput, "focus", focusWrapper(showPasswordDel, true)); $.e.add(passwordInput, "blur", blurWrapper(hidePasswordDel, true)); $.e.add(passwordInput, "input", function(e) { window.setTimeout(function() { inputWrapper(showPasswordDel, hidePasswordDel, true)(e) }, 0); }); $.e.add(phoneInput, "focus", focusWrapper(showPhoneDel)); $.e.add(phoneInput, "blur", blurWrapper(hidePhoneDel, false, false)); $.e.add(phoneInput, "input", inputWrapper(showPhoneDel, hidePhoneDel)); var delWrapper = function(input, hideFunction, password) { return function(e) { e && e.preventDefault(); input.value = ""; if (password) { if (window.openSDK && window.openSDK.clearAllEdit) { window.openSDK.clearAllEdit(); } } input.focus(); hideFunction(); } } uDel && $.e.add(uDel, "click", delWrapper(uInput, hideUDel)); pDel && $.e.add(pDel, "click", delWrapper(pInput, hidePDel, true)); phoneDel && $.e.add(phoneDel, "click", delWrapper(phoneInput, hidePhoneDel)); passwordDel && $.e.add(passwordDel, "click", delWrapper(passwordInput, hidePasswordDel)); }, //绑定验证码区域事件 bindVcodeEvent: function() { $("input_tips") && $.e.add($("input_tips"), "click", function(e) { $("vcode_input").focus(); $.css.hide("input_tips"); e.stopPropagation(); }); $("vcode_input") && $.e.add($("vcode_input"), "focus", function(e) { $.css.hide("input_tips"); e.stopPropagation(); }); $("vcode_input") && $.e.add($("vcode_input"), "blur", function(e) { if (this.value == "") { $.css.show("input_tips"); } }); $("vcode_img") && $.e.add($("vcode_img"), "click", function(e) { $("vcode_input").focus(); $.css.hide("input_tips"); pt.changeCodeImg(); e.stopPropagation(); }); $("submit") && $.e.add($("submit"), "click", function(e) { pt.submitVcode(); }); }, //隐藏地址栏 hideURLBar: function() { window.setTimeout(function() { window.scrollTo(0, 1); }, 0); }, // 根据当前页面状态摆放记住登录按钮的位置 showAutoLogin: function() { // todo 设置pagestate 常量 if (!pt.isMail) return; var autoLogin = $("auto_login"); if (!autoLogin) return; var btnGo = pt.btnGo; if (pt.pageState == 1) { $("web_login").insertBefore(autoLogin, btnGo); } else { var qlogin = $("q_login"); qlogin.insertBefore(autoLogin, qlogin.lastChild); } $.css.show(autoLogin); }, doOneKey: function(e) { // 防止短时间内重复点击 if (pt.doOneKey.ing) return; pt.doOneKey.ing = true; setTimeout(function() { pt.doOneKey.ing = false; }, 5000); var ua = navigator.userAgent.toLowerCase(); var p = pt.loginUrl + 'jump?u1=' + encodeURIComponent(pt.s_url) + "&pt_report=1"; if(window.pt_ptdrvs){ p += "&ptdrvs=" + window.pt_ptdrvs; } if (window.ptui_pt_ttype == "1") { p += "&pt_ttype=1"; } if (window.ptui_daid) { p += ("&daid=" + ptui_daid); } if (pt.low_login_enable) { p += "&low_login_enable=1&low_login_hour=" + window.ptui_low_login_hour; } p += "&style=" + window.ptui_style; var browser = $.detectBrowser()[0]; if (browser) { p += "&pt_ua=" + $.Encryption.md5(ua); p += "&pt_browser=" + browser; } var appname = $.bom.query("pt_appname"); if (appname) // 在手Q上展示应用名称 p += "&pt_appname=" + appname; var pkg = $.bom.query("pt_package"); if (/android/i.test(navigator.userAgent)) { if (pkg) // 在手Q上展示应用图标,复用申请快速登录所有图标 p += "&pt_package=" + pkg; } else { var bundleID = $.bom.query("pt_bundleid") || pkg; // 有可能ios和android包名相同,所以可以省略pt_bundleid if (bundleID) p += "&pt_bundleid=" + bundleID; } $.report.monitor(414090); qqMusicReport('83886593', 33616325); //QQ音乐一键登录上报 if (pt.isHulian) { pt.open.waiting('authdata', function() { if (window.ptui_pt_3rd_aid) { // for 互联 p += "&pt_3rd_aid=" + window.ptui_pt_3rd_aid; } if (pt.submit_o.openlogin_data) { p += "&pt_openlogin_data=" + pt.submit_o.openlogin_data; } OneKey('wtloginmqq://ptlogin/qlogin?p=' + encodeURIComponent(p)); }); } else { OneKey('wtloginmqq://ptlogin/qlogin?p=' + encodeURIComponent(p)); } }, /** * [addToSet 数组模拟集合的添加] * @param {[type]} list [description] * @param {[type]} o [description] */ addToSet: function(list, o) { if (!o) { } else { var id = o["uin"]; var needAdd = true; for (var i = 0, length = list.length; i < length; i++) { if (list[i]["uin"] == id) { needAdd = false; } } if (needAdd) { list.push(o); } } }, //获取快速登录帐号信息 get_qlogin_list: function() { var qlogin_list = []; //互联cookie登录 if (pt.isHulian) { if (pt.cookieInfo) { pt.addToSet(qlogin_list, pt.cookieInfo); } } else { if (pt.authInfo) { pt.addToSet(qlogin_list, pt.authInfo); } } if (pt.qqBrowserInfo) { pt.addToSet(qlogin_list, pt.qqBrowserInfo); } return qlogin_list; }, /** * [qlogin_submit 快速登录提交] * */ qlogin_submit: function(cgi) { $.report.monitor(259519); //手Q快速登录统计 var s_url = encodeURIComponent(pt.s_url); var pt_url; if (cgi == pt.qrcode.CGI) { pt_url = pt.loginUrl + cgi + "?u1=" + s_url; pt_url += "&from_ui=1&type=1&ptlang=" + pt.lang_num; pt_url += "&ptqrtoken=" + $.str.hash33($.cookie.get("qrsig")); } else if (cgi == "mqq") { pt_url = (pt.isHttps ? "https://ssl." : "http://") + "ptlogin2.qq.com/jump?clientuin=$UIN&clientkey=$KEY&keyindex=$KEYINDEX&u1=" + encodeURIComponent(pt.s_url); } else { var uin = pt.qqBrowserInfo.uin; var clientkey = pt.qqBrowserInfo.loginkey; pt_url = pt.loginUrl + "jump?keyindex=" + pt.keyindex + "&clientuin=" + uin + "&clientkey=" + clientkey + "&u1=" + s_url; } if (window.ptui_daid) pt_url += "&daid=" + window.ptui_daid; if (window.ptui_appid) pt_url += "&aid=" + window.ptui_appid; if (window.ptui_pt_qzone_sig == "1") { pt_url += "&pt_qzone_sig=1"; } if (window.ptui_pt_ttype == "1") { pt_url += "&pt_ttype=1"; } if (window.ptui_pt_light == "1") { pt_url += "&pt_light=1"; } if (pt.low_login_enable) { pt_url += "&low_login_enable=1&low_login_hour=" + window.ptui_low_login_hour; } if (window.ptui_pt_3rd_aid) { // for 互联 pt_url += "&pt_3rd_aid=" + window.ptui_pt_3rd_aid; } if (pt.submit_o.openlogin_data) { pt_url += "&pt_openlogin_data=" + pt.submit_o.openlogin_data; } if (window.ptui_kf_csimc != "0" && window.ptui_kf_csimc) { pt_url += "&csimc=" + ptui_kf_csimc; pt_url += "&csnum=" + ptui_kf_csnum; pt_url += "&authid=" + ptui_kf_authid; } pt_url += "&device=" + pt.deviceType; if (cgi != "mqq") pt_url += "&ptopt=1"; pt_url += "&pt_uistyle=" + window.ptui_style; if (cgi) return pt_url; $.http.loadScript(pt_url); }, /** * [cookielogin_submit 快速登录提交] * @return {[type]} [description] */ cookielogin_submit: function() { var superkey = pt.cookieInfo.superkey; if (superkey) { var superkey_token = superkey && $.str.hash33(superkey); pt.submit_o.auth_token = superkey_token; pt.submit('open'); } else { if (pt.mqqCanQLogin()) { pt.redirect(pt.target, pt.qlogin_submit("mqq")); } } }, /** * [cancel_cookielogin 取消cookie快速登录] */ cancel_cookielogin: function(clear) { try { $.css.show($("form_outter_wrap")); $.css.hide($("q_logon_list")); } catch (e) {} pt.cookieLogin = false; delete pt.submit_o['skey_token']; pt.cookieInfo = null; //清除帐号输入框 if (clear) pt.uInput.value = ""; }, authlogin_submit: function() { var authUrl = pt.authLoginUrl; authUrl += "®master=" + window.ptui_regmaster + "&aid=" + window.ptui_appid + "&s_url=" + encodeURIComponent(pt.s_url); if (pt.low_login_enable) { authUrl += "&low_login_enable=1&low_login_hour=" + window.ptui_low_login_hour; } //pt_ttype 是否下发vkey,现在已不使用 if (window.ptui_pt_ttype == "1") { authUrl += "&pt_ttype=1"; } //pt_light 是否下发superkey和skey if (window.ptui_pt_light == "1") { authUrl += "&pt_light=1"; } authUrl += "&device=" + pt.deviceType; //top.location.href = authUrl pt.redirect(pt.target, authUrl); }, /** * jsonp的方式提交登录表单 * @prama vcode 是否需要验证码 */ submit: function(vcode) { var u_input = pt.uInput, p_input = pt.is_oversea ? $('password') : pt.pInput; //get 参数 var uin = ""; //uin var pwd = ""; //原始密码 //这个来自check的cgi的返回,由于chrome的samesite策略,导致cookie中的ptdrvs可能种不上,这里在jsonp返回中获取并设置到全局变量上 if(window.pt_ptdrvs){ pt.submit_o['ptdrvs'] = window.pt_ptdrvs || ''; //参数也传ptdrvs,兜底 } //如果是快速登录,帐号和密码 if (pt.is_qlogin) { uin = pt.login_uin; //uin } else { uin = pt.needAt ? pt.needAt : u_input && u_input.value; //uin pt.login_uin = uin; //QQ音乐帐号密码登录上报 qqMusicReport("33616396", 33616396); } //////构造submit对象 if (vcode) { //免验证码的时候不带这个参数 pt.submit_o["pt_vcode_v1"] = 0; pt.submit_o["pt_verifysession_v1"] = pt.verifysession; } pt.submit_o.verifycode = pt.vcode.toUpperCase(); //验证码 必须 pt.submit_o.u = uin; var isMd5 = false; if (window.openSDK && openSDK.md5Pwd && openSDK.result == 0) { pwd = openSDK.md5Pwd; isMd5 = true; } else { pwd = p_input && p_input.value; //原始密码 isMd5 = false; } if (vcode != 'open') pt.submit_o.p = $.Encryption.getEncryption(pwd, pt.salt, pt.submit_o.verifycode, isMd5); //要提交给后台的密码形式 else delete pt.submit_o.p; pt.submit_o.pt_randsalt = pt.isRandSalt || 0; pt.submit_o.ptlang = pt.lang_num; //版本语种 必须 pt.submit_o.low_login_enable = (pt.low_login_enable == 1) ? 1 : 0; //是否自动登录 if (pt.submit_o.low_login_enable) { pt.submit_o.low_login_hour = window.ptui_low_login_hour; //弱登录默认一个月 } pt.submit_o.u1 = encodeURIComponent(pt.s_url); //成功url 必须 pt.submit_o.from_ui = 1; pt.submit_o.fp = "loginerroralert"; pt.submit_o.device = pt.deviceType; //设备类型 pt.submit_o.aid = pt.appid; //接入业务的appid 必须 if (window.ptui_daid) { pt.submit_o.daid = window.ptui_daid; //接入业务的appid 必须 } if (window.ptui_pt_qzone_sig == "1") { pt.submit_o.pt_qzone_sig = 1; } if (window.ptui_pt_ttype == "1") { pt.submit_o.pt_ttype = "1"; } if (window.ptui_pt_light == "1") { pt.submit_o.pt_light = "1"; } if (window.ptui_pt_3rd_aid) { pt.submit_o.pt_3rd_aid = window.ptui_pt_3rd_aid; } pt.submit_o.ptredirect = pt.target; pt.submit_o.h = 1; pt.submit_o.g = 1; //加盐了 pt.submit_o.pt_uistyle = window.ptui_style; if (window.ptui_kf_csimc != "0" && window.ptui_kf_csimc) { pt.submit_o.csimc = ptui_kf_csimc; pt.submit_o.csnum = ptui_kf_csnum; pt.submit_o.authid = ptui_kf_authid; } pt.submit_o.regmaster = window.ptui_regmaster; var param = pt.object2param(pt.submit_o); //如果验证码为空(需要验证码),跳到验证码页面 if (!vcode) { pt.showVcode(); pt.isSubmiting = false; //提交结束 } else { console.log('login--',vcode) pt.checkNetwork(); pt.startLoading(); var cgi = pt.isHulian ? 'pt_open_login' : 'login'; var url = pt.loginUrl + cgi + "?" + param; //这里延迟100ms发出请求,因为有人说这样能解决他们的bug,只能试试了 setTimeout(function(){ if(cgi === 'login'){ // 如果是login,先存起来备用 pt.smsLoginUrl = url } $.http.loadScript(url); //回调 ptuiCB方法 },100) } return false; }, smsSubmit: function(){ // pt.submit('sms') var url = pt.smsLoginUrl pt.isloading = true if(url){ if($.cookie.get("pt_sms")){ url += '&pt_sms_code='+ $.cookie.get("pt_sms") } $.http.loadScript(url); } }, /** * 用户点击确定,jsonp回调方法 * * @param ret 登录状态主信息 0 成功 * @param extret 登录状态附加信息 * @param url 登录成功的跳转地址 * @param redirect 跳转方式 0:self 1:top 2:parent 手机端没用 * @param Mmsg 登录信息 * @param nick 登录成功的号码的昵称 */ cb: function(ret, extret, url, redirect, Mmsg, nick) { pt.isSubmiting = false; //提交结束 if (pt.qrcode.used && [0, 65, 66, 67].indexOf(+ret) == -1) { // 上报二维码异常 $.report.monitor('2586869'); } switch (+ret) { case 0: clearInterval(pt.qrcode.clock); //如果自动登录,则保存到本地存储, var loginUin = pt.uInput && pt.uInput.value; //输入的帐号 pt.saveLastUin(loginUin || ""); //密保模版 if (url.indexOf("/cgi-bin/mibao_vry") > -1) { url += "&style=" + pt.style; } if (pt.isOffice && window.mqq && mqq.invoke) // 通知手Q mqq.invoke("QQOfficeOpen", "checkApp", { appId: window.ptui_pt_3rd_aid }); if (pt.qrcode.used) { pt.qrcode.done = true; $.report.monitor('2136878'); } pt.redirect(redirect, url); return; case 4: //验证码错误 pt.changeCodeImg(); break; case 65: // 二维码已失效 clearInterval(pt.qrcode.clock); $.report.monitor('2586868'); if (window.ptui_tab) { $.css.show($('qr_invalid')); if ($.bom.query("autorefresh") == "1") { $('qr_invalid').click(); return; } } else pt.showErr("一键登录超时,请重试。", 1000 * 1000); return; case 66: case 67: return; case 10010: // sms 验证码错误 pt.smsIframe.postMessage({msg:'smsError'}) break case 10009: $.cookie.set('pt_sms_phone',Mmsg,window.location.host, '/', 1000*60) var ptdrvs = $.cookie.get('ptdrvs') pt.smsPtdrvs = ptdrvs var appid = $.url.getParam('appid') var uin = $.cookie.get('pt_loginuin') || pt.uInput.value var Iframe = $.iframe() Iframe.init({ name:'verify', id:'verify', url: "https://ui.ptlogin2.qq.com/web/verify/iframe?uin=" + uin + "&appid=" + appid, iframeStyle:'width: 100vw;height: 100vh;margin: 0px auto;position: absolute;top: 0;border: none;z-index:10', smsSubmitEvent: pt.smsSubmit }) pt.smsIframe = Iframe break default: clearInterval(pt.qrcode.clock); //其他错误返回我们的页面 pt.go_back(); } //锁定帐号的时候不展示手机号入口 if (ret == 3 && !pt.is_oversea && [9, 35, 42].indexOf(parseInt(window.ptui_style)) !== -1 && !pt.lockedAccount){ pt.alert.show(Mmsg + '
    ' + STR_LANG.password_error_tips); //密码错误需要弹窗 }else if(ret == 10010 || ret == 10009){ ; } else{ pt.showErr(Mmsg); } }, /** * jsonp回调方法,判断是否需要验证码 * * @param ret 0:不需要验证码 1:需要验证码 * @param code 需要验证码时,为加密串,拉取验证码需要带上 * 不需要用户填验证码时,需要自动带上的验证 */ cb_checkVC: function(ret, code, salt, verifysession, isRandSalt) { //code 原来获取验证码的时候需要带上,参数名为vc_type //ret 0:正常不需要验证码;1:安全中心需要验证码;2:uin不存在;3:check内部错误 switch (ret + '') { case '0': pt.vcode = code || "abcd"; pt.verifysession = verifysession; break; case '1': pt.vcode = ''; pt.cap_cd = code; break; case '2': case '3': break; default: break; } if (ret == 2) { pt.showErr(pt.lang.err_uin); return; } if (ret == 3) { pt.showErr(pt.checkErr[ptui_lang]); return; } pt.salt = salt; pt.isRandSalt = isRandSalt; //提交的时候根据验证码判断是否需要提交到后台 pt.submit(pt.vcode) }, /** * 到后台查询是否需要加载验证码,并在回调函数中确定是否提交 * @param 是否快速登录 */ check: function(is_qlogin) { //避免多次提交 if (pt.isSubmiting) { return; } pt.is_qlogin = is_qlogin; //先前台验证 普通登录 if (!pt.is_qlogin) { if (!pt.checkValidate()) { clearTimeout(pt._timer); pt.endLoading(); return; } } var uin = ""; //如果是快速登录,帐号和密码 if (is_qlogin) { uin = pt.login_uin; //uin } else { uin = pt.needAt ? pt.needAt : pt.uInput.value; //uin } var url = pt.checkUrl + "pt_tea=2&uin=" + uin + "&appid=" + pt.appid + "&ptlang=" + pt.lang_num + "®master=" + window.ptui_regmaster + "&pt_uistyle=" + pt.style + "&r=" + Math.random(); if (window.TDC && TDC.getInfo && TDC.getInfo().tokenid) url += "&pt_jstoken=" + TDC.getInfo().tokenid; $.http.loadScript(url); // 回调cb_checkVC return; }, //检查uin和密码合法性 checkValidate: function() { var f_u = pt.is_oversea ? $('phone') : pt.uInput; //帐号输入框 var f_p = pt.is_oversea ? $('password') : pt.pInput; //密码输入框 var u = f_u.value; if (pt.is_oversea) { u = '00' + $('country-code').innerHTML.replace(/[^0-9]/, '') + u; u = u.replace('0086', ''); //国内手机号不需要加国家码 } if (f_u.value == "") { pt.showErr(pt.lang.no_uin, function() { f_u.focus(); }); //"你还没有输入帐号!" return false; } if (!pt.checkQQUin(u)) { pt.showErr(pt.lang.err_uin, function() { f_u.focus(); }); //"请输入正确的帐号!" return false; } f_u.value = $.str.trim(f_u.value); if (f_p.value == "") { pt.showErr(pt.lang.no_password, function() { f_p.focus(); }); //"你还没有输入密码!" return false; } return true; }, /** * 检查QQ用户帐号是否合法(号码和email和中文) */ checkQQUin: function(qquin) { if (qquin.length == 0) return false; qquin = $.str.trim(qquin); pt.needAt = ""; var tmp = $.check; if ($.check.is_weibo_appid(pt.appid)) { if (tmp.isQQ(qquin) || tmp.isMail(qquin)) { return true; } else if (tmp.isNick(qquin) || tmp.isName(qquin)) { //短昵称和中文帐号前加@ pt.needAt = "@" + encodeURIComponent(qquin); return true; } else if (tmp.isPhone(qquin)) { //手机号码前加@ pt.needAt = "@" + qquin.replace(/^(86|886)/, ""); return true; } else if (tmp.isSeaPhone(qquin)) { pt.needAt = "@00" + qquin.replace(/^(00)/, ""); if (/^(@0088609)/.test(pt.needAt)) { pt.needAt = pt.needAt.replace(/^(@0088609)/, "@008869"); //碰到0088609开头的前端统一修正为008869 by harlantu } return true; } pt.needAt = ""; } else { //其他 if (tmp.isQQ(qquin) || qquin.match(/@/)) { //这里只要包含@就认为是邮箱 避免重复添加@qq.com return true; } if (tmp.isPhone(qquin)) { pt.needAt = "@" + qquin.replace(/^(86|886)/, ""); return true; } if (tmp.isForeignPhone(qquin)) { pt.needAt = "@" + qquin; } //正常情况下不是qq号/邮箱/手机的都认为是邮箱名 pt.uInput.value = qquin + "@qq.com"; return true; } //国外手机 if (tmp.isForeignPhone(qquin)) { pt.needAt = "@" + qquin; return true; } if (tmp.isPaipaiDuokefu(qquin)) { return true; } return false; }, //检查验证码的合法性 checkVcode: function() { var vcode = $("vcode_input"); if (vcode.value == "") { pt.showErr(pt.lang.no_code); //"你还没有输入验证码!" vcode.focus(); return false; } if (vcode.value.length < 4) { pt.showErr(pt.lang.less_code); //"请输入完整的验证码!" vcode.focus(); vcode.select(); return false; } if (!(/^[a-zA-Z0-9]+$/.test(vcode.value))) { pt.showErr(pt.lang.err_code); //"请输入正确的验证码!" vcode.focus(); vcode.select(); return false; } return true; }, //点击头像 clickHeader: function(event, force) { event.preventDefault(); if ((pt.isWtlogin || window.ptui_style == 35) && !force) return var pNode = event.currentTarget; var uin = pNode.getAttribute("id"); var type = pNode.getAttribute("type"); pt.login_uin = uin; pt.login_pwd = pNode.getAttribute("pwd"); switch (type + "") { case "1": //普通登录 pt.check(true); break; case "2": //qq浏览器快速登录 pt.qlogin_submit(); break; case "3": //授权登录 pt.authlogin_submit(); break; case "4": //互联登录头像 pt.cookielogin_submit(); break; default: pt.check(true); } }, //获取头像的回调函数,jsonp调用 //{"uin":"uin","url":"url"} setHeader: function(json) { //列表生成了,只需要修改头像地址即可 for (var o in json) { if (json[o].url != "" && o != "") { if ($("img_" + o)) { $("img_" + o).src = json[o]; } } } pt.hideURLBar(); }, //拉取头像 initFace: function() { var qlogin_list_data = pt.qlogin_list_data; var length = qlogin_list_data.length; var protocol = pt.isHttps ? "https://ssl." : "http://"; for (var i = 0; i < length; i++) { $.http.loadScript(protocol + "ptlogin2." + pt.domain + "/getface?appid=" + pt.appid + "&imgtype=3&encrytype=0&devtype=1&keytpye=0&uin=" + qlogin_list_data[i].uin + "&r=" + Math.random()); } }, //拉取头像错误处理 face_error: function(img) { if (img.src != pt.default_face_url) { img.src = pt.default_face_url; } return false; }, //获取长字符串的缩略字符,中间加... getShortWord: function(element, str, width) { str = str ? str : ""; var appendStr = "..."; element.innerHTML = str; if (element.clientWidth <= width) { } else { var len = str.length; var harfLen = Math.ceil(len / 2); for (var i = 0; i < harfLen; i++) { var left = str.substring(0, harfLen - i) var right = str.substring(harfLen + i, len); element.innerHTML = left + appendStr + right; if (element.clientWidth <= width) { element.title = str; break; } var right = str.substring(harfLen + i + 1, len); element.innerHTML = left + appendStr + right; if (element.clientWidth <= width) { element.title = str; break; } } } element.style.width = width + "px"; }, /** * 刷新验证码图片 */ changeCodeImg: function() { if (pt.new_vcode) {} else { var img = $("vcode_img"); var domain = pt.domain; var verifycodeUrl = (pt.isHttps ? "https://ssl." : "http://") + "captcha." + domain + "/getimage"; //qq.com的https走安全中心的 if (pt.isHttps && domain != "qq.com" && domain != "tenpay.com") { verifycodeUrl = "https://ssl.ptlogin2." + domain + "/ptgetimage"; } verifycodeUrl += ("?aid=" + pt.appid + "&uin=" + pt.login_uin + "&v=" + Math.random()); img.src = verifycodeUrl; } }, newVCFirst: true, //显示验证码页面 showVcode: function() { //针对简体中文和支持postMessgae的切换到新版验证码 if (pt.new_vcode) { $("content").style.display = "none"; $("new_vcode").style.display = "block"; if (pt.newVCFirst) { pt.newVCFirst = false; capInit($('new_vcode'), { callback: pt.VCCallback, showHeader: true, uin: pt.login_uin, capcd: pt.cap_cd }); } else { capRefresh({ uin: pt.login_uin, capcd: pt.cap_cd }); } pt.ptui_notifySize(); } else { $("login").style.display = "none"; $("vcode").style.display = "block"; //绑定验证码区域事件 pt.bindVcodeEvent(); //拉取验证码 pt.changeCodeImg(); } pt.hideURLBar(); $("btn_app_down") && $.css.hide("btn_app_down"); }, go_back: function() { $("content") && ($("content").style.display = "block"); $("login") && ($("login").style.display = "block"); $("vcode") && ($("vcode").style.display = "none"); $("new_vcode") && ($("new_vcode").style.display = "none"); }, //提交验证码 submitVcode: function() { // todo remove it //避免多次提交 if (pt.isSubmiting) { return; } if (!pt.checkVcode()) { return false; } pt.submit_o.verifycode = $("vcode_input").value.toUpperCase(); //验证码 必须 var pwd = ""; //原始密码 var isMd5 = false; if (window.openSDK && openSDK.md5Pwd && openSDK.result == 0) { pwd = openSDK.md5Pwd; isMd5 = true; } else { pwd = pt.pInput.value; //原始密码 isMd5 = false; } pt.submit_o.p = $.Encryption.getEncryption(pwd, pt.salt, pt.submit_o.verifycode, isMd5); //要提交给后台的密码形式 pt.submit_o.pt_randsalt = pt.isRandSalt || 0; if (window.TDC && TDC.getInfo && TDC.getInfo().tokenid) pt.submit_o.pt_jstoken = TDC.getInfo().tokenid; var param = pt.object2param(pt.submit_o); var cgi = pt.isHulian ? 'pt_open_login' : 'login'; var url = (pt.isHttps ? "https://ssl." : "http://") + "ptlogin2." + pt.domain + "/" + cgi + "?" + param; $.http.loadScript(url); //回调 ptuiCB方法 }, /** * [submitNewVcode 提交新的验证码] * @param {[type]} data [description] * @return {[type]} [description] */ submitNewVcode: function(data) { //$.cookie.set("verifysession", data.sig, pt.domain); //把cookie当成验证码图片的cookie set pt.submit_o.verifycode = data.randstr.toUpperCase(); //验证码 必须 pt.submit_o.pt_vcode_v1 = 1; pt.submit_o.pt_verifysession_v1 = data.ticket; var pwd = ""; //原始密码 var isMd5 = false; if (window.openSDK && openSDK.md5Pwd && openSDK.result == 0) { pwd = openSDK.md5Pwd; isMd5 = true; } else { pwd = pt.pInput.value; //原始密码 isMd5 = false; } pt.submit_o.p = $.Encryption.getEncryption(pwd, pt.salt, pt.submit_o.verifycode, isMd5); //要提交给后台的密码形式 pt.submit_o.pt_randsalt = pt.isRandSalt || 0; if (window.ptui_kf_csimc != "0" && window.ptui_kf_csimc) { pt.submit_o.csimc = ptui_kf_csimc; pt.submit_o.csnum = ptui_kf_csnum; pt.submit_o.authid = ptui_kf_authid; } var param = pt.object2param(pt.submit_o); var cgi = pt.isHulian ? 'pt_open_login' : 'login'; var url = (pt.isHttps ? "https://ssl." : "http://") + "ptlogin2." + pt.domain + "/" + cgi + "?" + param; if(cgi === 'login'){ pt.smsLoginUrl = url } pt.checkNetwork(); pt.startLoading(); $.http.loadScript(url); //回调 ptuiCB方法 }, /* 互联授权页面回调实现 */ open: { timer: -1, authListDone: false, waiting: function(what, forFn) { if (!forFn) return; switch (what) { case 'authlist': if (pt.open.authListDone) forFn(); else pt.open.waiting.authlistFn = forFn; break; case 'authdata': if (pt.submit_o.openlogin_data) { forFn(); } else { pt.open.getAuthData(); pt.open.waiting.authdataFn = forFn; } break; } }, authListReady: function(opt) { pt.open.authListDone = true; if (pt.open.waiting.authlistFn) { pt.open.waiting.authlistFn(); pt.open.waiting.authlistFn = null; } opt = opt || {}; var superkey = window.ptui_daid && parseInt($.cookie.get("supertoken")); if (superkey) opt.superkey = 1; // 触发柔性逻辑 if (opt.pt_flex) window.pt_flex = 1; if (opt.skey) opt.skey = +opt.skey; window.pt_skey_valid = opt.skey; if ((opt.skey == 1 || opt.superkey) || pt.qqBrowserInfo) { pt.openCookieInfo = opt; pt.refreshQloginUI(); pt.initFace(); } //拉取完成之后立即拉取opendata if (window.pt_flex) pt.open.getData({ value: location.search.substr(1) + "&pt_flex=1" }); else xMsg.call("connect", "getData", {}, pt.open.getData); if (window.ptui_tab) xMsg.call("connect", "hideList", {}); }, setFrameHeight: function(opt) {}, getData: function(data) { clearTimeout(pt.open.timer); pt.submit_o.openlogin_data = encodeURIComponent(data.value); /* 就目前来说,只在一键登录处 just waiting authdata, 所以处理完及时返回,避免多余操作 */ if (pt.open.waiting.authdataFn) { pt.open.waiting.authdataFn(); pt.open.waiting.authdataFn = null; return; } }, getAuthData: function() { if (!pt.open.authListDone){ // fix个bug: // 看了一下逻辑,在2s内,授权列表还没加载出来,就立刻点击“一键登录”,会触发这个提示。但实际上等列表加载完,会自动执行回调,跳登录的。 // 就是过了2s后,授权列表没加载出来,也会自动触发柔性策略,自动执行回调,依然能成功登陆,所以没必要出现“授权列表加载失败”提示了 // 那就把这句话注释掉好了 // return pt.showErr("授权列表加载失败"); return; } pt.open.timer = setTimeout(function() { pt.showErr("授权信息获取失败"); }, 3000); }, fillAppInfo: function(res) { // cgi get_app_basicinfo jsonp callback if (res && res.retcode == 0 && res.result && res.result.pc) { var icon = res.result.pc.Logo100; if (icon && icon.indexOf("http://") > -1) icon = icon.replace("http://", "https://"); $("app_logo").style.backgroundImage = "url(" + icon + ")"; $("app_alias").innerHTML = res.result.pc.AppAlias; } }, loadAppInfo: function() { $.http.loadScript("//openmobile.qq.com/api/get_app_info_by_id?callback=get_app_basicinfo&appid=" + window.ptui_pt_3rd_aid); var path = window.ptui_pt_3rd_aid.toString(); while (path.length > 8) path = path.substr(path.length - 8); while (path.length < 8) path = '0' + path; path = path.replace(/(\w{2})/g, '$1/'); var adimgurl = '//i.gtimg.cn/open/app_icon/' + path + window.ptui_pt_3rd_aid + '_android_ad_0.jpg' console.log(adimgurl) var img = new Image; img.onload = function() { console.log(img); var appinfo = document.getElementsByClassName('appinfo')[0] if (!appinfo) return; img.style.width = '100%'; img.style.borderTopLeftRadius = '0.5rem'; img.style.borderTopRightRadius = '0.5rem'; appinfo.style.padding = 0; appinfo.style.fontSize = 0; // 避免有字体导致多出一行 appinfo.appendChild(img); var app_logo = $('app_logo'), app_alias = $('app_alias'), app_comment = $('app_comment'); if (app_logo) app_logo.style.display = 'none'; if (app_alias) app_alias.style.display = 'none'; if (app_comment) app_comment.style.display = 'none'; } img.src = adimgurl; } }, /** * [crossMessage 跨域通信] * @param {[type]} messasge [description] * @return {[type]} [description] */ crossMessage: function(message) { //支持html5的消息传递 if (typeof window.postMessage != "undefined") { var messasgeStr = $.str.json2str(message); window.parent.postMessage(messasgeStr, "*"); } }, ////////////////////////////以下为一些调用业务测的接口 //通知父窗口关闭 ptui_notifyClose: function(e) { e && e.preventDefault(); var messasge = {}; messasge.action = "close"; pt.crossMessage(messasge); }, ptui_notifySize: function(div) { var message = {}; message.action = "resize"; if (div) { var obj = $(div); message.width = obj.offsetWidth || 1; message.height = obj.offsetHeight || 1; } else { // todo 出现拼图验证码,希望能回传全屏大小 message.width = 320; message.height = 441; } pt.crossMessage(message); }, //记录登录框访问次数,避免手Qkey过期时和业务之间死循环 accessCount: function() { if (!$.localStorage.isSupport()) return 0; return parseInt($.localStorage.get('accessCount')); }, access: function() { if (!$.localStorage.isSupport()) return; try { var count, lasttime, now; now = new Date(); lasttime = new Date(); lasttime.setTime($.localStorage.get('lastAccessDate')); if (Math.abs(now - lasttime) < 30 * 1000) { count = parseInt($.localStorage.get('accessCount')) + 1; } else { count = 1; } $.localStorage.set('accessCount', count); $.localStorage.set('lastAccessDate', now.getTime()); } catch (e) { $.localStorage.set('accessCount', 1); $.localStorage.set('lastAccessDate', new Date().getTime()); } }, //style42用 switchpwd: function() { $.css.show($('pwdlogin')); pt.uInput && pt.uInput.focus(); $.css.hide($('qrlogin')); $.css.show($('switch')); $.css.show($('zc_feedback')); pt.qrcode && clearInterval(pt.qrcode.clock); }, switchqr: function() { $.css.hide($('pwdlogin')); $.css.show($('qrlogin')); $.css.hide($('switch')); $.css.hide($('zc_feedback')); pt.qrcode.get(0); }, //刷新qlogin页面,仅当处于快速登录页面 或切换到快速登录 refreshQloginUI: function() { if (pt.isOffice) pt.build_office_qlogin(); else if (!pt.isWtlogin && !pt.is3gNews) pt.build_qlogin_list(); }, mqqCanQLogin: function() { var ua = navigator.userAgent, mqq = ua.match(/QQ\/(\d\.\d\.\d)/i); if (mqq && mqq[1] >= "5.9") { return true; } return false; } }; /** * alert 提示能力 */ pt.alert = (function(){ let alertBackground=null; let alertDiv = null return { show: function(message) { if (!alertBackground) { alertBackground = document.createElement("div"); alertBackground.className = 'qui-dialog-mask'; } if (!alertDiv) { alertDiv = document.createElement('div'); alertDiv.className = 'qui-dialog-box'; } alertDiv.innerHTML = '
    ' + message + '
    ' + window.STR_LANG.close + '
    '; document.body.appendChild(alertBackground); document.body.appendChild(alertDiv); }, hide: function() { document.body.removeChild(alertBackground); document.body.removeChild(alertDiv); } } })() pt.qrcode = { CGI: 'ptqrlogin', used: false, done: false, clock: 0, get: function(type) { var loginName = "ptqrshow"; var proto = pt.isHttps ? "https://ssl." : "http://"; var url = proto + "ptlogin2." + pt.domain + "/" + loginName + "?s=8&e=0&"; url += "appid=" + pt.appid + "&type=" + type + "&t=" + Math.random(); if (pt.daid) { url += "&daid=" + pt.daid; } if (window.ptui_pt_3rd_aid) { // for 互联 url += "&pt_3rd_aid=" + window.ptui_pt_3rd_aid; } if (window.ptui_regmaster) { url += '®master=' + window.ptui_regmaster; } clearInterval(pt.qrcode.clock); pt.checkNetwork(); if (type == 1) { $.http.loadScript(url); // ptui_qrcode_CB } else { $.e.add($('qrimg'), 'error', function() { $.css.show('qr_invalid'); }); $.e.add($('qrimg'), 'load', function() { clearTimeout(pt._timer); pt.qrcode.polling(); }); $('qrimg').src = url; } pt.qrcode.used = true; pt.qrcode.done = false; $.report.monitor('2136877'); }, polling: function(qrcode) { clearInterval(pt.qrcode.clock); pt.qrcode.clock = setInterval(function() { var qrUrl = pt.qlogin_submit(pt.qrcode.CGI); $.http.loadScript(qrUrl + "&r=" + Math.random()); }, 3000); if (qrcode) { var schema = pt.isIos ? "wtloginmqq3:" : "wtloginmqq:"; var dstUrl = schema + '//ptlogin/qlogin?qrcode=' + encodeURIComponent(qrcode) + '&schemacallback=' + encodeURIComponent('weixin://'); openApp(dstUrl); } } }; function ptui_qrcode_CB(res) { clearTimeout(pt._timer); res && (res.ec == 0) && pt.qrcode.polling(res.qrcode); } function weixin_sig_cb() { var callback = function() { WeixinJSBridge.invoke('getInstallState', { "packageName": "com.tencent.mobileqq", "packageUrl": "mqq://" }, function(res) { var err_msg = res && res.err_msg; var canOnekey; if (err_msg && (canOnekey = err_msg.match(/:yes(?:_(\d+))?/))) { var androidVersionCode = 336; //pt_no_onekey用于关闭一键登录 if ((pt.isIPhone || (pt.isAndroid && canOnekey[1] >= androidVersionCode))&& $.bom.query('pt_no_onekey')!=='1') pt.showOneKey('justshow'); } }); }; if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") { callback(); } else { if (document.addEventListener) { document.addEventListener("WeixinJSBridgeReady", callback, false); } else if (document.attachEvent) { document.attachEvent("WeixinJSBridgeReady", callback); document.attachEvent("onWeixinJSBridgeReady", callback); } } } /* * jsonp形式的调用,不可转移命名空间 * ret 0:不需要验证码 1:需要验证码 * code 需要验证码时,为加密串,拉取验证码需要带上 * 不需要用户填验证码时,需要自动带上的验证码 * * @param {*} ptdrvs 这个用于在iframe内无法下发cookie的时候作为兜底逻辑 */ function ptui_checkVC(ret, code, salt, verifysession, isRandSalt,ptdrvs) { if (!pt.isloading) return; //check已经超时就不要处理了 clearTimeout(pt._timer); pt.endLoading(); window.pt_ptdrvs = ptdrvs || ''; //前面加个pt的前缀防止冲突 pt_ptdrvs if (window.openSDK && openSDK.getMD5FromNative) { openSDK.getMD5FromNative(function() { pt.cb_checkVC(ret, code, salt, verifysession, isRandSalt); }) } else { pt.cb_checkVC(ret, code, salt, verifysession, isRandSalt); } } /** * 刷新验证码,页面中有用到,暂不更改命名空间 */ function ptui_changeImg() { } /** * 登录提交后,回调函数,暂不更改命名空间 */ function ptuiCB(ret, extret, url, redirect, Mmsg, nick) { if (ret == 10005) { Mmsg = '为了帐号安全,请使用一键登录。'; if ($("onekey")) { pt.showOneKey(); } } if (ret != 0 && !pt.is_qlogin) { //QQ音乐帐号密码登录错误统计 qqMusicReport("33616396", 33616397); } if (!pt.isloading && !pt.qrcode.used) return; //已经超时就不要处理了 clearTimeout(pt._timer); try { pt.endLoading(); } catch (e) {} pt.cb(ret, extret, url, redirect, Mmsg, nick); } /** * 上报拉取验证码所需时间 * 页面中用到,暂不更改命名空间 */ function imgLoadReport() { } /** * 检验登录表单所有数据的合法性 * 此方法在点击登录的时候调用,页面中调用,暂不更改命名空间 */ function ptui_checkValidate() { return pt.checkValidate(); } /** * [ptui_auth_CB 授权回调函数] * @param {[type]} ret,url [description] * @return {[type]} [description] */ function ptui_auth_CB(ret, url) { switch (parseInt(ret)) { //显示授权页面 case 0: if (pt.isHulian) pt.setCookieLogin(); else pt.showAuth(url); break; //没有授权页面显示 case 1: if (pt.isHulian) { // pt.cancel_cookielogin(); break; } if (pt.mqqCanQLogin() && pt.accessCount() < 5) { //没有陷入死循环 var url = (pt.isHttps ? "https://ssl." : "http://") + "ptlogin2.qq.com/jump?clientuin=$UIN&clientkey=$KEY&keyindex=$KEYINDEX&u1=" + encodeURIComponent(pt.s_url); pt.redirect(pt.target, url); break; } break; //不显示授权页面直接跳转 case 2: if (pt.isHulian) { pt.setCookieLogin(); break; } var authUrl = url + "®master=" + window.ptui_regmaster + "&aid=" + window.ptui_appid + "&s_url=" + encodeURIComponent(pt.s_url); if (pt.low_login_enable == 1) { authUrl += "&low_login_enable=1&low_login_hour=" + window.ptui_low_login_hour; } if (window.ptui_pt_ttype == "1") { authUrl += "&pt_ttype=1"; } if (window.ptui_pt_light == "1") { authUrl += "&pt_light=1"; } pt.redirect(pt.target, authUrl); break; default: } pt.refreshQloginUI(); } /** * [ptuiCB description] * @param {String} ret [错误码] * @param {String} url [跳转url] * @param {String} msg [登录信息] */ function ptui_qlogin_CB(ret, url, msg) { switch (ret + '') { case '0': //top.location.href = url; pt.redirect(pt.target, url); break; case '5': if (MTT.refreshToken) { var clock = setTimeout(function() { pt.showErr(msg); }, 3000); MTT.refreshToken(pt.qqBrowserInfo.uin, function(data) { MTT.refreshToken = null; if (!data.stweb) return; $.report.monitor("624562"); clearTimeout(clock); pt.qqBrowserInfo.loginkey = data.stweb; pt.qlogin_submit(); }); $.report.monitor("624561"); } else { pt.showErr(msg); } break; default: $.report.nlog("qq浏览器快速登录失败," + ret, "443881", pt.qqBrowserInfo.uin); pt.showErr(msg); } } function canOpenqqUaCheck() { var iosbrowser = [ 'uc', 'baidu', 'weibo' ]; //ios不能打开手Q的浏览器 var androidbrowser = [ //安卓不能打开QQ的名单 // 'uc', // 'qq', // '2345', // 'sogou', // 'chrome', // 'liebao', 'weibo' ]; //手Q目前兼容了的浏览器,360算在chrome里,即android下可以打开手Q的浏览器,baidu安卓打不开 var browserType = null; var ua = navigator.userAgent.toLowerCase(); if (ua.indexOf('ucbrowser') > -1) { browserType = 'uc'; } else if (ua.indexOf('baidubrowser') > -1) { browserType = 'baidu'; } else if (ua.indexOf('mqqbrowser') > -1 || ua.indexOf('tencenttraveler') > -1) { browserType = 'qq'; } else if (ua.indexOf('liebao') > -1) { browserType = 'liebao'; } else if (ua.indexOf('2345browser') > -1) { browserType = '2345'; } else if (ua.indexOf('sogoumobilebrowser') > -1) { browserType = 'sogou'; } else if (ua.indexOf('weibo')> -1){//微博暂时屏蔽 browserType = 'weibo'; //这里注意,一定要最后判断chrome,因为其他app的ua里边也可能有chrome } else if (ua.indexOf('chrome') > -1) { //360,chrome都可以打开 browserType = 'chrome'; } else { browserType = 'other'; } console.log(browserType); if (pt.isAndroid) { if (androidbrowser.indexOf(browserType) > -1) { return false; } else { return true; } } else if (pt.isIos) { if (iosbrowser.indexOf(browserType) > -1) { return false; } else { return true; } } return false; } OneKey.ERRMSG = { "2052": "使用一键登录,请安装最新版本的QQ手机版", "1028": "使用一鍵登錄,請安裝最新版本的QQ手機版", "1033": "Have the latest Mobile QQ?", "10000": "当前应用不支持QQ快速登录,建议使用其他浏览器尝试。" }; function OneKey(dstUrl) { OneKey.done = false; OneKey.TIMEOUT = 3000; if (pt.isWX) { OneKey.TIMEOUT = 5000; OneKey.qrcode = true; for (var lang in OneKey.ERRMSG) { if (OneKey.ERRMSG.hasOwnProperty(lang)) OneKey.ERRMSG[lang] = OneKey.ERRMSG[lang].replace(/([^<]*)<\/a>/, "$1"); } pt.qrcode.get(1); } else { setTimeout(function() { openApp(dstUrl); }, 100); } } /** * [openApp 优化拉起QQ手机版] * @param {String} appScheme QQ手机版的scheme * @param {Function} [timeOutCallback] 拉起超时的回调,超时不一定失败,也可能是用户主动切回来 * @param {Function} [failCallback] 拉起失败的回调 */ function openApp(appScheme, timeOutCallback, failCallback) { if (OneKey.done) return; if (pt.isLaunching) return; pt.isLaunching = true; var timeout = OneKey.TIMEOUT; var startDate = new Date(); pt.btnOnekey.innerHTML = STR_LANG.onekeying; setTimeout(function() { timeOutCallback && timeOutCallback(); pt.isLaunching = false; pt.btnOnekey.innerHTML = STR_LANG.onekey; if (pt.qrcode.done) return; if (new Date() - startDate <= timeout + 200) { // 200 毫秒是误差 failCallback && failCallback(); //停留在当前页面,给出错误提示 if (!canOpenqqUaCheck()) { pt.showErr(OneKey.ERRMSG["10000"], 5000); //浏览器原因拉起手Q失败停留在当前页面,给出错误提示 } else { pt.showErr(OneKey.ERRMSG[ptui_lang], 5000); //停留在当前页面,给出错误提示 } $.report.nlog("callApp failed:" + navigator.userAgent, 424783); qqMusicReport('83886593', 33616387); //QQ音乐一键登录失败量 } }, timeout); // 为什么折腾?因为至少android微信不延时打开的话,按钮的文案不会更新 if (pt.isWX && pt.isAndroid) setTimeout(function() { doOpenApp(appScheme) }, 100); else doOpenApp(appScheme); } /** * * @param {String} appScheme 要 使用的schema * @param {Boolean} forceLocation 这个是为了兼容老版本微信,在使用jsapi跳转失败时,用传统的方法来跳转 */ function doOpenApp(appScheme, forceLocation) { var res = $.detectBrowser(); var browser = res[0] && res[0].toLowerCase(); var schemas = {}; //只有微信才走这个逻辑,企业微信不走这个逻辑 if (pt.browser.isWX && !pt.browser.isWorkWX && !forceLocation) { $.invokeWXAPI('launchApplication', { "schemeUrl": appScheme }, function(res) { var err_msg = res && res.err_msg; console.log(err_msg) if (err_msg != 'launchApplication:ok') { console.log('try again') //可能是老版本微信 再用老方式试一次 doOpenApp(appScheme, true); } }) } else if (pt.isAndroid) { var openStyle = res[1] || "location"; if (browser) { schemas = { 'ucbrowser': 'ucweb://', 'meizu': 'mzbrowser://', 'liebaofast': 'lb://', 'baidubrowser': 'bdbrowser://', 'baiduboxapp': 'bdapp://', 'qihoobrowser': 'qihoobrowser://', 'chrome': 'googlechrome://', 'sogoumobilebrowser': 'SogouMSE://', '2345browser': 'browser2345://', 'now/' : 'tnow://openpage/web?url=' }; if (schemas[browser]) appScheme += "&schemacallback=" + encodeURIComponent(schemas[browser]); } switch (openStyle) { case "iframe": if (openApp.iframe) { openApp.iframe.src = appScheme; } else { openApp.iframe = document.createElement("iframe"); openApp.iframe.src = appScheme; openApp.iframe.style.display = "none"; document.body.appendChild(openApp.iframe); } openApp.flag = "iframe"; break; case "open": var win = window.open(appScheme, "_blank"); setTimeout(function() { win.close(); }, 0); openApp.flag = "open"; break; case "location": location.href = appScheme; openApp.flag = "location"; break; } } else { //IOS or others if (browser) { schemas = { 'ucbrowser': 'ucbrowser://', 'liebao': 'lb://u/100/', 'baiduboxapp': 'baiduboxapp', //ios百度浏览器目前缺少schema,暂时不考虑 'qihoobrowser': 'qihoobrowser://mse.360.cn/app?q=', 'sogoumobilebrowser': 'SogouMSE://openurl?url=', 'chrome': 'googlechrome', '2345browser': 'browser2345://', 'now/' : 'tnow://openpage/web?url=' }; if (schemas[browser]) appScheme += "&schemacallback=" + encodeURIComponent(schemas[browser]); } if (pt.isInIframe){ // ios 9无法在iframe中拉起APP pt.browser.setLocation(appScheme, window.top); }else{ pt.browser.setLocation(appScheme, window) } openApp.flag = "location"; } } /** * 把跟native调用相关的逻辑放到pt.nativeApi这个命名空间下 */ pt.nativeApi = { doOpenApp : doOpenApp } /** * [ 互联opensdk密码加密] * @return {[type]} [description] */ var openSDK = (function() { var md5Pwd = ""; var result = 0; var sn = 0; var callbackArray = []; var curPosFromJS = function(pos, callback) { sn = 1; if (typeof callback == "function") { callbackArray[sn] = callback; } //pt.showErr("curPosFromJS,pos="+pos); window.location.href = "jsbridge://SecureJsInterface/curPosFromJS/" + sn + "/openSDKCallBack/" + pos; }; var isPasswordEdit = function(flag, callback) { sn = 2; if (typeof callback == "function") { callbackArray[sn] = callback; } //pt.showErr("isPasswordEdit,sn="+sn); window.location.href = "jsbridge://SecureJsInterface/isPasswordEdit/" + sn + "/openSDKCallBack/" + flag; }; var clearAllEdit = function(callback) { sn = 3; if (typeof callback == "function") { callbackArray[sn] = callback; } //pt.showErr("clearAllEdit,sn="+sn); window.location.href = "jsbridge://SecureJsInterface/clearAllEdit/" + sn + "/openSDKCallBack"; }; var getMD5FromNative = function(callback) { sn = 4; if (typeof callback == "function") { callbackArray[sn] = callback; } //pt.showErr("getMD5FromNative,sn="+sn); window.location.href = "jsbridge://SecureJsInterface/getMD5FromNative/" + sn + "/openSDKCallBack"; }; if (window.ptui_enablePwd == "1") { return { curPosFromJS: curPosFromJS, isPasswordEdit: isPasswordEdit, clearAllEdit: clearAllEdit, getMD5FromNative: getMD5FromNative, sn: sn, md5Pwd: md5Pwd, result: result, callbackArray: callbackArray } } })(); function openSDKCallBack(json) { var result = json.result; var md5 = json.data; var sn = json.sn; switch (sn) { case 4: openSDK.md5Pwd = md5; openSDK.result = result; //alert("md5="+openSDK.md5Pwd); openSDK.callbackArray[sn].call(); break; default: break; } } function get_app_basicinfo(res) { pt.open.fillAppInfo(res); } function ptui_wtlogin_CB(uin,sig) { clearInterval(pt.qrcode.clock); pt.isLoading && pt.endLoading(); if(!window.wtCB){ // 兼容and6奇怪的客户端bug // 这里安卓6下,腾讯视频的客户端有个wtCB无法注入的bug,这里暂时的兜底逻辑 by dariondiao 20190408 if(window.WTLogin && window.WTLogin.ptloginCallBack){ WTLogin.ptloginCallBack(uin,sig); }else{ pt.showErr('请安装手机QQ后再登录'); } console.log('wtCB不存在'); }else{ window.wtCB && window.wtCB.apply(window, arguments); console.log('wtCB存在'); } } //这里的代码只有在单元测试的时候会执行 if(typeof process!=='undefined' && process.env && process.env.UNITTEST==1){ module.exports = pt } //启动代码都在login_mobile_init.js里边,会合并进来 //20180129 add var hlhdFlag = false; //是否进行互联新版本登录模式灰度,条件为:1.在灰度名单中 2.在非手Q中 3.在style为35的情况下 var isMobileQQ = !!(typeof mqq != "undefined" && typeof mqq.QQVersion != "undefined" && mqq.QQVersion != 0 && !/Qzone/.test(navigator.userAgent)); if (window.ptui_style == 35 && window.hlhd_temp && !isMobileQQ) { hlhdFlag = true; } //启动登录页的主逻辑 pt.access(); pt.init(); // pt.isWX = true; // pt.showOneKey('justshow'); if (!window.hlhdFlag) { if ($.bom.query("pt_wxtest") !== '0' && pt.isWX) weixin_sig_cb(); //使用jsbridge 不用发起请求了 } else { pt.showOneKey(); } try { if (window._timePoints && window._timePoints.length > 1 && typeof(window.speedReportAR) == 'function') { window._timePoints[2] = Date.now(); //参数填入(appId, buzId, siteId, pageId, gray),其中 appId 是固定值20122 ,剩下的来自申请的 id //例如,校园圈主页的active点id为 21485-1-1-24,则填入 window.speedReportAR(20122, 21998, 1, 1); } } catch (err) { //console.log(err); } //20181129 add QQ音乐加上报 var url_appid = $.bom.query("appid") || ''; var qqMusicReport = function(appid, moinitorid) { if (url_appid == "83886593" && moinitorid) { $.report.monitor(moinitorid); } } qqMusicReport("83886593", 33616394); ///QQ音乐总量pv