From c77fe5462a4106122cb8cfe3e37fce550abd4822 Mon Sep 17 00:00:00 2001 From: Simon Kornblith Date: Thu, 21 Aug 2008 05:46:54 +0000 Subject: [PATCH] references #831, transparent EZProxy support changes default behavior. transparent redirection is now enabled by default, and a caution dialog appears when proxies are first accessed. when transparent redirection is turned off, no dialog appears, and proxies get saved automatically. when the user switches transparent redirection on, there is a warning that s/he should check that there are only trusted proxies in the list. i'm not sure how well i've worded the messages, so feel free to suggest better alternatives. also, a bit of jsdoc cleanup on proxy.js --- .../content/zotero/preferences/preferences.js | 12 ++- chrome/content/zotero/xpcom/proxy.js | 100 ++++++++++++------ chrome/locale/en-US/zotero/zotero.dtd | 8 +- chrome/locale/en-US/zotero/zotero.properties | 7 +- chrome/skin/default/zotero/zotero.css | 6 ++ defaults/preferences/zotero.js | 2 +- 6 files changed, 99 insertions(+), 36 deletions(-) diff --git a/chrome/content/zotero/preferences/preferences.js b/chrome/content/zotero/preferences/preferences.js index d1a085e6db..a2003390b8 100644 --- a/chrome/content/zotero/preferences/preferences.js +++ b/chrome/content/zotero/preferences/preferences.js @@ -1127,6 +1127,16 @@ function refreshProxyList() { */ function updateProxyPrefs() { Zotero.Prefs.set("proxies.autoRecognize", document.getElementById('zotero-proxies-autoRecognize').checked); - Zotero.Prefs.set("proxies.transparent", document.getElementById('zotero-proxies-transparent').checked); + + var oldTransparent = Zotero.Prefs.get("proxies.transparent"); + var newTransparent = document.getElementById('zotero-proxies-transparent').checked; + if(!oldTransparent && newTransparent) { + Components.classes["@mozilla.org/embedcomp/prompt-service;1"] + .getService(Components.interfaces.nsIPromptService).alert(window, + Zotero.getString("proxies.enableTransparentWarning.title"), + Zotero.getString("proxies.enableTransparentWarning.description")); + } + Zotero.Prefs.set("proxies.transparent", newTransparent); + Zotero.Proxies.init() } \ No newline at end of file diff --git a/chrome/content/zotero/xpcom/proxy.js b/chrome/content/zotero/xpcom/proxy.js index a7ba4c1155..9abd62973a 100644 --- a/chrome/content/zotero/xpcom/proxy.js +++ b/chrome/content/zotero/xpcom/proxy.js @@ -26,6 +26,7 @@ /** * A singleton to handle URL rewriting proxies + * @namespace */ Zotero.Proxies = new function() { var on = false; @@ -38,6 +39,9 @@ Zotero.Proxies = new function() { var lastRecognizedURI = false; var lastButton = false; + /** + * Initializes http-on-examine-response observer to intercept page loads and gets preferences + */ this.init = function() { if(!on) { var observerService = Components.classes["@mozilla.org/observer-service;1"] @@ -52,7 +56,11 @@ Zotero.Proxies = new function() { } /** - * Observe method to capture page loads + * Observe method to capture page loads and determine if they're going through an EZProxy. + * At the moment, also clears Content-Disposition header on requests for EndNote files so we + * can capture them instead of letting them get saved as attachments + * + * @param {nsIChannel} channel */ this.observe = function(channel) { channel.QueryInterface(Components.interfaces.nsIHttpChannel); @@ -106,28 +114,21 @@ Zotero.Proxies = new function() { Components.utils.reportError(e); } - if(proxy) { - var checkState = {value:false}; - var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] - .getService(Components.interfaces.nsIPromptService); + if(!transparent) { + // if transparent is turned off, just save the proxy + proxy.save(); + } else if(proxy) { + // otherwise, make sure we want it + var io = {site:proxy.hosts[0], proxy:channel.URI.hostPort}; var window = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator) .getMostRecentWindow("navigator:browser"); + window.openDialog('chrome://zotero/content/proxy.xul', '', 'chrome,modal', io); - if(!lastRecognizedURI || !channel.originalURI || !channel.originalURI.equals(lastRecognizedURI)) { - lastButton = ps.confirmEx(window, - Zotero.getString("proxies.recognized"), - Zotero.getString("proxies.recognized.message"), - ((proxies.length ? 0 : ps.BUTTON_DELAY_ENABLE) + ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK + - ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL + ps.BUTTON_POS_1_DEFAULT), - null, null, null, Zotero.getString("proxies.recognized.disable"), checkState); - lastRecognizedURI = channel.originalURI ? channel.originalURI : channel.URI; - } - - if(lastButton == 0) proxy.save(); - if(checkState.value) { - autoRecognize = false; - Zotero.Prefs.set("proxies.autoRecognize", false); + if(io.add) proxy.save(); + if(io.disable) { + transparent = false; + Zotero.Prefs.set("proxies.transparent", false); } break; @@ -154,6 +155,7 @@ Zotero.Proxies = new function() { /** * Gets all proxy objects + * @type Zotero.Proxy[] */ this.get = function() { if(!proxies) { @@ -166,6 +168,7 @@ Zotero.Proxies = new function() { /** * Removes a proxy object from the list of proxy objects + * @returns {Boolean} True if the proxy was in the list, false if it was not */ this.remove = function(proxy) { var index = proxies.indexOf(proxy); @@ -176,7 +179,7 @@ Zotero.Proxies = new function() { } /** - * Saves a proxy object not previously in the proxy list + * Inserts a proxy into the host map; necessary when proxies are added */ this.save = function(proxy) { proxies.push(proxy); @@ -185,11 +188,10 @@ Zotero.Proxies = new function() { hosts[host] = proxy; } } - return proxy; } /** - * Refreshes host map; necessary when proxies are added, changed, or deleted + * Refreshes host map; necessary when proxies are changed or deleted */ this.refreshHostMap = function() { hosts = {}; @@ -203,7 +205,12 @@ Zotero.Proxies = new function() { } /** - * Returns a page's proper url, adjusting for proxying + * Returns a page's proper URL from a proxied URL + * @param {String} url + * @param {Boolean} onlyReturnIfProxied Controls behavior if the given URL is not proxied. If + * it is false or unspecified, unproxied URLs are returned verbatim. If it is true, the + * function will return "false" if the given URL is unproxied. + * @type String */ this.proxyToProper = function(url, onlyReturnIfProxied) { for each(var proxy in proxies) { @@ -220,7 +227,12 @@ Zotero.Proxies = new function() { } /** - * Returns a page's proxied url from the proper url + * Returns a page's proxied URL from the proper URL + * @param {String} url + * @param {Boolean} onlyReturnIfProxied Controls behavior if the given URL is not proxied. If + * it is false or unspecified, unproxied URLs are returned verbatim. If it is true, the + * function will return "false" if the given URL is unproxied. + * @type String */ this.properToProxy = function(url, onlyReturnIfProxied) { var uri = ioService.newURI(url, null, null); @@ -234,9 +246,10 @@ Zotero.Proxies = new function() { } /** - * A class to handle individual proxy servers - * + * Creates a Zotero.Proxy object from a DB row + * * @constructor + * @class Represents an individual proxy server */ Zotero.Proxy = function(row) { if(row) { @@ -247,21 +260,32 @@ Zotero.Proxy = function(row) { } } +/** + * Regexps to match the URL contents corresponding to proxy scheme parameters + * @const + */ const Zotero_Proxy_schemeParameters = { "%p":"(.*?)", // path "%d":"(.*?)", // directory "%f":"(.*?)", // filename "%a":"(.*?)" // filename }; + +/** + * Regexps to match proxy scheme parameters in the proxy scheme URL + * @const + */ const Zotero_Proxy_schemeParameterRegexps = { "%p":/([^%])%p/, "%d":/([^%])%d/, "%f":/([^%])%f/, "%h":/([^%])%h/, "%a":/([^%])%a/ -} +}; + /** - * Compiles the regular expression against which we match URLs for this proxy + * Compiles the regular expression against which we match URLs to determine if this proxy is in use + * and saves it in this.regexp */ Zotero.Proxy.prototype.compileRegexp = function() { const metaRe = /[-[\]{}()*+?.\\^$|,#\s]/g; @@ -304,6 +328,9 @@ Zotero.Proxy.prototype.compileRegexp = function() { /** * Ensures that the proxy scheme and host settings are valid for this proxy type + * + * @returns {String|Boolean} An error type if a validation error occurred, or "false" if there was + * no error. */ Zotero.Proxy.prototype.validate = function() { if(this.scheme.length < 8 || (this.scheme.substr(0, 7) != "http://" && this.scheme.substr(0, 8) != "https://")) { @@ -399,6 +426,7 @@ Zotero.Proxy.prototype.erase = function() { * Converts a proxied URL to an unproxied URL using this proxy * * @param m {Array} The match from running this proxy's regexp against a URL spec + * @type String */ Zotero.Proxy.prototype.toProper = function(m) { if(this.multiHost) { @@ -423,6 +451,7 @@ Zotero.Proxy.prototype.toProper = function(m) { * Converts an unproxied URL to a proxied URL using this proxy * * @param {nsIURI} uri The nsIURI corresponding to the unproxied URL + * @type String */ Zotero.Proxy.prototype.toProxy = function(uri) { proxyURL = this.scheme; @@ -448,6 +477,7 @@ Zotero.Proxy.prototype.toProxy = function(uri) { /** * Loads a proxy object from a DB row + * @private */ Zotero.Proxy.prototype._loadFromRow = function(row) { this.proxyID = row.proxyID; @@ -458,10 +488,16 @@ Zotero.Proxy.prototype._loadFromRow = function(row) { this.compileRegexp(); } +/** + * Detectors for various proxy systems + * @namespace + */ Zotero.Proxies.Detectors = new Object(); /** * Detector for OCLC EZProxy + * @param {nsIChannel} channel + * @type Boolean|Zotero.Proxy */ Zotero.Proxies.Detectors.EZProxy = function(channel) { const ezProxyRe = /\?(?:.+&)?(url|qurl)=([^&]+)/i; @@ -556,7 +592,8 @@ Zotero.Proxies.Detectors.EZProxy.obs = Components.classes["@mozilla.org/observer .getService(Components.interfaces.nsIObserverService); /** - * Do-nothing stream listener + * @class Do-nothing stream listener + * @private */ Zotero.Proxies.Detectors.EZProxy.DummyStreamListener = function() {} Zotero.Proxies.Detectors.EZProxy.DummyStreamListener.prototype.onDataAvailable = function(request, @@ -565,7 +602,8 @@ Zotero.Proxies.Detectors.EZProxy.DummyStreamListener.prototype.onStartRequest = Zotero.Proxies.Detectors.EZProxy.DummyStreamListener.prototype.onStopRequest = function(request, context, status) {} /** - * Observer to clear cookies on an HTTP request, then remove itself + * @class Observer to clear cookies on an HTTP request, then remove itself + * @private */ Zotero.Proxies.Detectors.EZProxy.Observer = function(newChannel) { this.channel = newChannel; @@ -584,6 +622,8 @@ Zotero.Proxies.Detectors.EZProxy.Observer.prototype.QueryInterface = function(aI /** * Detector for Juniper Networks WebVPN + * @param {nsIChannel} channel + * @type Boolean|Zotero.Proxy */ Zotero.Proxies.Detectors.Juniper = function(channel) { const juniperRe = /^(https?:\/\/[^\/:]+(?:\:[0-9]+)?)\/(.*),DanaInfo=([^+,]*)([^+]*)(?:\+(.*))?$/; diff --git a/chrome/locale/en-US/zotero/zotero.dtd b/chrome/locale/en-US/zotero/zotero.dtd index 0fe423dc1d..c5cd815b04 100644 --- a/chrome/locale/en-US/zotero/zotero.dtd +++ b/chrome/locale/en-US/zotero/zotero.dtd @@ -154,4 +154,10 @@ - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index 79353ebe0e..054d15954c 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -505,6 +505,7 @@ proxies.error.scheme.noHTTP = Valid proxy schemes must start with "http://" or proxies.error.host.invalid = You must enter a full hostname for the site served by this proxy (e.g., jstor.org). proxies.error.scheme.noHost = A multi-site proxy scheme must contain the host variable (%h). proxies.error.scheme.noPath = A valid proxy scheme must contain either the path variable (%p) or the directory and filename variables (%d and %f). -proxies.recognized = Proxy Recognized -proxies.recognized.message = Would you like Zotero to store information about this proxy server to enable saving of references accessed through it?\n\nWARNING: Only click "OK" below if you have accessed this site through your library or another institution you trust. -proxies.recognized.disable = Disable automatic recognition of proxy systems \ No newline at end of file +proxies.recognized.message = Adding this proxy will allow Zotero to recognize items from its pages and will automatically redirect future requests to %1$S through %2$S. +proxies.recognized.add = Add Proxy +proxies.enableTransparentWarning.title = Warning +proxies.enableTransparentWarning.description = Please ensure that the proxies listed below belong to a library, school, or other institution with which you are affiliated. A malicious proxy could pose a security risk when transparent redirection is enabled. \ No newline at end of file diff --git a/chrome/skin/default/zotero/zotero.css b/chrome/skin/default/zotero/zotero.css index d253792792..49222acf81 100644 --- a/chrome/skin/default/zotero/zotero.css +++ b/chrome/skin/default/zotero/zotero.css @@ -205,4 +205,10 @@ zoteromergepane { .zotero-scrape-popup-collection { list-style-image: url('chrome://zotero/skin/treesource-collection.png'); +} + +.zotero-warning { + font-weight: bold; + font-size: 1.25em; + margin-bottom: 1em; } \ No newline at end of file diff --git a/defaults/preferences/zotero.js b/defaults/preferences/zotero.js index e1669216cd..6d16414090 100644 --- a/defaults/preferences/zotero.js +++ b/defaults/preferences/zotero.js @@ -89,4 +89,4 @@ pref("extensions.zotero.sync.server.compressData", true); // Proxy pref("extensions.zotero.proxies.autoRecognize", true); -pref("extensions.zotero.proxies.transparent", false); \ No newline at end of file +pref("extensions.zotero.proxies.transparent", true); \ No newline at end of file