代码之家  ›  专栏  ›  技术社区  ›  Gunther Schadow

我的网页需要jszip和gzip,jszip包含所有的成分,但以我无法破解的方式隐藏它们。

  •  0
  • Gunther Schadow  · 技术社区  · 6 年前

    在javascript中对gzip的支持非常弱。所有浏览器都实现它来支持内容编码:gzip头,但是没有对浏览器的gzip/gunzip功能的标准访问。因此,必须使用仅限javascript的方法。附近有一些旧的gzip JS库,但它们似乎不支持流,并且需要6年的维护。

    然后是pako,更积极地维护,但是如果使用自己的分发版,也不会看到流启用,因此需要将整个二进制数组和gzip输出保存在内存中。我可能错了,但这正是我所收集的。

    JSzip是一个设计良好的工具,支持流“workers”。jszip使用pako。ZIP条目是放气的,有一个CRC32校验和,就像gzip一样,当然只有稍微不同的组织。仅仅考虑一下jszip源代码,就可以很容易地将pako的gzip压缩选项公开到jszip的流支持中。如果我同时使用jszip和gzip,为什么我要加载两次pako?

    我希望我可以直接将jszip的内部结构扩展到底层的工作人员,并使用基于pako的“flat”(即在flat/de flat中)实现和pako认可的gzip选项。用chrome javascript控制台进行了探索,但我无法通过。可分发的可加载jszip.js或jszip-min.js隐藏了所有内部构件,使其无法访问脚本。我不能打开那个盒子。

    因此,我一直在研究Git Hub源代码,以了解我是否可以构建自己的jszip.js或jszip-min.js可加载模块,在这里我可以导出更多的内部资源以在页面中使用,但在这20年中,Unix生成文件、Ant以及所有东西,当涉及到这些封装JavaScript的技巧时,我觉得自己是一个完全的新手。模块,我看到了Bower和“gruntfiles”,它们似乎都与node.js相关,我不需要(只需要客户端浏览器),也从未使用过,所以我不知道从哪里开始。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Gunther Schadow    6 年前

    正如Evert所说,我应该先检查文档中的构建说明 https://stuk.github.io/jszip/documentation/contributing.html .

    很明显,第一个需要git并生成本地克隆。然后需要设置grunt命令行,这需要npm,它与nodejs一起提供。一旦Grunt运行,还有其他的依赖项需要安装NPM。这是通常的小事情关闭和不工作,但足够的瞪大眼睛和蛮力重试来完成。

    现在jszip/lib/index.js包含最终导出的资源。它是jszip对象。因此,为了处理内部内容,我可以将这些内容添加到jszip对象中,例如,它已经包含:

    JSZip.external = require("./external");
    module.exports = JSZip;
    

    因此,我们可以轻松地添加其他要使用的资源:

    JSZip.flate = require("./flate");
    JSZip.DataWorker = require('./stream/DataWorker');
    JSZip.DataLengthProbe = require('./stream/DataLengthProbe');
    JSZip.Crc32Probe = require('./stream/Crc32Probe');
    JSZip.StreamHelper = require('./stream/StreamHelper');
    JSZip.pako = require("pako");
    

    现在,我可以在chrome调试器中创建概念验证:

    (new JSZip.StreamHelper(
       (new JSZip.DataWorker(Promise.resolve("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!")))
          .pipe(new JSZip.DataLengthProbe("uncompressedSize"))
          .pipe(new JSZip.Crc32Probe())
          .pipe(JSZip.flate.compressWorker({}))
          .pipe(new JSZip.DataLengthProbe("compressedSize"))
          .on("end", function(event) { console.log("onEnd: ", this.streamInfo) }), 
       "uint8array", "")
    ).accumulate(function(data) { console.log("acc: ", data); })
     .then(function(data) { console.log("then: ", data); })
    

    这是可行的。我用gzip头和尾把自己变成了gzip文件流,正确地创建了一切。我将jszip/lib/generate/gzip文件worker.js放在下面:

    'use strict';
    
    var external = require('../external');
    var utils = require('../utils');
    var flate = require('../flate');
    var GenericWorker = require('../stream/GenericWorker');
    var DataWorker = require('../stream/DataWorker');
    var StreamHelper = require('../stream/StreamHelper');
    var DataLengthProbe = require('../stream/DataLengthProbe');
    var Crc32Probe = require('../stream/Crc32Probe');
    
    function GZipFileWorker() {
        GenericWorker.call(this, "GZipFileWorker");
        this.virgin = true;
    }
    utils.inherits(GZipFileWorker, GenericWorker);
    
    GZipFileWorker.prototype.processChunk = function(chunk) {
        if(this.virgin) {
            this.virgin = false;
            var headerBuffer = new ArrayBuffer(10);
            var headerView = new DataView(headerBuffer);
            headerView.setUint16(0, 0x8b1f, true); // GZip magic
            headerView.setUint8(2, 0x08); // compression algorithm DEFLATE
            headerView.setUint8(3, 0x00); // flags
            // bit 0   FTEXT
            // bit 1   FHCRC
            // bit 2   FEXTRA
            // bit 3   FNAME
            // bit 4   FCOMMENT
            headerView.setUint32(4, (new Date()).getTime()/1000>>>0, true);
            headerView.setUint8(8, 0x00); // no extension headers
            headerView.setUint8(9, 0x03); // OS type UNIX
            this.push({data: new Uint8Array(headerBuffer)});
        }
        this.push(chunk);
    };
    
    GZipFileWorker.prototype.flush = function() {
        var trailerBuffer = new ArrayBuffer(8);
        var trailerView = new DataView(trailerBuffer);
        trailerView.setUint32(0, this.streamInfo["crc32"]>>>0, true);
        trailerView.setUint32(4, this.streamInfo["originalSize"]>>>0 & 0xffffffff, true);
        this.push({data: new Uint8Array(trailerBuffer)});
    };
    
    exports.gzip = function(data, inputFormat, outputFormat, compressionOptions, onUpdate) {
        var mimeType = data.contentType || data.mimeType || "";
        if(! (data instanceof GenericWorker)) {
            inputFormat = (inputFormat || "").toLowerCase();
            data = new DataWorker(
                utils.prepareContent(data.name || "gzip source",
                                     data,
                                     inputFormat !== "string",
                                     inputFormat === "binarystring",
                                     inputFormat === "base64"));
        }
        return new StreamHelper(
            data
                .pipe(new DataLengthProbe("originalSize"))
                .pipe(new Crc32Probe())
                .pipe(flate.compressWorker( compressionOptions || {} ))
                .pipe(new GZipFileWorker()),
            outputFormat.toLowerCase(), mimeType).accumulate(onUpdate);
    };
    

    在jszip/lib/index.js中,我只需要:

    var gzip = require("./generate/GZipFileWorker");
    JSZip.gzip = gzip.gzip;
    

    这样的工作原理是:

    JSZip.gzip("Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!", "string", "base64", {level: 3}).then(function(result) { console.log(result); })
    

    我可以将结果粘贴到Unix管道中,如下所示:

    $ echo -n "H4sIAOyR/VsAA/NIzcnJVwjPL8pJUVTwoJADAPCORolNAAAA" |base64 -d |zcat
    

    它正确地返回

    Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!
    

    它还可以与文件一起使用:

    JSZip.gzip(file, "", "Blob").then(function(blob) { 
         xhr.setRequestProperty("Content-encoding", "gzip");
         xhr.send(blob); 
      })
    

    我可以将blob发送到我的Web服务器。我已经检查过大文件确实是分块处理的。

    我唯一不喜欢的是,最后一个blob仍然组装成一个大blob,所以我假设它在内存中保存所有压缩数据。如果该攻击是该工作管道的端点,这样当xhr.send从blob中逐块获取数据时,它将仅在那时使用工作管道中的块。但是,由于它只保存压缩内容,因此影响会大大降低,而且(至少对我而言)大型文件可能是不需要gzip压缩的多媒体文件。

    我没有编写gunzip函数,因为坦率地说,我不需要它,也不想让它无法正确解析gzip头中的扩展头。一旦我将压缩内容上传到服务器(在我的例子中是S3),当我再次获取它时,我假设浏览器会为我进行解压缩。不过我还没检查过。如果它成为一个问题,我会回来编辑这个答案更多。

    这是我在Github的叉子: https://github.com/gschadow/jszip ,已输入拉请求。