Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F20064636
pEpListener.jsm
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
6 KB
Subscribers
None
pEpListener.jsm
View Options
/*global Components: false */
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* This module serves to integrate pEp into Enigmail
*
* The module is still a prototype - not ready for daily use!
*/
"use strict";
var EXPORTED_SYMBOLS = ["EnigmailpEpListener"];
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
const MIN_PORT_NUM = 15900;
const MAX_PORT_NUM = 15991;
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); /*global XPCOMUtils: false */
Cu.import("resource://enigmail/log.jsm"); /*global EnigmailLog: false */
Cu.import("resource://enigmail/data.jsm"); /*global EnigmailData: false */
const HTTP_OK = "200";
const HTTP_ERR_BAD_REQUEST = "400";
const HTTP_ERR_UNAUTHORIZED = "401";
const HTTP_ERR_INTERNAL_ERROR = "500";
const HTTP_ERR_NOT_IMPLEMENTED = "501";
function PepListener(callBackFunction, securityToken) {
this.callBackFunction = callBackFunction;
this.securityToken = securityToken;
}
function getHttpBody(req) {
let i = req.search(/\r?\n\r?\n/);
if (i > 0) {
++i;
return req.substr(i);
}
return req;
}
/**
* Create a HTTP resonse to send back
*/
function createHttpResponse(statusCode, messageData) {
let dt = new Date();
let retObj;
let statusMsg;
if (statusCode === HTTP_OK) {
retObj = {
jsonrpc: "2.0",
result: {
outParams: [],
return: {
status: 0,
hex: "PEP_STATUS_OK"
}
},
id: messageData
};
statusMsg = "OK";
}
else {
retObj = {
jsonrpc: "2.0",
error: {
code: -statusCode,
message: messageData
}
};
statusMsg = messageData;
}
let data = JSON.stringify(retObj);
let msg = "HTTP/1.1 " + statusCode + " " + statusMsg + "\r\n" +
"Content-Type: text/plain\r\n" +
"Date: " + dt.toUTCString() + "\r\n" +
"Content-Length: " + (data.length + 2) + "\r\n\r\n" + data + "\r\n";
return msg;
}
PepListener.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIServerSocketListener]),
reader: {
self: null,
onInputStreamReady: function(input) {
let sin = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
sin.init(input);
let requestData = "";
try {
while (sin.available()) {
requestData += sin.read(512);
}
}
catch (ex) {
EnigmailLog.DEBUG("pEpListener.onInputStreamReady: input stream closed\n");
return;
}
EnigmailLog.DEBUG("pEpListener.onInputStreamReady: got data '" + requestData + "'\n");
let responseData = this.self.handleHttpRequest(requestData);
EnigmailLog.DEBUG("pEpListener.onInputStreamReady: sending response '" + responseData + "'\n");
this.self.output.write(responseData, responseData.length);
this.self.output.flush();
let tm = Cc["@mozilla.org/thread-manager;1"].getService();
input.asyncWait(this.self.reader, 0, 0, tm.mainThread);
}
},
onSocketAccepted: function(serverSocket, clientSocket) {
EnigmailLog.DEBUG("pEpListener.onSocketAccepted: New connection on " + serverSocket.port + "\n");
this.clientSocket = clientSocket;
this.serverSocket = serverSocket;
this.input = clientSocket.openInputStream(0, 0, 0).QueryInterface(Ci.nsIAsyncInputStream);
this.output = clientSocket.openOutputStream(Ci.nsITransport.OPEN_BLOCKING, 0, 0);
this.reader.self = this;
let tm = Cc["@mozilla.org/thread-manager;1"].getService();
this.input.asyncWait(this.reader, 0, 0, tm.mainThread);
},
onStopListening: function(serverSocket, status) {
EnigmailLog.DEBUG("pEpListener.onStopListening: Closing connection on " + serverSocket.port + "\n");
},
/**
* handle a HTTP request and return the HTTP response message string
*
* @param requestData - String: HTTP request
*
* @return String: HTTP response
*/
handleHttpRequest: function(requestData) {
let responseData = "";
let obj;
if (requestData.search(/^POST/i) === 0) {
requestData = getHttpBody(requestData);
requestData = EnigmailData.convertToUnicode(requestData, "utf-8");
try {
obj = JSON.parse(requestData);
}
catch (ex) {
return createHttpResponse(HTTP_ERR_BAD_REQUEST, "Bad request: no proper JSON object.");
}
try {
let tok = this.securityToken;
if ("security_token" in obj && obj.security_token === this.securityToken) {
let msgId = 1;
if ("id" in obj) {
msgId = obj.id;
}
if (this.callBackFunction) {
let r = this.callBackFunction(obj);
if (r === 0) {
return createHttpResponse(HTTP_OK, msgId);
}
return createHttpResponse(HTTP_ERR_NOT_IMPLEMENTED, "Method not implemented.");
}
return createHttpResponse(HTTP_OK, msgId);
}
else {
return createHttpResponse(HTTP_ERR_UNAUTHORIZED, "Wrong security token.");
}
}
catch (ex) {
EnigmailLog.writeException("pEpListener.handleHttpRequest", ex);
return createHttpResponse(HTTP_ERR_INTERNAL_ERROR, "Internal exception.");
}
}
return createHttpResponse(HTTP_ERR_BAD_REQUEST, "Bad request: unsupported HTTP method.");
}
};
var EnigmailpEpListener = {
/**
* returns port number or -1 in case of failure
*/
createListener: function(callBackFunction, securityToken) {
let serverSocket = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket);
let portNum = MIN_PORT_NUM;
while (portNum < MAX_PORT_NUM) {
try {
serverSocket.init(portNum, true, -1);
let l = new PepListener(callBackFunction, securityToken);
serverSocket.asyncListen(l);
EnigmailLog.DEBUG("pEpListener.createListener: Listening on port " + portNum + "\n");
return portNum;
}
catch (ex) {
if (ex.name === "NS_ERROR_SOCKET_ADDRESS_IN_USE") {
++portNum;
}
else
portNum = MAX_PORT_NUM + 1;
}
}
return -1;
}
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 23, 7:20 PM (11 h, 30 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ba/8c/2034a88d9bb970ab1490d43c6df3
Attached To
rENIG Enigmail
Event Timeline
Log In to Comment