tampermonkey的一个坑

关于Tampermonkey脚本开发时遇到的一个坑

  • GM_XmlhttpRequest
    这个GM函数在wiki上是如此解释的:

Make an xmlHttpRequest.
Property of details:
method one of GET, HEAD, POST
url the destination URL
headers ie. user-agent, referer, ... (some special headers are not supported by Safari and Android browsers)
data some string to send via a POST request
binary send the data string in binary mode
timeout a timeout in ms
context a property which will be added to the response object
responseType one of arraybuffer, blob, json
overrideMimeType a MIME type for the request
anonymous don't send cookies with the requests (please see the fetch notes)
fetch (beta) use a fetch instead of a xhr request
(at Chrome this causes xhr.abort, details.timeout and xhr.onprogress to not work and makes >xhr.onreadystatechange receive only readyState 4 events)
username a username for authentication
password a password
<events> onload, onerror, onreadystatechange, onprogress, onloadstart, ontimeout

在这个地方,约定了Data参数,与ajax的不同,是使用string字符串的形式,详细表述在网上也有一些,但是问题不在这里
比较坑的是,使用post方法传送数据时,一直出现400错误,经过反复排查,才发现headers首部设置不能随便添加值,headers的字段会对请求发生干扰,由于chrome环境没法捕获数据包,因此不清楚到底是哪里发生了错误。

解决这个错误之后,又发现,不设置headers字段时,服务器上会接收不到参数
必须设置headers参数为

headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }

至此,一个完整的post请求才算正常

API停止

Typecho竟然有0day,已更新迁移到新版本,API ALL down,转至其他地方

直播间自动领便当的升级

记一次脚本升级

2017年10月下旬,伟大的二次元同性交友网站更新了他们的直播页面,在前几天反复收到脚本更新的反馈请求,于是抽了两天时间仔细研究了一下 BiliBili 的新直播间页面。

  • api.live.bilibili.com和live.bilibili.com混用

在新的页面上,所有的数据接口全部转向了api.live.bilibili.com,使用jsonp的方法跨域请求,尤其是宝箱验证码的部分,也是这样一个跨域的图片,由于跨子域的图片会污染canvas导致无法识别,所以这否决了在当前页面中进行验证码识别的方案,只能另外寻找识别方法。

基于iframe的跨子域通信的方法,可以将验证码识别单独放在一个iframe中,脚本另外绑定该网址,在该网址中进行验证码识别,在需要识别验证码的时候,主页面打开iframe,脚本完成识别后立即回调主页面的验证函数,即可做到处理图片跨域的问题。

这里也很想吐槽 标准 ,明明iframe都可以跨子域相互通信,那么禁止图片跨子域的意义不大啊……如果可以使用脚本的话,不过这对网站方来说还是有一定意义的。

  • vue.js使用的双向绑定技术无法识别JS操作value的结果

在vue.js的双绑中,是没法识别到JS对input元素的操作的,因此在验证码识别完成后,提交之时还是会显示验证码为空,原因在于v-model中的值没有能够正确改变。

网上对与该问题只找到一个处理办法,使用.focus函数先使input取得焦点,实际测试的时候还是发现并不能做到100%解决这个问题,其他方案大多数是建议操作input时同样适用vue.js内部的方法。

该问题困扰了我很长时间,最后依然无法解决,只能另外写一套计时程序,仿照其API与后台进行通讯,也就是目前的做法。于是又不得不写了一套消息提示函数和ajax函数。最后使用iframe进行回调。

整个处理的流程就是在第一次载入以后读取目前的宝箱状态,然后将原有的宝箱隐藏,用自己的一套计时函数替代原有的函数,最后按照流程嵌套,即可完成最终的识别和验证过程

有一个比较坑的就是在验证完成之后,需要请求另一个API来刷新服务器的宝箱状态,这个我觉得是多余的,但是不得不加上去。否则服务器不会为下一个宝箱计时。

最后将脚本整合在同一个脚本中,完成一些扫尾工作,就算是完成这一次升级了。

javascript验证码识别小记

关于javascript进行的简单的验证码识别

  • 示例验证码:bilibili直播间领瓜子算式验证码(120px*40px)

getCaptcha (1).jpg

经过分析,该验证码满足三个特征

  1. 长度固定,左边两个数字,然后一个符号,右边一个数字,总长度4位。
  2. 字符有限,0-9共10个数字,再加上一个加号和一个减号。
  3. 样式单一,没有字体变化,干扰元素极少,字符之间有一定的空隙。

这篇博客中,它使用了提取各个数字的区块的识别方法,但是该方法只能应用在字符位置固定且等宽的情况,在bilibili这个验证码中,字符的初始位置并不固定,不能通过公式进行切割,字符的宽度也不相等,所以只能另外寻找方法

根据上面的规律和这次验证码的特殊性,可以确定出识别方案:

  1. 先通过二值化,将锯齿像素排除,将图片转为特定的二值化后的矩阵
  2. 依据空白,将字符分割开来
  3. 将分割开的字符分别确定其特征

分割开的字符,二值化后可以产生白色像素和黑色像素,在这里用1表示黑色像素,这样的话我们就可以成功表示出二值化后的像素矩阵

代码如下:

            var ctx = $("#helper_canvas")[0].getContext("2d");
            var pixels = ctx.getImageData(0,0,120,40).data;
            //console.log(pixels);
            var pix = []; //定义一维数组
            var j = 0;
            var i=0;
            var n=0;
            for(i=1;i<=40;i++)
            {
                pix[i] = []; //将每一个子元素又定义为数组
                for(n=1;n<=120;n++)
                {
                    let c = 1;
                    if(pixels[j]-(-pixels[j + 1])-(- pixels[j + 2]) >200){
                        c=0;
                    }
                    j = j+4;
                    pix[i][n]=c; //此时pix[i][n]可以看作是一个二级数组
                }
            }
            //我们得到了二值化后的像素矩阵pix[40][120]

通过这个二值矩阵,我们将每一列求和,为0的位置就是该列全都是空白,因此可以求出一个和的数组lie[120],该数组记录了每一列上黑色像素的个数。
于是通过切割0的部分,我们可以将其各个字符的分割出来,并且去获得每一个字符的像素总数,第一列的像素数和最后一列的像素数。

代码如下:

    

    var lie = [];
    lie[0]=0;
    for(i=1;i<=120;i++){
        lie[i] = 0;
        for(n=1;n<=40;n++){
            lie[i] = lie[i]+pix[n][i];
        }
    }
    var ta = [];
    n=0;
    for(i=1;i<=120;i++){
        if(lie[i]>0&&lie[i-1]===0){
            n++;
            ta[n] = new Object();
            ta[n].fi = lie[i];
            ta[n].total = 0;
        }
        if(lie[i]>0){
            ta[n].total = ta[n].total+lie[i];
        }
        if(lie[i-1]>0&&lie[i]===0){
            ta[n].la = lie[i-1];
        }
    }

通过该代码,我们可以依据二值化矩阵得出每一个字符的三个属性,包括:像素个数,第一列像素个数,和最后一列像素个数
通过总像素个数,我们已经能够区分大部分的字符,但是0、6、9三个字符的像素个数接近,只能通过第一列像素个数和最后一列像素个数进行区分。

在对十几张验证码进行统计以后,我们可以大概得出如下的识别函数:

  function get_word(a){
        if(a.total<=50) return "-";
        if(a.total>120&&a.total<135) return "+";
        if(a.total>155&&a.total<162) return 1;
        if(a.total>189&&a.total<195) return 7;
        if(a.total>228&&a.total<237) return 4;
        if(a.total>250&&a.total<260) return 2;
        if(a.total>286&&a.total<296) return 3;
        if(a.total>303&&a.total<313) return 5;
        if(a.total>335&&a.total<342) return 8;
        if(a.total>343&&a.total<350){
            if(a.fi>24&&a.la>24) return 0;
            if(a.fi<24&&a.la>24) return 9;
            if(a.fi>24&&a.la<24) return 6;

        }

    }

通过该识别函数,即可得出四个字符,最后进行一下算式加减即可完成识别
最终效果:1.gif

本项目地址:bilibili自动领瓜子

Windows云服务器部署 GitBlit 方法与注意事项

Windows云服务器部署 GitBlit 方法与注意事项

GitBlit 是一个由Java实现的Git服务器,功能上与目前的GitHub差不多,但是这个是开源且免费的

首先前往GitBlit官网下载程序,主要使用GitBlit的GO版本,这个版本功能比较全面

链接:GitBlit.

另外需要一个Java,网上的教程推荐JDK的居多,其实只需要JRE即可,java1.8也能够使用。

部署步骤:

  1. 在云服务器上安装好对应版本的java,并将java安装目录下,bin目录添加到系统环境变量中
  2. 将下载的GitBlit程序解压,目前最新版为1.8,需要修改data文件夹下 defaults.properties 文件,这里保存的是系统默认的配置,我是直接在这个文件中修改的,也可以先修改 gitblit.properties ,在其中include你自己修改的配置文件。

    • git.repositoriesFolder 这个是存放Git仓库的文件夹
    • server.httpPort 和server.httpsPort 分别为http协议和https 协议的端口,一般将server.httpsPort设置为0,来禁用HTTPS
    • server.httpBindInterface 和server.httpsBindInterface 宿主监控的网络接口 ,就是服务器端访问的网址,如果上一步禁用了HTTPS,那么这里server.httpsBindInterface就无所谓了

    注意,在云服务器环境下,配置完毕以后可能会有绑定端口失败的情况,就是这一步出的问题,在云服务器中,不可以填写他自己的ip,只能使用0.0.0.0来代替

  3. 运行GitBlit,然后通过浏览器填入IP访问,能正常打开网站就表明程序是正常的。

在本地向远程仓库PULL/PUSH的时候一直处于同步状态不传输数据,经过排查,将服务器安全组放通全部端口即可(可视需要禁止一些高危端口)

在后期,还可以调整目录下的 installService.cmd,将其设为windows服务,在后台运行。具体设置步骤为:

  • SET ARCH 这里设置为你的系统位数,32位的是x86,64位的是amd64,

比如我就是 SET ARCH=amd64

  • 然后在这个下面添加一行SET CD=C:FTPGitgitblit-1.8.0 ,后面这个是你GitBlit目录的完全路径
  • 将下方--StartParams的参数删除

最后的文件应该类似于此:

@REM arch = x86, amd64, or ia32
SET ARCH=amd64
SET CD=C:FTPGitgitblit-1.8.0
@REM Be careful not to introduce trailing whitespace after the ^ characters.
@REM Use ; or # to separate values in the --StartParams parameter.
"%CD%%ARCH%gitblit.exe" //IS//gitblit ^

     --DisplayName="gitblit" ^
     --Description="a pure Java Git solution" ^
     --Startup=auto ^
     --LogPath="%CD%\logs" ^
     --LogLevel=INFO ^
     --LogPrefix=gitblit ^
     --StdOutput=auto ^
     --StdError=auto ^
     --StartPath="%CD%" ^
     --StartClass=org.moxie.MxLauncher ^
     --StartMethod=main ^
     --StartParams="" ^
     --StartMode=jvm ^
     --StopPath="%CD%" ^
     --StopClass=org.moxie.MxLauncher ^
     --StopMethod=main ^
     --StopParams="--stop;--baseFolder;%CD%\data" ^
     --StopMode=jvm ^
     --Classpath="%CD%\gitblit.jar" ^
     --Jvm=auto ^
     --JvmMx=1024