commit 695cb4710669a6580a74b28989f06932c9162793
parent d8783a93a0c4f9880020723a79d3667173f60aec
Author: Simon Kornblith <simon@simonster.com>
Date: Tue, 3 Jul 2012 19:50:12 -0400
Only allow endpoints specifically marked as permitted to be accessed by the bookmarklet to be accessed by the bookmarklet.
Diffstat:
2 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/chrome/content/zotero/xpcom/server.js b/chrome/content/zotero/xpcom/server.js
@@ -216,7 +216,19 @@ Zotero.Server.DataListener.prototype._headerFinished = function() {
Zotero.debug(this.header, 5);
const methodRe = /^([A-Z]+) ([^ \r\n?]+)(\?[^ \r\n]+)?/;
- const contentTypeRe = /[\r\n]Content-Type: +([^ \r\n]+)/i;
+ const contentTypeRe = /[\r\n]Content-Type: *([^ \r\n]+)/i;
+
+ if(!Zotero.isServer) {
+ const originRe = /[\r\n]Origin: *([^ \r\n]+)/i;
+ var m = originRe.exec(this.header);
+ if(m) {
+ this.origin = m[1];
+ } else {
+ const bookmarkletRe = /[\r\n]X-Zotero-Bookmarklet: *([^ \r\n]+)/i;
+ var m = bookmarkletRe.exec(this.header);
+ if(m) this.origin = "https://www.zotero.org";
+ }
+ }
// get first line of request
var method = methodRe.exec(this.header);
@@ -294,11 +306,8 @@ Zotero.Server.DataListener.prototype._generateResponse = function(status, conten
if(!Zotero.isServer) {
response += "X-Zotero-Version: "+Zotero.version+"\r\n";
response += "X-Zotero-Connector-API-Version: "+CONNECTOR_API_VERSION+"\r\n";
-
- const originRe = /[\r\n]Origin: +([^ \r\n]+)/i;
- var m = originRe.exec(this.header);
- if(m && (m[1] === "https://www.zotero.org" || m[1] === "http://www.zotero.org")) {
- response += "Access-Control-Allow-Origin: "+m[1]+"\r\n";
+ if(this.origin === "https://www.zotero.org" || this.origin === "http://www.zotero.org") {
+ response += "Access-Control-Allow-Origin: "+this.origin+"\r\n";
response += "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n";
response += "Access-Control-Allow-Headers: Content-Type,X-Zotero-Connector-API-Version,X-Zotero-Version\r\n";
}
@@ -324,12 +333,24 @@ Zotero.Server.DataListener.prototype._processEndpoint = function(method, postDat
try {
var endpoint = new this.endpoint;
- // check that endpoint supports method
+ // Check that endpoint supports method
if(endpoint.supportedMethods && endpoint.supportedMethods.indexOf(method) === -1) {
this._requestFinished(this._generateResponse(400, "text/plain", "Endpoint does not support method\n"));
return;
}
+ // Check that endpoint supports bookmarklet
+ if(this.origin) {
+ var isBookmarklet = this.origin === "https://www.zotero.org" || this.origin === "http://www.zotero.org";
+ // Disallow bookmarklet origins to access endpoints without permitBookmarklet
+ // set. We allow other origins to access these endpoints because they have to
+ // be privileged to avoid being blocked by our headers.
+ if(isBookmarklet && !endpoint.permitBookmarklet) {
+ this._requestFinished(this._generateResponse(403, "text/plain", "Access forbidden to bookmarklet\n"));
+ return;
+ }
+ }
+
var decodedData = null;
if(postData && this.contentType) {
// check that endpoint supports contentType
diff --git a/chrome/content/zotero/xpcom/server_connector.js b/chrome/content/zotero/xpcom/server_connector.js
@@ -70,6 +70,7 @@ Zotero.Server.Endpoints["/connector/getTranslators"] = Zotero.Server.Connector.G
Zotero.Server.Connector.GetTranslators.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Gets available translator list and other important data
@@ -121,6 +122,7 @@ Zotero.Server.Connector.Data = {};
Zotero.Server.Connector.Detect.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Loads HTML into a hidden browser and initiates translator detection
@@ -209,6 +211,7 @@ Zotero.Server.Endpoints["/connector/savePage"] = Zotero.Server.Connector.SavePag
Zotero.Server.Connector.SavePage.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Either loads HTML into a hidden browser and initiates translation, or saves items directly
@@ -311,6 +314,7 @@ Zotero.Server.Endpoints["/connector/saveItems"] = Zotero.Server.Connector.SaveIt
Zotero.Server.Connector.SaveItem.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Either loads HTML into a hidden browser and initiates translation, or saves items directly
@@ -372,6 +376,7 @@ Zotero.Server.Endpoints["/connector/saveSnapshot"] = Zotero.Server.Connector.Sav
Zotero.Server.Connector.SaveSnapshot.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Save snapshot
@@ -454,6 +459,7 @@ Zotero.Server.Endpoints["/connector/selectItems"] = Zotero.Server.Connector.Sele
Zotero.Server.Connector.SelectItems.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Finishes up translation when item selection is complete
@@ -487,6 +493,7 @@ Zotero.Server.Endpoints["/connector/attachmentProgress"] = Zotero.Server.Connect
Zotero.Server.Connector.Progress.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* @param {String} data POST data or GET query string
@@ -511,6 +518,7 @@ Zotero.Server.Endpoints["/connector/getTranslatorCode"] = Zotero.Server.Connecto
Zotero.Server.Connector.GetTranslatorCode.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Returns a 200 response to say the server is alive
@@ -539,6 +547,7 @@ Zotero.Server.Endpoints["/connector/getSelectedCollection"] = Zotero.Server.Conn
Zotero.Server.Connector.GetSelectedCollection.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
/**
* Returns a 200 response to say the server is alive
@@ -594,6 +603,7 @@ Zotero.Server.Endpoints["/connector/ping"] = Zotero.Server.Connector.Ping;
Zotero.Server.Connector.Ping.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json", "text/plain"],
+ "permitBookmarklet":true,
/**
* Sends nothing
@@ -617,6 +627,7 @@ Zotero.Server.Connector.IEHack = function() {};
Zotero.Server.Endpoints["/connector/ieHack"] = Zotero.Server.Connector.IEHack;
Zotero.Server.Connector.IEHack.prototype = {
"supportedMethods":["GET"],
+ "permitBookmarklet":true,
/**
* Sends a fixed webpage
@@ -642,6 +653,7 @@ Zotero.Server.Endpoints["/translate/select"] = Zotero.Server.Connector.Incompati
Zotero.Server.Connector.IncompatibleVersion.prototype = {
"supportedMethods":["POST"],
"supportedDataTypes":["application/json"],
+ "permitBookmarklet":true,
"init":function(postData, sendResponseCallback) {
sendResponseCallback(404);