Friday, May 10, 2013

Userscripts.org 风险脚本过滤器


// ==UserScript==
// @name        Userscripts.org 风险脚本过滤器
// @description 过滤掉 Userscripts.org 上可能危险的脚本
// @homepageURL http://jixun.org/
// @include     h*://userscripts.org/*
// @version     5.104-c41
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @run-at      document-start
// @updateURL https://userscripts.org/scripts/source/164600.meta.js
// @downloadURL https://userscripts.org/scripts/source/164600.user.js
// ==/UserScript==

// 火狐兼容修正
if (typeof (GM_info) != 'object')
    GM_info = { script: {version: GM_getMetadata("version").join('')} };


var arrSettings = [{
    stri: '每天检查脚本更新',
    save: 'dailyUpdate',
    defu: true
},{
    stri: '开启火狐兼容 [流量可能变大]',
    save: 'firefoxMode',
    defu: /firefox\/\d+\.\d+$/i.test(navigator.userAgent)
},{
    stri: '自动下一页 [流量可能变大]',
    save: 'autoNextPage',
    defu: false
},{
    stri: '扫描脚本源码',
    save: 'enableScriptCheck',
    defu: true
},{
    stri: '启用白名单',
    save: 'enableWhitelist',
    defu: true
},{
    stri: '自动订阅',
    save: 'autoSubscribe',
    defu: true
},{
    stri: '自动 Follow',
    save: 'autoFollow',
    defu: true
},{
    stri: '脸谱自动赞好',
    save: 'autoLike',
    defu: true
},{
    stri: '添加好友字串',
    save: 'autoAddFriend',
    defu: true
},{
    stri: '读取 token',
    save: 'readToken',
    defu: true
},{
    stri: '调用已知的恶意脚本',
    save: 'knownScamScript',
    defu: true
},{
    stri: 'Ask.fm 欺诈',
    save: 'askfmScam',
    defu: true
},{
    stri: 'Ultoo.com 欺诈',
    save: 'ultooScam',
    defu: true
},{
    stri: '访问用户密码',
    save: 'readPwd',
    defu: true
},{
    stri: '自动跳广告链接扫描',
    save: 'autoJumpAd',
    defu: true
},{
    stri: '返利代码 (测试中, 缺少样本)',
    save: 'moneyBack',
    defu: true
},{
    stri: '隐藏页面插入',
    save: 'hiddenPage',
    defu: false
},{
    stri: '脚本经过混淆或可能存在注入点',
    save: 'evalFunc',
    defu: false // 误杀太大,默认不开启
},{
    stri: '远程脚本插入',
    save: 'remoteScript',
    defu: false
},{
    stri: '访问远程服务器',
    save: 'accessInternet',
    defu: false
}];

$(document).ready(function(){
    var sSettingPrifix = 'uso_sf_setting_',
        sScriptUsoId = '164600',
        bUserLoggedIn = $('.login_status a[href="/home"]').length,
        bDebugScript = false,
        bDebugUpdate = true;
    
    function $Get ( sItem, retIfNull ) {
        return localStorage.getItem ( sItem ) || $Set(sItem, retIfNull)
    }
    
    function $Set ( sItem, sVar ) {
        localStorage.setItem ( sItem, sVar )
        return sVar
    }
    
    // 左下角读取页面提示
    var $s_lblnp = $('<div>').css ({
        'position': ' fixed',
        'bottom': ' -20px',
        'height': ' 40px',
        'width': ' 100px',
        'border-top-right-radius': ' 20px',
        'background-color': ' darkcyan',
        'text-align': ' right',
        'padding': ' 3px',
        'color': ' white',
        'padding-right': ' 10px'
    }).hide().appendTo ($('body'))
    .text ('正在读取下一页…');
    
    var $s_cpn = parseInt ($('.current:first').text()),
        $s_fr = !$s_cpn,
        $s_npp = ($('a.next_page').attr('href')||'').replace('=' + ($s_cpn + 1), '=|PAGE|');
    
    $(document).on('scroll', ($s_fr ? function () {}: function (e) {
        // 已经在读取下一页,不执行。
        if($s_fr || !$$.autoNextPage)
            return;
        
        if ($(document).height() - unsafeWindow.innerHeight - unsafeWindow.pageYOffset < 0x66) {
            // 检测到页面尾端,开始读取下一页…
            $s_fr = true;
            $s_cpn ++;
            $s_lblnp.show ( 200 );
            
            var targetUrl = $s_npp.replace(/\|PAGE\|/,$s_cpn);
            // console.log (targetUrl, $s_npp);
            $.ajax({
                url: targetUrl,
                dataType: 'html',
                success: function (r) {
                    $d = $(r).find('tr[id^="scripts-"]');
                    $d.appendTo ($('table.wide.forums tbody'));
                    checkPage($d);
                    $s_fr = false;
                    $s_lblnp.hide ( 200 );
                },
                error: function (a) {
                    $s_lblnp.hide ( 200 );
                    if (a.status != 404)
                        return $s_fr = false;
                    
                    console.log ('已经是页面尾端!');
                }
            });
            
        }
    }));
    
    // 右下角设定按钮
    $('<div>').css ({
        'position': 'fixed',
        'border': '1px black solid',
        'bottom': '10px',
        'height': '100px',
        'right': '-80px',
        'width': '100px',
        'border-radius': '20px',
        'background': '#FF8800',
        'transform': 'rotate(-90deg)',
        '-o-transform': 'rotate(-90deg)',
        '-ms-transform': 'rotate(-90deg)',
        '-moz-transform': 'rotate(-90deg)',
        '-webkit-transform': 'rotate(-90deg)',
        'text-align': 'center',
        'padding': '3px',
        'cursor': 'pointer'
    }).appendTo ($('body')).click(function () {
        $('body').css ('overflow', 'hidden');
        $uiSetting.show().animate({
            'opacity': '1'
        });
        $uiOverlay.show().animate ({
            'opacity': '.75'
        });
    }).text ('脚本扫描器设定').hover(function () {
        $(this).css ('color', 'white');
    }, function () {
        $(this).css ('color', '');
    });
    
    var $uiSetting = $('<div>').css ({
        'margin': '10px auto',
        'border': 'black 1px solid',
        'position': 'fixed',
        'top': '20%',
        'width': '80%',
        'left': '10%',
        'right': '10%',
        'height': '60%',
        'background': 'rgb(176, 196, 222)',
        'z-index': '99999',
        'padding': '10px',
        'overflow-y': 'auto',
        'opacity': '0'
    }).appendTo ($('body')).hide();
    
    var $uiOverlay = $('<div>').css ({
        'opacity': '.75',
        'position': 'fixed',
        'z-index': '99998',
        'background': 'gray',
        'top': '0',
        'left': '0',
        'width': '100%',
        'height': '100%',
        'opacity': '0'
    }).click (function () {
        $('body').css ('overflow', 'auto');
        $uiSetting.animate({
            'opacity': '0'
        }, function () {
            $(this).hide();
        });
        $uiOverlay.animate ({
            'opacity': '0'
        }, function () {
            $(this).hide();
        });
    }).appendTo ($('body')).hide();
    
    $('<div>').css ({
        'float': 'right',
        'width': '15%',
        'height': '100px',
        'border': '2px white dashed',
        'cursor': 'pointer',
        'text-align': 'center'
    }).append($('<p>').css({
        'margin-top': '30px'
    }).html('如果您喜欢该脚本,<br />还请打个 5 分,谢谢~'))
    .hover(function () {
        $(this).css ('background', 'skyblue');
    }, function () {
        $(this).css ('background', 'inherit');
    }).click (function () {
        unsafeWindow.open ('//userscripts.org/reviews/new?script_id=' + sScriptUsoId);
    }).appendTo( $uiSetting );
    
    var $$ = {};
    function createSettingPanel ( sSettingPrifix, arrSettings ) {
        arrSettings.forEach ( function (e) {
            var varSet = $Get(sSettingPrifix + e.save, e.defu);
            varSet = ((varSet == 'true') || (varSet == '1') || (varSet == 1))
            $$[e.save] = varSet;
            
            if (bDebugScript)
                console.log (varSet, typeof(varSet));
            
            $('<input type="checkbox">')
            .appendTo($uiSetting).prop (
                'checked',
                varSet
            ).attr ('id', sSettingPrifix + e.save).prop ('checked');
            
            $('<label>').text (e.stri)
            .appendTo($uiSetting).append('<br />')
            .attr ('for', sSettingPrifix + e.save);
        });
        
        $('<input type="button">').css ({
            'padding': '2px 10px',
            'margin-top': '20px',
            'margin-left': '5px'
        }).attr('value', '保存').click(function () {
            // Hide dialog
            $uiOverlay.click();
            
            // Save settings
            $uiSetting.find('input[type="checkbox"][id^="'
                            + sSettingPrifix + '"]')
            .each (function () {
                localStorage.setItem (
                    this.id,
                    this.checked
                );
            });
            $uiSetting.find('input, label').remove();
            createSettingPanel (sSettingPrifix, arrSettings);
        }).appendTo($uiSetting);
        
        $('<input type="button">').css ({
            'padding': '2px 10px',
            'margin-left': '5px'
        }).attr('value', '恢复默认').click(function () {
            // Hide dialog
            $uiOverlay.click();
            
            arrSettings.forEach ( function (e) {
                $Set(
                    sSettingPrifix + e.save,
                    e.defu
                )
            });
            $uiSetting.find('input, label').remove();
            createSettingPanel (sSettingPrifix, arrSettings);
        }).appendTo($uiSetting);
    }
    
    $('<h1>').appendTo ($uiSetting).text('USO 危险脚本识别器 —— 脚本选项');
    $('<span>').appendTo ($uiSetting).css({
        'display': 'block',
        'font-size': 'small',
        'margin-left': '20px',
        'margin-bottom': '20px'
    }).html('基于 <a href="/users/501553" target="_blank">equazcion</a> 的作品\
《<a href="/scripts/show/163038" target="_blank">Userscripts.org Scam Filter</a>》进行汉化、增强,\
在此表示感谢。<br />如果您发现流氓作者、恶意脚本但是不能被正确识别的话,还请发布在讨论区,谢谢。');
    createSettingPanel (sSettingPrifix, arrSettings);
    $$.scanScript = ($$.autoSubscribe || $$.autoFollow || $$.evalFunc 
                     || $$.autoLike ||  $$.autoAddFriend || $$.readToken
                     || $$.hiddenPage|| $$.remoteScript || $$.accessInternet
                     || $$.readPwd || $$.moneyBack || $$.autoJumpAd
                     || $$.askfmScam || $$.ultooScam) && ($$.enableScriptCheck);
    
    // [[  返利、暗藏广告监测正则声明  ]]     开始
    var siteListA = 'lumi258|nala|etam|nop|lovo|efeihu|tinies|99read|tnice|sasa|chictalk|gouxie|'
    + 'm18|yintai|all3c|9dadao|cosme-de|xiu|hi-tec|do93|hanshanggou|xifuquan|513523|vsnoon|mfpla'
    + 'za|uiyi|xzuan|skomart|learbetty|yesfashion|felissimo|mmuses|ihush|redmall|autosup|amssy|b'
    + 'uding|echuyi|lefeng|ukool|gitanamagic|yidianda|officedepot|justonline|buyjk|shopin|cendil'
    + 'e|e-lining|outlets001|mamimai|vingz|aizhigu|x(\\\\|)\\.com(\\\\|)\\.cn|naruko|dahuozhan|e'
    + 'rq|360buy|dangdang123';
    
    var siteListB = 'masamaso|vcotton|lamiu|purcotton|sportica|naguu|aimer|quwan|pufung|vipstore'
    + '|doodays|idshe|jsstyle|idaphne|vosovo|banggo|misslele|hmeili|easy361|yyosso|w1|fs-mall|ju'
    + 'stbb|xiaozhuren|uipmall|immyhome|fclub|shaobag|cheeee|jiuq|happigo|no5|olomo|258sd|lehome'
    + '|jiuxian|taohv|99buy|lyceem';
    
    var siteListC = '51buy|china-pub|xiu|meituan|suning|coo8|dhc|mbaobao|letao|wl|bookuu|taoxie|'
    + 'justonline|mangocity|flowercn|9588|linktech|ocj';
    
    var moneybackPattenA = new RegExp ('(' + siteListA + ')(\\\\|)\\.(.+?)(\\/|\\?|&)(product_id|product|unionId)','i');
    var moneybackPattenB = new RegExp ('(' + siteListB + ')(\\\\|)\\.(.+?)(\\/|\\?|&)goods','i');
    var moneybackPattenC = new RegExp ('(' + siteListC + ')(\\\\|)\\.(.+?)(\\/|\\?|&)\\d\+','i');
    
    // [[  返利、暗藏广告监测正则声明  ]]     结束
    
    // [[  已知远端恶意脚本地址  ]]          开始
    var knowSacmTarget = 'dropbox(.+?)56439548|linkut\\.eu';
    var knownScamPatten = new RegExp ('(' + knowSacmTarget + ')','i');
    // [[  已知远端恶意脚本地址  ]]          结束
    
    
    var scriptId = parseInt((location.href.match (/\/(\d+)/i)||[,0])[1]);
    $('<style>').html('tr.scam { opacity: .3; } tr.scamHide { display: none; }').appendTo($('body'));
    
    // *** Set update info ***
    var lP = location.protocol;
    
    // Tell auto-updater this script's description page URL, for the update notification link
    var thisScriptURL = lP + '//userscripts.org/scripts/show/' + sScriptUsoId; 
    
    // Tell auto-updater this script's meta data URL, for checking the script's latest version number
    var thisScriptMetaURL = lP + '//userscripts.org/scripts/source/' + sScriptUsoId + '.meta.js'; 
    // *** End update info ***
    
    // 数据库开始
    
    // 已知的乱七八糟的脚本作者… 官方改了排列方式我还在想怎么突然少了那么多黑名单
    var scammers = [
        100713, 10072, 126265, 130901, 139742, 151070, 169798, 179136, 196818, 199618, 201391, 208735, 234423, 238348, 250955, 
        256842, 271918, 283470, 286875, 288247, 289792, 289964, 290748, 291772, 292807, 301639, 308463, 314407, 319859, 320677, 
        322218, 327303, 329565, 331170, 342061, 342242, 353460, 360083, 365484, 369106, 378054, 392894, 395734, 398936, 401264, 
        403145, 409280, 412918, 413570, 414793, 416110, 417384, 418280, 420148, 420155, 422222, 422223, 422224, 422226, 422227, 
        423469, 426106, 426361, 426481, 426758, 427026, 427958, 428623, 428693, 428875, 431803, 432055, 433063, 433419, 434378, 
        434587, 434590, 434917, 435713, 436783, 437023, 437719, 439139, 439208, 439396, 439843, 440592, 440592, 440600, 440800, 
        440810, 441085, 441113, 441298, 442036, 442192, 442199, 442265, 442420, 442786, 445056, 445145, 445861, 464299, 467890, 
        468969, 469018, 469610, 469618, 469741, 469778, 469780, 469784, 469787, 469791, 469809, 469852, 469860, 469886, 469976, 
        470172, 470374, 470394, 470697, 470746, 471187, 471736, 471739, 471746, 471931, 472464, 473044, 473740, 473813, 473973, 
        474262, 474473, 474749, 475448, 475548, 475874, 476102, 476758, 477018, 477783, 477939, 479194, 479455, 480097, 480448, 
        481002, 482213, 482708, 483252, 484441, 484490, 484532, 484943, 485411, 486100, 486160, 487207, 487511, 488376, 489669, 
        489768, 489916, 490174, 490444, 490808, 492379, 492463, 492564, 492799, 493299, 493603, 495883, 495995, 496061, 496647, 
        497119, 497163, 497384, 497739, 497795, 497933, 498115, 498417, 498726, 498788, 498865, 498950, 499040, 499556, 499802, 
        500010, 500038, 500078, 500190, 500250, 500300, 500403, 500430, 500630, 500637, 500679, 500825, 500843, 501009, 501053, 
        501137, 501345, 501361, 501444, 501446, 501668, 501687, 501773, 501839, 502003, 502190, 502217, 502220, 502362, 502367, 
        502394, 502509, 502511, 502618, 503054, 503108, 503206, 503298, 503334, 503485, 503498, 503586, 503590, 503614, 503630, 
        503709, 503775, 503800, 503837, 503846, 503861, 503959, 504005, 504188, 504327, 504342, 504380, 504474, 504495, 504611, 
        504693, 504831, 504907, 504955, 504962, 504988, 504993, 505035, 505047, 505078, 505107, 505130, 505168, 505247, 505250, 
        505267, 505300, 505314, 505326, 505329, 505330, 505352, 505401, 505429, 505434, 505444, 505511, 505519, 505607, 505617, 
        505635, 505689, 505764, 505765, 505770, 505775, 505778, 505782, 505791, 505792, 505802, 505802, 505802, 505845, 505864, 
        505912, 505926, 505945, 505950, 506068, 506107, 506119, 506181, 506195, 506223, 506307, 506308, 506312, 506323, 506324, 
        506372, 506401, 506430, 506512, 506542, 506547, 506579, 506607, 506668, 506680, 506689, 506697, 506729, 506729, 506731, 
        506735, 506741, 506748, 506824, 506866, 506898, 506908, 506958, 506973, 506995, 506998, 507014, 507032, 507041, 507082, 
        507089, 507093, 507094, 507118, 507142, 507166, 507183, 507199, 507208, 507215, 507232, 507241, 507241, 507260, 507267, 
        507280, 507340, 507365, 507395, 507466, 507471, 507472, 507485, 507486, 507498, 507510, 507524, 507554, 507588, 507596, 
        507604, 507614, 507645, 507649, 507651, 507659, 507700, 507726, 507729, 507732, 507751, 507753, 507756, 507765, 507767, 
        507776, 507832, 507854, 507861, 507861, 507870, 507870, 507876, 507881, 507901, 507909, 507927, 507934, 507958, 508036, 
        508057, 508083, 508087, 508103, 508121, 508147, 508149, 508224, 508228, 508237, 508299, 508301, 508322, 508327, 508333, 
        508339, 508401, 508422, 508437, 508452, 508594, 508665, 508667, 508673, 508693, 508725, 508770, 508774, 508789, 508794, 
        508814, 508826, 508839, 508849, 508882, 508885, 508929, 508952, 509003, 509046, 509083, 509102, 509157, 509241, 509275, 
        509293, 509298, 509312, 509360, 509376, 509378, 509401, 509405, 509425, 509455, 509477, 509541, 509598, 509657, 509690, 
        509694, 509709, 509729, 509760, 509798, 509806, 509806, 509950, 509965, 510077, 510116, 510181, 510183, 510191, 510309, 
        510350, 510382, 510389, 510422, 510487, 510527, 510565, 510582, 510588, 510605, 510609, 510611, 510630, 510636, 510672, 
        510691, 510729, 510750, 510766, 510780, 510785, 510788, 510790, 510847, 510850, 510881, 510918, 510946, 510972, 510975, 
        511000, 511004, 511015, 511060, 511070, 511090, 511093, 511096, 511118, 511127, 511129, 511138, 511160, 511170, 511188, 
        511244, 511319, 511328, 511333, 511367, 511386, 511401, 511415, 511439, 511475, 511543, 511558, 511598, 511604, 511640, 
        511674, 511676, 511758, 511795, 511801, 511847, 511852, 511856, 511861, 511888, 511959, 511984, 511989, 511998, 512061, 
        512085, 512089, 512124, 512154, 512178, 512179, 512195, 512212, 512226, 512259, 512362, 512387, 512412, 512442, 512514, 
        512519, 512525, 512529, 512570, 512570, 512571, 512606, 512668, 512669, 512674, 512685, 512693, 512725, 512743, 512750, 
        512752, 512759, 512776, 512779, 512836, 512842, 512915, 512972, 513002, 513028, 513030, 513106, 513188, 513216, 513236, 
        513246, 513264, 513355, 513357, 513360, 513360, 513364, 513390, 513409, 513429, 513430, 513448, 513487, 513490, 513541, 
        513557, 513638, 513678, 513804, 513812, 513836, 513843, 513968, 513981, 513984, 514045, 514114, 514143, 514231, 514231, 
        514276, 514332, 514361, 514396, 514399, 514408, 514409, 514412, 514445, 514448, 514493, 514517, 514637, 514658, 514718, 
        514725, 514728, 514768, 514863, 514873, 514894, 514911, 514953, 515026, 515078, 515107, 515176, 515223, 515268, 515272, 
        515299, 515313, 515321, 515440, 515446, 515465, 515489, 515540, 515577, 515832, 515836, 515862, 515898, 516034, 516035, 
        516079, 516107, 516124, 516152, 516201, 516225, 516272, 516309, 516334, 516431, 516460, 516468, 516474, 516502, 516540, 
        516568, 516582, 516589, 516650, 76302, 85357,  9657
    ];
    
    var copyCat = [
        513573,484405,513621,422292,478814,513746,494425,508578,498070,500894,514046,514258,512116,466803,506234,
        182070,154802,210716,326372,142623,479344,412017,195004,209847,483188,515140,506391,502722,497223,516057,
        498655
    ];
    
    // Ignore the following script authors. This is to prevent known false-positive detections
    var whitelistUser = [
        501553, /* equazcion */
        474953, /* jixun67 */
        494707, /* yulei */
        202260, /* NLF */
        /* ↓官方名单 */
        19916,297645,86416,103626
    ];
    // 一般是那些能消广告的被误报… 这个没办法…
    var whitelistScript = [
        89761,  // The Pir*te Bay Ad Remover
        89322,  // AdsFight!
        87011,  // ViewTube
        130917, // SaveTube
        114002, // YouTube Center
        126619, // iZhihu 我爱知乎
        161883, // search_engineJump 修改版
        165091, // CSDN 免积分下载
        9310,   // GoogleMonkeyR
        114087  // 眼不见心不烦(新浪微博)
    ];
    var scamScript = [
        162484,
        /* ↓官方名单 */
        124287, 165241, 142050, 165892, 165889
    ];
    
    // 数据库结束
    
    console.log ('成功加载脚本 [ Userscripts.Org 风险脚本过滤器 ] 版本 ', GM_info.script.version,
                 '。\n当前数据库共包含 无良作者 [', scammers.length,
                 '] 个, 白名单作者 [', whitelistUser.length,
                 '] 个, 黑名单脚本 [', scamScript.length,
                 '] 个, 白名单脚本 [', whitelistScript.length,
                 '] 个, 山寨脚本作者 [', copyCat.length,
                 '] 个.');
    
    // Set global variables
    var cScam, suspects = [], arrStates = [];
    
    /* Check for an existing session cookie: Ajax Range header for bandwidth limiting measure doesn't work without a session cookie.
    If one is not found, retrieve the login page once (without logging in), which creates the session cookie for us */
    // Jixun: Don't see the point doing that.
    
    // If our toggle cookie doesn't exist yet, create it, so our toggle state can be saved
    $Get('ScamHide', true);
    
    // Set the expanded warning to be placed in the descriptions of suspected scam scripts
    var caution = '<span style="line-height:100%;color:darkred;font-weight:bold;margin-bottom:-10px;display:block;">' + 
        '该脚本可能为恶意脚本,' + 
        '使用时请小心。<br />' + 
        '<span class="reason" style="color:red;font-weight:bold;font-family:verdana;font-size:90%;line-height:150%;"></span></span><br />' +
        '<span style="font-weigth:bold;line-height:110%;">作者描述:</span> ';
    
    // Set update notice
    var notify = '<a style="font-size: 11px; text-decoration: none !important; border-bottom: 1px orange dotted;' +
        'margin-left: 15px;" class="notify" target="_blank" href="' + thisScriptURL + '">' +
        '发现新版本, 建议更新!</a>';
    
    // Insert our toggle link, along with fields to show # of detected scams and the auto-update notice
    var $table = $('table.forums .la:contains("Name"):first')
    .append('&nbsp; ' + 
            '<a href="#" class="autoToggle">过滤?</a>&nbsp;(' + 
            '<span class="working" style="color:orange;text-shadow:0px 0px 5px #yellow;">扫描中…</span>' + ': ' +
            '<span class="total">0</span><span class="tog"></span>)' + 
            '<span class="upd" style="display: block;"></span>');
    var bTableMode = !$table.length;
    
    // Set toggle link hover effect
    $('a.autoToggle').hover(
        function(){
            $(this).css('color','#FFDD11');
        },
        function(){
            $(this).css('color','white');
        }
    );
    
    // Determine login status, which effects the location of elements on the page
    var loggedIn = (bUserLoggedIn); 
    
    function checkIfAllDone () {
        if (bDebugScript)
            console.log (arrStates.join(), suspects);
        if (arrStates.join().indexOf('0') > -1)
            return;
        
        $('span.working').text('完毕').css('color','white').css('text-shadow','');
    }
    
    checkPage($('tr[id^="scripts-"]'));
    function checkPage ($arg1) {
        $arg1.each(function(i,val){
            // Extract script ID from row ID
            var self = this;
            id = $(self).attr('id').replace('scripts-','');
            console.log ('Scanning:', id);
            suspects[i] = id;
            arrStates.push (0);
            
            if (!$$.firefoxMode) {
                // Get title length so we can determine where author code will be on the retrieved page 
                var offset = $(this).find('a.title').attr('title').length;
                
                // Author code is further down for logged-in users, so add to the offset if we're logged in
                if (bUserLoggedIn)
                    offset += 100;
                
                // Retrieve that section of the script's "fans" page
                var myHeader = {Range: "bytes=" + (offset + 1600) + "-" + (offset + 2300)};
            } else {
                var myHeader = {};
            }
            $.ajax({
                url: location.protocol + '//userscripts.org/scripts/fans/' + suspects[i], 
                dataType: 'text', 
                headers: myHeader,
                cache: true,
                success: handOff1,
                fail: function () {
                    setTimeout (function () {
                        checkPage ($(self));
                    }, 500);
                }
            });
            
            function handOff1(data){
                // Hand off the retrieved description page to the checkScriptAuthor function
                checkScriptAuthor (data, suspects[i], i);
            }
        });
    }
    
    function checkScriptAuthor(data ,id, index){
        if (bDebugScript)
            console.log ('checkScriptAuthor', arguments);
        var uid = parseInt(id);
        
        // Get script author's ID from the retrieved script description page
        if (bTableMode)
            var author = parseInt (data);
        else
            var author = parseInt ((data.match(/user_id="(\d+?)"/i)||[,0])[1]);
        
        // Debug author offset
        console.log ('Id ::', id, 'by', author);
        // If the script's author is in our whitelist, move on
        if ($$.enableWhitelist && whitelistUser.indexOf(author) > -1){
            tagGood ('认证作者', id, index);
            // If the script's author matches one of our known scammers, tag the script as a suspected scam
        } else if (scammers.indexOf(author) > -1){
            tagScam ('已知的流氓脚本作者', id, '流氓作者', index);
            // Otherwise, retrieve the script code for scanning
        } else if (copyCat.indexOf(author) > -1) {
            console.log (author);
            tagScam ('这家伙不知道从哪里山寨过来的脚本', id, '山寨作者', index);
        } else if ($$.scanScript) {
            $.ajax({
                url: location.protocol + '//userscripts.org/scripts/source/' + id + '.user.js', 
                dataType: 'text', 
                cache: true,
                success: function (data){ checkScript(data, uid, index); }});
            // Jixun: Short the code.
            return;
        } else {
            checkScript('', uid, index);
        }
    }
    
    function htmlTagCheck (tagName) {
        return (new RegExp ('(\'|"|\<|\\/)([a-zA-Z\\s]+?|)' + tagName + '(\'|"|\<|\\/|\\s)', 'i'));
    }
    
    function batchTest ( data, arrRegExp ) {
        if (bDebugScript)
            console.log (arguments);
        
        arrRegExp.forEach ( function ( cRegExp ) {
            if (cRegExp.test (data))
                return true;
        });
        return false;
    }
    
    function checkScript(rawData, id, index){
        if ($$.enableWhitelist && whitelistScript.indexOf(id) > -1){
            tagGood ('认证脚本', id, index);
            return ;
        } else if (scamScript.indexOf(id) > -1){
            tagScam ('已知的流氓脚本', id, '流氓脚本', index);
            return ;
        }
            
            if (rawData == '') {
                arrStates [index] = 1;
                checkIfAllDone ();
                return;
            }
        
        // Simple unpack of the code
        var data = unescape (rawData.replace(/\\u/gi, '%u'));
        
        if (bDebugScript)
            console.log ('checkScript', arguments);
        console.log ('Checking script :: ', id/*, '\n', data*/);
        
        // Skip scripts that don't contain at least one instance of the word "facebook" or "ultoo"
        // Jixun: But you'll never know if it sends data to another server or not.
        var arrReasons = [];
        // Check the script code for known scam patterns
        if ($$.autoSubscribe && /(action=|\/)subscribe/g.test(data))
            arrReasons.push ('自动订阅');
        
        if ($$.autoFollow && /follow(_|\/)/i.test(data))
            arrReasons.push ('自动 Follow');
        
        if ($$.evalFunc && (/p,a,c,k,e,(d|r)/.test(data.replace(/\s/g, '')) || /(;|=|\n|^)(\s+|)eval(\s+|)\(/.test(data)) )
            arrReasons.push('脚本经过混淆或存在隐藏的注入危险');
        
        if ($$.autoLike && /like\.php?href\=/i.test(data))
            arrReasons.push('脸谱自动赞好');
        
        if ($$.autoAddFriend && /(&|\?)action=add_friend/i.test(data))
            arrReasons.push ('自动添加好友参数');
        
        if ($$.readToken && /(&|\?)token[_=]/i.test(data)) 
            arrReasons.push ('token 获取');
        
        if ($$.hiddenPage && htmlTagCheck('frame').test(data)) 
            arrReasons.push ('插入隐藏页面');
        
        if ($$.remoteScript && htmlTagCheck('script').test(data))
            arrReasons.push ('插入远程脚本');
        
        if ($$.accessInternet && /xmlhttp/i.test(data))
            arrReasons.push ('访问远程服务器');
        
        // /([^a-z]pass(word|wd|)[^a-z]|pwd)/i
        if ($$.readPwd && /([^a-z]passw(ord|d|)[^a-z])/i.test (data)) // 密码窃取
            arrReasons.push ('读取密码');
        
        if ($$.autoJumpAd && /\.(\s+|)href(\s+|)=(\s+|)('|")([a-z0-9:\/\\]+)adf\.ly/i.test(data))
            arrReasons.push ('跳到广告页');
        
        if ($$.askfmScam && /((ask\.fm(.+?|)(like|ask|p(re|er)gunt))|(href\='Skype))/i.test(data))
            arrReasons.push ('Ask.fm 欺诈');
        
        if ($$.ultooScam && /('|")([a-z0-9\s]+|)PollUserName([a-z0-9\s]+|)('|")/i.test(data))
            arrReasons.push ('Ultoo 欺诈');
        
        if ($$.knownScamScript)
            if (knownScamPatten.test(data))
                arrReasons.push ('调用已知恶意脚本');
            
            if ($$.moneyBack) {
                // 防止資源浪費
                if (batchTest (data, [
                    /\?pid=mm_/i,
                    /amazon(\\|)\.(.+?)(\/|\?|&)(tag|prodid|asin|detailApp)=/i,
                    /linktech(\\|)\.c/i,
                    /sdo(.+?)(\/|\?|&)pid=/i,
                    /(vancl|beifabook|xinhuabookstore)(\\|)\.com/i,
                    moneybackPattenA,
                    moneybackPattenB,
                    moneybackPattenC
                ])) {
                    arrReasons.push ('包含返利代码');
                }
            }
        
        if (arrReasons.length >0)
            tagScam (arrReasons.join(', '), id, '风险脚本', index);
        else
            tagGood ('安全', id, index);
    }
    
    function tagScript (sReason, id, htmlColour, className, bHide, bCount, sCaution, tag, index){
        if (bDebugScript)
            console.log (bTableMode);
        
        if (bTableMode) {
            $('#details h2.title:first')
            .prepend ('[' + tag + '] ').css({
                'color': htmlColour,
                'font-size': '18px'
            }).after ($('<span>').css({
                'color': htmlColour
            }).text(sReason || ''));
            
            return;
        }
        if (bDebugScript)
            console.log ('tagScript', arguments);
        
        arrStates [index] = 1;
        checkIfAllDone ();
        
        toggleScams(false);
        // Set row selector
        var row = 'tr[id="scripts-' + id + '"] ';
        
        // Tag the suspected scam's HTML code
        // Show reason only on hover
        $(row).addClass(className).find('td.script-meat')
        .css('padding-bottom','0').hover(function(){
            $('span.reason', this).show();
        }, function(){
            $('span.reason', this).hide();
        });
        
        // Hide the suspected scam if the cookie tells us the toggle is set to hide
        if (bHide)
            $(row).attr('hidden',''); 
        
        // Tag the suspected scam visually using our preset messages
        $(sCaution).insertBefore($(row).find('a.title').css('color', htmlColour)
                                 .parent().find('p.desc'));
        
        // Set the text to use when tagging suspected scam scripts
        $(row).find('a.title').before($('<span>').css({
            'color': htmlColour
        }).text('[' + tag + '] '));
        
        // Append reason text
        if (sReason)
            $(row + 'span.reason').text(sReason).append('<br />').hide();
        
        // Increment the running count of detected scams
        if (bCount)
            $('span.total').text(parseInt($('span.total').text()) + 1);
        
    }
    
    function tagScam (reason, id, tag, index){
        if (bDebugScript)
            console.log ('tagScam', arguments);
        
        tagScript ('原因: ' + reason, id, 'darkred', 'scam',
                   ('true' == $Get('ScamHide')),
                   true, caution, tag, index);
    }
    
    function tagGood (reason, id, index){
        if (bDebugScript)
            console.log ('tagGood', arguments);
        
        tagScript (false, id, 'green', 'safe', false, false,
                   '<span class="reason" style="color: green"></span>',
                   reason, index);
    }
    
    function getToday () {
        // No round up.
        return parseInt(+new Date()/86400000);
    }
    
    $('#content h1,.container h2').first()
    .after('<span style="color: green; display: block;">即使脚本报告为安全,也应该多留个心眼。</span>');
    
    // Check for single script.
    if (bTableMode) {
        checkScriptAuthor ($('span.author a[user_id]').attr('user_id'), scriptId, 0, true);
    }
    
    // Set the toggle link's click function
    $('a.autoToggle').click(function(){
        toggleScams(true);
    });
    
    // Make sure the toggle setting is in effect in case a toggle click occurred during the loop
    // toggleScams(false);
    
    function toggleScams(click){
        if (bDebugScript)
            console.log ('toggleScams');
        var cScamHide = ($Get('ScamHide') == 'true');
        
        if (click) {
            cScamHide = !cScamHide;
            $Set('ScamHide', cScamHide);
        }
        
        if (cScamHide)
            hideScams();
        else
            showScams();
    }
    
    function hideScams(click){
        $('tr.scam').addClass ('scamHide');
        $('span.tog').text('个已隐藏');
    }
    
    function showScams(click){
        $('tr.scam').removeClass ('scamHide');
        $('span.tog').text('个风险脚本');
    }
    
    /* Auto-updater: Daily check. 
    If an update is found, update notice displays on the current and next two subsequent page loads, 
    then stops displaying again until following day. */
    
    // Jixun: using time stamp.
    var cUpdater = parseInt($Get('ScamFilterUpdate', getToday() - 1));
    if (bDebugUpdate)
        console.log ('cUpdater ::', cUpdater, thisScriptMetaURL);
    
    // If it's older than today then check.
    // Or the user don't want it update :(
    if ($$.dailyUpdate && cUpdater < getToday()){
        // Retrieve the piece
        $.ajax({
            url: thisScriptMetaURL, 
            dataType: 'text', 
            cache: false,
            success: checkUpdates
        });
    }
    
    function checkUpdates(data){
        if (bDebugUpdate)
            console.log ('Func :: checkUpdates ::', arguments);
        
        // Extract Scam Hider's current version number from the retrieved data...
        var currentVersion = (GM_info.script.version),
            latestVersion  = ((data.match(/@version(\s+)(.+)/i)||[,,0])[2]);
        
        // Debug offset:
        console.log ('Installed version: ', currentVersion,
                     'Latest version: ',    latestVersion   );
        
        // and compare it to the installed version number.
        if (currentVersion != latestVersion){
            // If the current version number retrieved is greater than the installed version number, show our update notice.
            $('span.upd').html(notify);
            
            // Set the notification link's tooltip to show installed + latest versions
            $('a.notify').attr('title','当前版本: ' + currentVersion + '\n最新版本: ' + latestVersion);
        } else {
            // Script updated
            $Set ('ScamFilterUpdate', getToday());
        }
    }
    
});

0 comments:

Post a Comment