如何在outlook.com网络邮件中拦截使用Firefox XUL扩展程序上传电子邮件附件

时间:2013-10-29 16:54:50

标签: javascript dom encryption outlook xul

我有一个XUL扩展,它使用本机Windows DLL和js-ctypes来加密本地文件系统中的文件。我已经测试了它的菜单驱动版本,它似乎工作正常。

现在我想执行以下操作:在创建带附件的新电子邮件时,能够“上传”附件文件并在上传到撰写的电子邮件之前对其进行处理(意思是:加密)。我想以透明的方式做到这一点,因此除了提供加密密码之外,用户不必经过菜单驱动的过程。

我想在outlook.com基于网络的电子邮件(不是Office版本)中执行此操作。

我知道这是一个很长的镜头,但有人知道从哪里开始寻找?过去有人做过这样的事吗?

提前致谢!

1 个答案:

答案 0 :(得分:1)

一个好的起点是一个已经做你想要的插件(以通用的方式):

https://addons.mozilla.org/en-US/firefox/addon/tamper-data/

在下载页面上显示Use tamperdata to view and modify HTTP/HTTPS headers and post parameters。你有兴趣改变'后期参数',这是一个很好的起点。


但如果你只是想自己实现这个......

我已经无序地回答了这个问题,以便在开发中构建解决方案方面取得进展。

在最终扩展中,您需要:

  1. 拦截请求
  2. 定位正确的请求
  3. 获取对POST请求正文的访问权限
  4. 解析POST请求正文的表单数据(以获取真正的二进制文件数据)
  5. 执行加密步骤
  6. 重新编码二进制文件数据,重新组合表单数据,并修改POST请求标题
  7. 替换POST请求中的现有内容。

  8. 拦截请求&替换现有的POST内容

    基础是你需要实现nsIObserver传递nsIHTTPChannel作为观察的“主题”。您希望观察的“通知”称为http-on-modify-request

    有一些简单的示例(12)用于拦截GET文档中的http-on-modify-request个请求,但拦截POST请求更复杂。

    获取POST请求正文:

    有一个mozillazine forum thread处理这个确切的主题。 Kamelot9该帖子中的第二篇帖子详细说明了如何(1)获取帖子正文:

    var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
    var uploadChannel = httpChannel.QueryInterface(Ci.nsIUploadChannel);
    var uploadChannelStream = uploadChannel.uploadStream;
    uploadChannelStream
        .QueryInterface(Ci.nsISeekableStream)
        .seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
    var stream = Cc["@mozilla.org/binaryinputstream;1"]
        .createInstance(Ci.nsIBinaryInputStream);
    stream.setInputStream(uploadChannelStream);
    var postBytes = stream.readByteArray(stream.available());
    var poststr = String.fromCharCode.apply(null, postBytes);
    

    此处aSubject此处作为http-on-modify-request通知的参数。然后,您只需修改poststr即可。您可能还需要修改Content-length标题(或者您的帖子可能会被截断),具体取决于服务器。

    替换POST请求内容:

    一旦你修改了POST主体,你需要(2)用你自己的inputStream替换uploadChannel的现有内容:

    var inputStream = Cc["@mozilla.org/io/string-input-stream;1"]
        .createInstance(Ci.nsIStringInputStream);
    inputStream.setData(poststr, poststr.length);
    uploadChannel.setUploadStream(
        inputStream, 
        "application/x-www-form-urlencoded", 
        -1);
    // do this last - setUploadStream resets requestMethod to PUT
    httpChannel.requestMethod = "POST";
    
    上面的

    CcCi分别只是Components.classesComponents.interfaces的简写。这些速记变量可能已经设置好,或者您可以自己定义它们。

    解析表单数据:

    我认为通常对于文件上传,Content-type:将是multipart/form-data

    要了解您感兴趣的特定“附件”,您需要:

    1. 解析mime信封以获取文件附件
    2. 查找文件附件
    3. 删除所使用的任何文本编码(例如:BASE64
    4. 在POST标题中,您将获得类似的内容:

      Content-Type: multipart/form-data; boundary=JGUOAeGT3Fjgjcdk6s35F2mPVVyTdzgR
      

      其中'JGUOAeGT3Fjgjcdk6s35F2mPVVyTdzgR'是MIME边界。在POST的正文中,将开始的内容将格式如下:

      --[boundary]
      CONTENT-PART #1
      --[boundary]
      CONTENT-PART #2
      --[boundary]
      

      上面的每个CONTENT-PART都会有一些HTTP标题,一个空行,然后是特定CONTENT-PART的正文。

      来自另一个stackoverflow question的示例:

      Content-Disposition: form-data; name="updates"; filename="update1353963418000.json"
      Content-Type: application/json; charset=UTF-8
      Content-Transfer-Encoding: binary
      
      {"collectionType":"activities","date":"2012-11-26","ownerId":"qw12er23","ownerType":"user","subscriptionId":"112233-activities"}]
      

      在这种情况下,Content-Transfer-Encoding是二进制(原始编码)UTF8,因此您无需再做任何工作就可以读取CONTENT-PART正文中的JSON

      在您的情况下,浏览器将发送一个二进制文件,因此它可能已将Content-Transfer-Encoding设置为base64,这意味着您需要对其进行Base64解码。 CONTENT-PART来获取真正的二进制文件。如果base64data包含编码内容,那么这将为您提供原始二进制数据:

      var rawData = atob(base64data);
      

      此时,您可以在rawData上执行任何加密。

      记住,你必须在加密后重新编码二进制数据(使用btoa),然后在重新构建POST请求体之前,你需要重新组装多部分信封。 (不要忘记获取最终请求正文的.length,以便您可以替换请求标头中的Content-length。)。

      定位请求:

      这是修改POST请求的基本机制。但您仍然需要单独输出您的特定POST请求(检查观察者通知中的POST请求URL),以便允许其他POST请求正常进行而不调用您的修改代码。