[置顶] 小米js源码解析

通过逐行的分析,小米的骗局越来越清晰了。其实页面就30秒被提交一次。提交后获得一个js文件,其js文件的地址类似是http://tc.hd.xiaomi.com/hdget?callback=hdcontrol&_=hdget,然后

hdcontrol({
    "stime": 1378180861,
    "status": {
        "allow": false,
        "miphone": {
            "hdstart": true,
            "hdstop": false,
            "hdurl": "?_a=20130903_september_first_weeks&_op=choose",
            "duration": null,
            "pmstart": false
        },
        "mibox":


        {
            "hdstart": true,
            "hdstop": false,
            "hdurl": "?_a=20130903_september_first_weeks&_op=choose",
            "duration": null,


            "pmstart": false
        }
    }
})

这个文件竟然直接调用下面写的hdcontrol函数。还直接传了参。。。

e里面保存了隐藏的hdurl,如果大家知道url可以直接进入选择页面,当然请求的时候应该服务器要认可预定成功的判断。

所以,骗局在于页面重试是30秒才重新抢一次的,用户之后点多少次都没用。所谓的倒计时也是在骗人。

这个是一个url捉迷藏的游戏。

先去吃饭,下午继续。

如果真心想抢到小米的东西,开无数个窗口,然后点了抢购之后,安心等待30秒是一个好办法。如果有有一个页面抢到了,页面会自己跳转的。

function hdcontrol(e) {

        var c = e.status, //e.status是服务器端返回的一个json,最后分析这个json
        d = c.miphone.hdurl,
        b = c.mibox.hdurl,
        a = c.mitv.hdurl,
        f = e.d22a51 ? e.d22a51 * 0x3e8: 0x1388; //是5秒还是1秒,是一个问题, d22a51 是什么?
        if (CONFIG.proType === ”phone“ && d) { //你可以买手机了
            m.locationNext(d)
        } else {
            if (CONFIG.proType === ”box“ && b) { //你可以买盒子了
                m.locationNext(b)
            } else {
                if (CONFIG.proType === ”tv“&& a) { //你可以买电视了
                    m.locationNext(a)
                } else {
                    if (window.ajaxInter) {
                        clearTimeout(ajaxInter) //清除延时
                    };
                    ajaxInter = window.setTimeout(function() { 
                        getStatus.requestAgain() //设定重试的延时
                    },
                    f) //延时时间是1秒或者5秒
                }
            }
        };
        getPermit.hdStatus(e) //下面再看
    };
    function hdinfo(a) {
        var b = a.stime + (0x8 - new Date().getTimezoneOffset() / 0x3c * -0x1) * 0xe10; //服务器返回的当前时间
        servertime = b;  //结合时区存起来
        CONFIG.isBook = { //记录是否预订了
            phone: a.status.miphone.reg,
            tv: a.status.mitv.reg,
            box: a.status.mibox.reg
        };
        getPermit.hdStatus(a)
    };
    var getPermit = {
        hdStatus: function(c) {
            var a = c.status,
            e = (a.miphone.hdstart === false && a.miphone.hdstop === true) ? true: false, //查看返回结果,判断是否在购买活动期间,每次应该是10分钟左右。最少应该是5分钟,几分钟后,活动结束。
            b = (a.mibox.hdstart === false && a.mibox.hdstop === true) ? true: false, //盒子
            d = (a.mitv.hdstart === false && a.mitv.hdstop === true) ? true: false; //电视
            if (d || e || b) {
                window.clearTimeout(timeoutRequest); //获得服务器时间,如果不在活动内,就获取服务器时间
                m.$(”preLoad“).style.display = ”none“;
                if (window.getServerTime) {
                    window.clearInterval(getServerTime) 
                };
                m.$(”hdTipInfo“).style.display =”none“;
                m.$(”showMore“).style.display =”none“
            };
            if ((d && CONFIG.proType === ”tv“) || (e && CONFIG.proType === ”phone“) || (b && CONFIG.proType === ”box“)) {
                getStatus.boxy(false, ”“);
                htmlStr.getOverInfo(); //查看预订类型
                getStatus.boxy(true, ”-reg“)
            };
            if (d && e && b) {
                m.cookieXM(CONFIG.cookies.status, 0x1); //存储到cookie里面
                htmlStr.init(0x4) //4
            } else {
                if (d && e && !b) {
                    htmlStr.init(0x7) //7是买手机,电视
                } else {
                    if (d && !e && !b) {
                        htmlStr.init(0x5) //5是买电视
                    } else {
                        if (d && !e && b) {
                            htmlStr.init(0x8) //8是买盒子和电视
                        } else {
                            if (!d && e && b) {
                                htmlStr.init(0x9) //9是买手机,盒子
                            } else {
                                if (!d && !e && b) {
                                    htmlStr.init(0xa) //10是盒子
                                } else {
                                    if (!d && e && !b) {
                                        htmlStr.init(0x6) //是手机
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

    },

//

    getStatus = {
        jsonInter: function(c, d, a) {
            var b = new Date().getTime(); //构建一个js块,其实小米通过js块的src=部分,插入js块后,向服务器提交购买请求
            m.creatJs(c + b, d, a)
        },
        init: function() {
            var a = this;
            if (m.cookie(CONFIG.cookies.status)) {
                m.$(“preLoad“).style.display =”none”;
                m.$("hdTipInfo ").style.display = "none";
                m.$("showMore").style.display = "none";
                htmlStr.init(0x4); //4,都买。。
                return false
            };
            this.jsonInter(CONFIG.srcs.hdinfo, “hdinfo”, false); //在页面初始化完毕的时候,就查询信息,比如服务器时间,是否登录,是否预约
            getServerTime = window.setInterval(function() {
                if (typeof(servertime) !== “undefined”) {
                    window.clearTimeout(timeoutRequest);
                    m.$(“preLoad”).style.display = “none”;
                    a.jugeStatus(); //下面再分析
                    window.clearInterval(getServerTime)
                }
            },
            CONFIG.timer.server); //0.1秒之后就执行
            timeoutRequest = setTimeout(function() {
                m.$(“preLoad”).innerHTML = “ <p>抱歉,网络拥堵无法连接服务器。由于访问人数太多导致服务器压力山大,请刷新页面重试~”;
                m.$(“preLoad”).style.cssText =“background:none;” 
            },
            CONFIG.timer.timeout) //5秒后是超时了。
        },
        jugeStatus: function() { //举个?
            var d = this,
            c = servertime * 0x3e8, //服务器时间*1000
            b = CONFIG.startDate, //抢购开始时间
            a = b - CONFIG.preLogMin * 0xea60; //30*60000是30分钟
            Util.resetServertime(); //重新读取服务器时间,校准时间,确实会出现时间不准的现象
            if (c < a) { //服务器时间还没到
                htmlStr.init(0x1); //显示没开始抢购
                d.timeOut()
            } else {
                if (c >= a && c < b) { //当进入最后30分钟
                    htmlStr.init(0x2); //进入状态2
                    if (m.cookie(CONFIG.cookies.userid)) {
                        d.timeOut()
                    }
                } else {
                    if (c >= b) {
                        htmlStr.init(0x3); //到点了,开始抢购
                        if (window.resetTime) {
                            clearInterval(resetTime)
                        };
                        m.$(“hdTipInfo”).style.display =“none”; //倒计时版消失
                        m.$(“showMore”).style.display = “ none ”
                    }
                }
            }
        },
        timeOut: function() { //如果没到时间,继续倒计时
            var a = this;
            a.setRemainTime(); //显示倒计时的时间
            if (window.InterValObj) {
                clearInterval(InterValObj)
            };
            InterValObj = window.setInterval(function() {
                a.setRemainTime()
            },
            CONFIG.timer.status) //以1秒为更新频率的倒计时
        },
        setRemainTime: function() {
            var e = this,
            b = CONFIG.startDate,
            h = b / 0x3e8;
            surplusTime = h - servertime;
            if (surplusTime >= 0x0) {
                var c = Math.floor(surplusTime % 0x3c),
                f = Math.floor((surplusTime / 0x3c) % 0x3c),
                d = Math.floor((surplusTime / 0xe10) % 0x18),
                g = Math.floor((surplusTime / 0x15180) % 0x1e);
                servertime++;
                var i = [c.toString(), f.toString(), d.toString(), g.toString()];
                var a = “<span>” + i[0x2] + “ </ins>小时” + i[0x1] + “</ins>分” + i[0x0] + “</ins>秒后开始”;
                if (d === 0x0) { //最后一小时
                    a = “<span>” + i[0x1] + “</ins>分”+ i[0x0] +“</ins>秒后开始”;
                    if (f === 0x0) {
                        a = _$[104] + i[0x0] + “</ins>秒后开始”//最后一分钟的显示 
                    }
                };
                if ( !! m.$ (“ surTime ”) {
                    m.$ (“ surTime ”).innerHTML = a
                }
            } else {
                m.$(“surTime”).innerHTML =“正在加载中...”;
                setTimeout(function() {
                    htmlStr.init(0x3) //显示抢购的按钮,可以点抢购按钮了
                },
                0x7d0); //又浪费2秒钟。。如果按标准流程,要慢2秒才能开始抢购
                if (window.InterValObj) {
                    clearInterval(InterValObj)
                }
            }

        },

//以上就是为了显示倒计时的时间

        boxy: function(b, d) {
            var c = (d) ? d: “”,
            a = m.$("boxbg"),
            e = m.$("box" + c);
            if (b) {
                a.style.height = Math.max(document.documentElement.clientHeight, document.documentElement.scrollHeight) + "px";
                a.style.display = "block";
                e.style.display = "block";
                if (!d && !window.loadingAnimate) {
                    Util.animate(“LoadingAnimate”, 0x7d0) //2秒钟的动画
                }
            } else {
                a.style.display = “none”;
                e.style.display = _“none”;
                if (!d && window.ajaxInter) {
                    clearTimeout(ajaxInter)
                }
            }
        },
        requestAgain: function() { //再次请求src里面的地址,但是隔了30秒
            var a = this;
            a.jsonInter(CONFIG.srcs.hdget,“hdget”, true)
        }
    },
    htmlStr = {
        init: function(a) {
            m.$(“hdBtns”).innerHTML = this.btn(a);
            m.$(“hdSubTitle”).innerHTML = this.subTitle(a);
            m.$(“hdLnks”).innerHTML = this.links(a);
            m.$(“hdMsg”).innerHTML = this.msgs(a);
            m.$(“mi3btn”).innerHTML = this.phoneBtn(a);
            m.$(“mitvbtn”).innerHTML = this.tvBtn(a);
            if (a === 0x4) {
                m.$(“linksCon-span”).innerHTML = “购买查询” 
            }
        },
        btn: function(d) {
            var c = “<a class="btn" onClick="Util.showBox('phone');">购买手机”,
            i = "<a class="btn" onClick="Util.showBox('tv');">购买电视",
            f = "<a class="btn" onClick="Util.showBox('box');">购买盒子",

            j = m.cookie("xm_pf_wl") ?"<a class="btn" href="" + CONFIG.urls.phone + "" onClick="return Util.bookedPop('phone',this);">支付手机</a>": "<a class="btn" href="" + CONFIG.urls.bookPhone +""  target="_blank">预约手机</a>", //这里注意,订购成功后,小米会更新客户端cookie的xm_pf_wl的字段,只有xm_pf_wl为1,才显示支付按钮,不过我们可以直接输入支付网页,或者刷新页面获得支付状态对cookie的更新


            h = m.cookie(“xm_pft_wl ”) ? “<a class="btn" href="” + CONFIG.urls.tv + “" onClick="return Util.bookedPop('tv',this);">支付电视</a>” : “<a class="btn" href="” + CONFIG.urls.bookTv + “"  target="_blank">预约电视</a>”, //同上
            g = m.cookie(“xm_pfb_wl”) ? “<a class="btn" href="” + CONFIG.urls.box + “" onClick="return Util.bookedPop('box',this);">支付盒子</a>” : “<a class="btn" href="” + CONFIG.urls.bookBox + “"  target="_blank">预约盒子</a>”,
            e = “<span class="untime">正在加载中...”,
            b = “ <a class="btn" href="” + CONFIG.urls.login +”" title="提前登录" >提前登录</a>“;

//以下显示不同的按钮           

 switch (d) {

            case 0x1:
                return e;
                break;
            case 0x2:
                var a = (m.cookie(CONFIG.cookies.userid));
                if (a) {
                    return e
                } else {
                    return b
                };
                break;
            case 0x3:
                return c + i + f; //显示不同的按钮
                break;
            case 0x4:
                return j + h + g;
                break;
            case 0x5:
                return c + h + f;
                break;
            case 0x6:
                return j + i + f;
                break;
            case 0x7:
                return j + h + f;
                break;
            case 0x8:
                return c + h + g;
                break;
            case 0x9:
                return j + i + g;
                break;
            case 0xa:
                return i + i + g;
                break
            }

        },

//以下是子标题

        subTitle: function(a) {
            var c = “11月19日星期二中午12点开放购买<br>小米3、小米电视、小米2S、红米手机、小米盒子”,
            b = “开放购买所有产品已售罄,成功购买用户请尽快支付<br>下午3点将进行剩余订单专场”;
            if (a === 0x4) {
                return b
            } else {
                return c
            }
        },
        links: function(b) {
            var a = “<a href="”+ CONFIG.urls.checkPhone + “" target="_blank">手机预约查询</a>”+ CONFIG.urls.checkTv +  “ <a href=" ”+ CONFIG.urls.checkPhone + “ " target="_blank">+ CONFIG.urls.checkPhone + " target="_blank">手机预约查询</a> ”+,
            c =“<a href="” + CONFIG.urls.checkPhoneBuy + “" target="_blank">手机购买查询</a>” + CONFIG.urls.checkTvBuy + “”+ CONFIG.urls.checkBoxBuy +“” 
            if (b === 0x4) {
                return c
            } else {
                return a
            }
        },
        msgs: function(a) {
            var c = “购买成功用户请在2小时内下单,下单后2小时内支付<br/>购买成功用户支付通道:160: " onClick="return Util.bookedPop('phone',this);">支付手机</a>”+ CONFIG.urls.phone +“成功购买用户请在2小时内下单,下单后2小时内支付<br/>红米手机联通合约版首发,¥999起。立即购买” + CONFIG.urls.tv + _$[161] + CONFIG.urls.box + _$[162],
            b = “成功购买用户请在2小时内下单,下单后2小时内支付<br/>红米手机联通合约版首发,¥999起。立即购买”;
            if (a === 0x4) {
                return b
            } else {
                if (a === 0x1 || a === 0x2) {
                    return “”
                } else {
                    return c
                }
            }
        },
        phoneBtn: function(a) {
            var c = “<p class="btn-noStart">1999元(16GB)即将开始”,
            d = “<a onClick="Util.showBox('phone');" class="btn-mid" href="#">1999元(16GB)立即购买”,
            b = “<a class="btn-mid" href="” + CONFIG.urls.phone +“" onClick="return Util.bookedPop('phone',this);"><span>1999元(16GB)立即支付”;
            switch (a) {
            case 0x1:
                return c;
                break;
            case 0x2:
                return c;
                break;
            case 0x4:
                return b;
                break;
            case 0x6:
                return b;
                break;
            case 0x7:
                return b;
                break;
            case 0x9:
                return b;
                break;
            default:
                return d
            }
        },
        tvBtn: function(a) {
            var c = “<p class="btn-noStart">2999元即将开始”,
            d = “ <a onClick="Util.showBox('tv');" class="btn-mid" href="#">2999元立即购买”,
            b = “ <a class="btn-mid" href="” + CONFIG.urls.tv + “" onClick="return Util.bookedPop('tv',this);"><span>2999元立即支付”;
            switch (a) {
            case 0x1:
                return c;
                break;
            case 0x2:
                return c;
                break;
            case 0x4:
                return b;
                break;
            case 0x5:
                return b;
                break;
            case 0x7:
                return b;
                break;
            case 0x9:
                return b;
                break;
            default:
                return d
            }
        },
        getOverInfo: function() {
            var a = “”,
            d = “”,
            c = “”,
            b = function(f, e, g) {
                return “<h3>对不起”+ f + “ 都售罄了</h3>都是我不好,人数太多,机器太少。别灰心,你可返回首页尝试购买” + e + “,<br/>也可立即预约11月26日下轮开放购买。” + g + “返回活动首页”
            };
            switch (CONFIG.proType) {
            case “phone”:
                a =“小米手机”;
                d =“小米电视及小米盒子”;
                c = CONFIG.urls.bookPhone; 
                break;
            case “tv”:
                a = "小米电视";
                d = "小米手机及小米盒子";
                c = CONFIG.urls.bookTv;
                break;
            case "box":
                a = "小米盒子";
                d = "小米手机及小米电视";
                c = CONFIG.urls.bookBox;
                break
            };
            m.$("box-reg-wrap").innerHTML = b(a, d, c);
            m.$("box-reg-wrap").style.background = "url(http://p.www.xiaomi.com/open/131101/images/mitu-2.png) no-repeat 5px 0" 
        }

    };

打完,收工。

最后一段分析:

下面这个链接就是抢购用的url

http://tc.hd.xiaomi.com/hdget?callback=hdcontrol&_=当前时间(用javascript写就算是new Date().getTime())

hdget获得请求后,结合cookie里面的内容,roll个结果记录下来,然后通知用户订购的结果

然后这个会返回一个javascript文件,文件里面有去选机型的url,这个文件里面调用了hdcontrol函数,让hdcontrol函数去跳转选机型的url。

这个url开头是http://t.hd.xiaomi.com/s/

然后加上hdcontrol返回的url位置,以开头的例子:

hdcontrol({
    "stime": 1378180861,
    "status": {
        "allow": false,
        "miphone": {
            "hdstart": true,
            "hdstop": false,
            "hdurl": "?_a=20130903_september_first_weeks&_op=choose",
            "duration": null,
            "pmstart": false
        },
        "mibox":


        {
            "hdstart": true,
            "hdstop": false,
            "hdurl": "?_a=20130903_september_first_weeks&_op=choose",
            "duration": null,


            "pmstart": false
        }
    }
})

这个url请求最终是http://t.hd.xiaomi.com/s/?_a=20130903_september_first_weeks&_op=choose

这种类似的格式。而将其混淆的url格式读取的代码简单如下即可:

list = [];
  for (var i = 0, l = arr.length; i < l; i++)
  {
      list[list.length] = '<li>' +i+':  '+ arr[i] + '';
  }
  list = '<ul>' + list.join('') + '</ul>';
   
  document.getElementById("copyright").innerHTML=list;

然后下一步就是抢时间输入验证码了。

还可以考虑直接用firefox或者firebug执行下面抢购的javascript代码,以跳过30秒重试的限制。

getStatus.jsonInter(CONFIG.srcs.hdget, "hdget", true);

你可能感兴趣的:([置顶] 小米js源码解析)