Improve error messages on certificate and connection errors
- Show a clearer message on a certificate error that includes the underlying error, which should make debugging much simpler. (No more checking in a browser and hoping it's the same connection.) - Mention proxy server in message on startup proxy-check failure - Include link to connection-error KB page on sync connection failure Closes #1191 Closes #1513
This commit is contained in:
parent
ea8b15a44a
commit
ff8df06c75
7 changed files with 91 additions and 96 deletions
|
@ -319,17 +319,19 @@ Zotero.HTTP = new function() {
|
||||||
}
|
}
|
||||||
Zotero.debug(msg, 1);
|
Zotero.debug(msg, 1);
|
||||||
|
|
||||||
try {
|
if (xmlhttp.status == 0) {
|
||||||
_checkSecurity(xmlhttp, channel);
|
try {
|
||||||
}
|
this.checkSecurity(channel);
|
||||||
catch (e) {
|
}
|
||||||
deferred.reject(e);
|
catch (e) {
|
||||||
return;
|
deferred.reject(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deferred.reject(new Zotero.HTTP.UnexpectedStatusException(xmlhttp, msg));
|
deferred.reject(new Zotero.HTTP.UnexpectedStatusException(xmlhttp, msg));
|
||||||
}
|
}
|
||||||
};
|
}.bind(this);
|
||||||
|
|
||||||
if (options.cookieSandbox) {
|
if (options.cookieSandbox) {
|
||||||
options.cookieSandbox.attachToInterfaceRequestor(xmlhttp);
|
options.cookieSandbox.attachToInterfaceRequestor(xmlhttp);
|
||||||
|
@ -663,9 +665,17 @@ Zotero.HTTP = new function() {
|
||||||
})
|
})
|
||||||
.catch(function (e) {
|
.catch(function (e) {
|
||||||
// Show error icon at startup
|
// Show error icon at startup
|
||||||
if (e instanceof Zotero.HTTP.SecurityException) {
|
if (!e.dialogHeader) {
|
||||||
Zotero.proxyFailure = e;
|
e.dialogHeader = Zotero.getString('networkError.errorViaProxy');
|
||||||
}
|
}
|
||||||
|
e.message += "\n\n" + Zotero.getString('startupError.internetFunctionalityMayNotWork');
|
||||||
|
if (!e.dialogButtonText) {
|
||||||
|
e.dialogButtonText = Zotero.getString('general.moreInformation');
|
||||||
|
e.dialogButtonCallback = () => {
|
||||||
|
Zotero.launchURL('https://www.zotero.org/support/kb/connection_error');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Zotero.proxyFailure = e;
|
||||||
Zotero.logError(e);
|
Zotero.logError(e);
|
||||||
let msg = "Error connecting to proxy -- proxied requests may not work";
|
let msg = "Error connecting to proxy -- proxied requests may not work";
|
||||||
Zotero.logError(msg);
|
Zotero.logError(msg);
|
||||||
|
@ -992,8 +1002,8 @@ Zotero.HTTP = new function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _checkSecurity(xmlhttp, channel) {
|
this.checkSecurity = function (channel) {
|
||||||
if (xmlhttp.status != 0 || !channel) {
|
if (!channel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,37 +1015,27 @@ Zotero.HTTP = new function() {
|
||||||
secInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
secInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||||
if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_INSECURE)
|
if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_INSECURE)
|
||||||
== Ci.nsIWebProgressListener.STATE_IS_INSECURE) {
|
== Ci.nsIWebProgressListener.STATE_IS_INSECURE) {
|
||||||
let url = channel.name;
|
// Show actual error from the networking stack, with the hyperlink around the
|
||||||
let ios = Components.classes["@mozilla.org/network/io-service;1"]
|
// error code removed
|
||||||
.getService(Components.interfaces.nsIIOService);
|
msg = Zotero.Utilities.unescapeHTML(secInfo.errorMessage);
|
||||||
try {
|
|
||||||
var uri = ios.newURI(url, null, null);
|
|
||||||
var host = uri.host;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
Zotero.debug(e);
|
|
||||||
}
|
|
||||||
let kbURL = 'https://www.zotero.org/support/kb/ssl_certificate_error';
|
|
||||||
msg = Zotero.getString(
|
|
||||||
'sync.storage.error.webdav.sslCertificateError',
|
|
||||||
'https://' + host
|
|
||||||
);
|
|
||||||
dialogButtonText = Zotero.getString('general.moreInformation');
|
dialogButtonText = Zotero.getString('general.moreInformation');
|
||||||
dialogButtonCallback = function () {
|
dialogButtonCallback = function () {
|
||||||
let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
Zotero.launchURL('https://www.zotero.org/support/kb/ssl_certificate_error');
|
||||||
.getService(Components.interfaces.nsIWindowMediator);
|
|
||||||
let win = wm.getMostRecentWindow("navigator:browser");
|
|
||||||
win.ZoteroPane.loadURI(kbURL, { metaKey: true, shiftKey: true });
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_BROKEN)
|
else if ((secInfo.securityState & Ci.nsIWebProgressListener.STATE_IS_BROKEN)
|
||||||
== Ci.nsIWebProgressListener.STATE_IS_BROKEN) {
|
== Ci.nsIWebProgressListener.STATE_IS_BROKEN) {
|
||||||
msg = Zotero.getString('sync.error.sslConnectionError');
|
msg = Zotero.getString('networkError.connectionNotSecure')
|
||||||
|
+ Zotero.Utilities.unescapeHTML(secInfo.errorMessage);
|
||||||
}
|
}
|
||||||
if (msg) {
|
if (msg) {
|
||||||
throw new Zotero.HTTP.SecurityException(
|
throw new Zotero.HTTP.SecurityException(
|
||||||
msg,
|
msg,
|
||||||
{
|
{
|
||||||
|
dialogHeader: Zotero.getString(
|
||||||
|
'networkError.connectionNotSecure',
|
||||||
|
Zotero.clientName
|
||||||
|
),
|
||||||
dialogButtonText,
|
dialogButtonText,
|
||||||
dialogButtonCallback
|
dialogButtonCallback
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,17 @@ Zotero.Sync.Storage.Mode.ZFS.prototype = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for SSL certificate error
|
||||||
|
if (status == 0) {
|
||||||
|
try {
|
||||||
|
Zotero.HTTP.checkSecurity(req);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
deferred.reject(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If S3 connection is interrupted, delay and retry, or bail if too many
|
// If S3 connection is interrupted, delay and retry, or bail if too many
|
||||||
// consecutive failures
|
// consecutive failures
|
||||||
if (status == 0 || status == 500 || status == 503) {
|
if (status == 0 || status == 500 || status == 503) {
|
||||||
|
|
|
@ -788,12 +788,9 @@ Zotero.Sync.APIClient.prototype = {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check connection for certificate errors, interruptions, and empty responses and
|
* Check connection for interruptions and empty responses and throw an appropriate error
|
||||||
* throw an appropriate error
|
|
||||||
*/
|
*/
|
||||||
_checkConnection: function (xmlhttp, channel) {
|
_checkConnection: function (xmlhttp, channel) {
|
||||||
const Ci = Components.interfaces;
|
|
||||||
|
|
||||||
if (!xmlhttp.responseText && (xmlhttp.status == 0 || xmlhttp.status == 200)) {
|
if (!xmlhttp.responseText && (xmlhttp.status == 0 || xmlhttp.status == 200)) {
|
||||||
let msg = null;
|
let msg = null;
|
||||||
let dialogButtonText = null;
|
let dialogButtonText = null;
|
||||||
|
@ -801,8 +798,11 @@ Zotero.Sync.APIClient.prototype = {
|
||||||
|
|
||||||
if (xmlhttp.status === 0) {
|
if (xmlhttp.status === 0) {
|
||||||
msg = Zotero.getString('sync.error.checkConnection');
|
msg = Zotero.getString('sync.error.checkConnection');
|
||||||
|
dialogButtonText = Zotero.getString('general.moreInformation');
|
||||||
|
let url = 'https://www.zotero.org/support/kb/connection_error';
|
||||||
|
dialogButtonCallback = () => Zotero.launchURL(url);
|
||||||
}
|
}
|
||||||
if (!msg) {
|
else if (!msg) {
|
||||||
msg = Zotero.getString('sync.error.emptyResponseServer')
|
msg = Zotero.getString('sync.error.emptyResponseServer')
|
||||||
+ Zotero.getString('general.tryAgainLater');
|
+ Zotero.getString('general.tryAgainLater');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1404,26 +1404,31 @@ Zotero.Sync.Runner_Module = function (options = {}) {
|
||||||
}
|
}
|
||||||
label.setAttribute('value', libraryName);
|
label.setAttribute('value', libraryName);
|
||||||
}
|
}
|
||||||
var content = doc.createElement('hbox');
|
var content = doc.createElement('vbox');
|
||||||
var buttons = doc.createElement('hbox');
|
var buttons = doc.createElement('hbox');
|
||||||
buttons.pack = 'end';
|
buttons.pack = 'end';
|
||||||
box.appendChild(label);
|
box.appendChild(label);
|
||||||
box.appendChild(content);
|
box.appendChild(content);
|
||||||
box.appendChild(buttons);
|
box.appendChild(buttons);
|
||||||
|
|
||||||
|
if (e.dialogHeader) {
|
||||||
|
let header = doc.createElement('description');
|
||||||
|
header.className = 'error-header';
|
||||||
|
header.textContent = e.dialogHeader;
|
||||||
|
content.appendChild(header);
|
||||||
|
}
|
||||||
|
|
||||||
// Show our own error mesages directly
|
// Show our own error mesages directly
|
||||||
|
var msg;
|
||||||
if (e instanceof Zotero.Error) {
|
if (e instanceof Zotero.Error) {
|
||||||
var msg = e.message;
|
msg = e.message;
|
||||||
}
|
}
|
||||||
// For unexpected ones, just show a generic message
|
// For unexpected ones, just show a generic message
|
||||||
|
else if (e instanceof Zotero.HTTP.UnexpectedStatusException && e.xmlhttp.responseText) {
|
||||||
|
msg = Zotero.Utilities.ellipsize(e.xmlhttp.responseText, 1000, true);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
|
msg = e.message;
|
||||||
msg = Zotero.Utilities.ellipsize(e.xmlhttp.responseText, 1000, true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO: Localize
|
|
||||||
var msg = "An error occurred during syncing:\n\n" + e.message;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var desc = doc.createElement('description');
|
var desc = doc.createElement('description');
|
||||||
|
|
|
@ -483,10 +483,7 @@ var ZoteroPane = new function()
|
||||||
|
|
||||||
if (Zotero.proxyFailure) {
|
if (Zotero.proxyFailure) {
|
||||||
try {
|
try {
|
||||||
Zotero.proxyFailure.message += "\n\n"
|
|
||||||
+ Zotero.getString('startupError.internetFunctionalityMayNotWork');
|
|
||||||
Zotero.Sync.Runner.updateIcons(Zotero.proxyFailure);
|
Zotero.Sync.Runner.updateIcons(Zotero.proxyFailure);
|
||||||
Zotero.proxyFailure = null;
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
Zotero.logError(e);
|
Zotero.logError(e);
|
||||||
|
@ -4611,64 +4608,33 @@ var ZoteroPane = new function()
|
||||||
|
|
||||||
this.syncAlert = function (e) {
|
this.syncAlert = function (e) {
|
||||||
e = Zotero.Sync.Runner.parseError(e);
|
e = Zotero.Sync.Runner.parseError(e);
|
||||||
|
var ps = Services.prompt;
|
||||||
|
var buttonText = e.dialogButtonText;
|
||||||
|
var buttonCallback = e.dialogButtonCallback;
|
||||||
|
|
||||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
if (e.errorType == 'warning' || e.errorType == 'error') {
|
||||||
.getService(Components.interfaces.nsIPromptService);
|
let title = Zotero.getString('general.' + e.errorType);
|
||||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK
|
// TODO: Display header in bold
|
||||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
|
let msg = (e.dialogHeader ? e.dialogHeader + '\n\n' : '') + e.message;
|
||||||
|
|
||||||
// Warning
|
|
||||||
if (e.errorType == 'warning') {
|
|
||||||
var title = Zotero.getString('general.warning');
|
|
||||||
|
|
||||||
// If secondary button not specified, just use an alert
|
if (e.errorType == 'warning' || buttonText === null) {
|
||||||
if (e.buttonText) {
|
|
||||||
var buttonText = e.buttonText;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ps.alert(null, title, e.message);
|
ps.alert(null, title, e.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = ps.confirmEx(
|
if (!buttonText) {
|
||||||
null,
|
buttonText = Zotero.getString('errorReport.reportError');
|
||||||
title,
|
buttonCallback = function () {
|
||||||
e.message,
|
|
||||||
buttonFlags,
|
|
||||||
"",
|
|
||||||
buttonText,
|
|
||||||
"", null, {}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (index == 1) {
|
|
||||||
setTimeout(function () { buttonCallback(); }, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Error
|
|
||||||
else if (e.errorType == 'error') {
|
|
||||||
var title = Zotero.getString('general.error');
|
|
||||||
|
|
||||||
// If secondary button is explicitly null, just use an alert
|
|
||||||
if (buttonText === null) {
|
|
||||||
ps.alert(null, title, e.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof buttonText == 'undefined') {
|
|
||||||
var buttonText = Zotero.getString('errorReport.reportError');
|
|
||||||
var buttonCallback = function () {
|
|
||||||
ZoteroPane.reportErrors();
|
ZoteroPane.reportErrors();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
var buttonText = e.buttonText;
|
|
||||||
var buttonCallback = e.buttonCallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
var index = ps.confirmEx(
|
let buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK
|
||||||
|
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
|
||||||
|
let index = ps.confirmEx(
|
||||||
null,
|
null,
|
||||||
title,
|
title,
|
||||||
e.message,
|
msg,
|
||||||
buttonFlags,
|
buttonFlags,
|
||||||
"",
|
"",
|
||||||
buttonText,
|
buttonText,
|
||||||
|
@ -4676,12 +4642,13 @@ var ZoteroPane = new function()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (index == 1) {
|
if (index == 1) {
|
||||||
setTimeout(function () { buttonCallback(); }, 1);
|
setTimeout(buttonCallback, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Upgrade
|
// Upgrade message
|
||||||
else if (e.errorType == 'upgrade') {
|
else if (e.errorType == 'upgrade') {
|
||||||
ps.alert(null, "", e.message);
|
ps.alert(null, "", e.message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,9 @@ general.operationInProgress = A Zotero operation is currently in progress.
|
||||||
general.operationInProgress.waitUntilFinished = Please wait until it has finished.
|
general.operationInProgress.waitUntilFinished = Please wait until it has finished.
|
||||||
general.operationInProgress.waitUntilFinishedAndTryAgain = Please wait until it has finished and try again.
|
general.operationInProgress.waitUntilFinishedAndTryAgain = Please wait until it has finished and try again.
|
||||||
|
|
||||||
|
networkError.connectionNotSecure = %S could not make a secure connection.
|
||||||
|
networkError.errorViaProxy = Error connecting via proxy server
|
||||||
|
|
||||||
about.createdBy = Zotero is a project of the [Roy Rosenzweig Center for History and New Media] and is developed by a [global community].
|
about.createdBy = Zotero is a project of the [Roy Rosenzweig Center for History and New Media] and is developed by a [global community].
|
||||||
about.getInvolved = Want to help? [Get involved] today!
|
about.getInvolved = Want to help? [Get involved] today!
|
||||||
|
|
||||||
|
|
|
@ -645,6 +645,15 @@
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#zotero-sync-error-panel .error-header {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
-moz-user-select: text;
|
||||||
|
user-select: text;
|
||||||
|
cursor: text
|
||||||
|
}
|
||||||
|
|
||||||
.zotero-sync-error-panel-library-name {
|
.zotero-sync-error-panel-library-name {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
Loading…
Reference in a new issue