1

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

现在我想做以下事情:在创建带有附件的新电子邮件时,能够“捕获”附件文件并在上传到撰写的电子邮件之前对其进行处理(意思是:加密它)。我想以一种透明的方式来做,这样用户就不必通过菜单驱动的过程,除了提供加密密码。

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

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

提前致谢!

4

1 回答 1

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 请求中的现有内容。

拦截请求并替换现有的 POST 内容

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

的文档中有拦截请求的简单示例(1、2 ,但是拦截请求更复杂。GEThttp-on-modify-requestPOST

获取 POST 请求正文:

有一个mozillazine 论坛主题处理这个确切的主题。 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:)

在 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问题的示例:

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.

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

var rawData = atob(base64data);

那时你可以做任何你想做的加密rawData

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

针对请求:

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

于 2014-01-08T03:07:34.983 回答