Merge pull request #3233 from yurydelendik/onpassword

Fixes password for range request loading
This commit is contained in:
Brendan Dahl 2013-05-09 17:28:16 -07:00
commit f07564b07f
6 changed files with 73 additions and 29 deletions

View File

@ -17,7 +17,7 @@
/* globals CanvasGraphics, combineUrl, createScratchCanvas, error, ErrorFont,
Font, FontLoader, globalScope, info, isArrayBuffer, loadJpegStream,
MessageHandler, PDFJS, PDFObjects, Promise, StatTimer, warn,
WorkerMessageHandler */
WorkerMessageHandler, PasswordResponses */
'use strict';
@ -39,9 +39,16 @@
* to manually serve range requests for data in the PDF. See viewer.js for
* an example of pdfDataRangeTransport's interface.
*
* @param {function} passwordCallback is optional. It is used to request a
* password if wrong or no password was provided. The callback receives two
* parameters: function that needs to be called with new password and reason
* (see {PasswordResponses}).
*
* @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
*/
PDFJS.getDocument = function getDocument(source, pdfDataRangeTransport) {
PDFJS.getDocument = function getDocument(source,
pdfDataRangeTransport,
passwordCallback) {
var workerInitializedPromise, workerReadyPromise, transport;
if (typeof source === 'string') {
@ -71,6 +78,7 @@ PDFJS.getDocument = function getDocument(source, pdfDataRangeTransport) {
transport = new WorkerTransport(workerInitializedPromise,
workerReadyPromise, pdfDataRangeTransport);
workerInitializedPromise.then(function transportInitialized() {
transport.passwordCallback = passwordCallback;
transport.fetchDocument(params);
});
return workerReadyPromise;
@ -482,6 +490,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.pagePromises = [];
this.embeddedFontsUsed = false;
this.passwordCallback = null;
// If worker support isn't disabled explicit and the browser has worker
// support, create a new web worker and test if it/the browser fullfills
// all requirements to run parts of pdf.js in a web worker.
@ -559,6 +569,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
function WorkerTransport_setupMessageHandler(messageHandler) {
this.messageHandler = messageHandler;
function updatePassword(password) {
messageHandler.send('UpdatePassword', password);
}
var pdfDataRangeTransport = this.pdfDataRangeTransport;
if (pdfDataRangeTransport) {
pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
@ -588,10 +602,18 @@ var WorkerTransport = (function WorkerTransportClosure() {
}, this);
messageHandler.on('NeedPassword', function transportPassword(data) {
if (this.passwordCallback) {
return this.passwordCallback(updatePassword,
PasswordResponses.NEED_PASSWORD);
}
this.workerReadyPromise.reject(data.exception.message, data.exception);
}, this);
messageHandler.on('IncorrectPassword', function transportBadPass(data) {
if (this.passwordCallback) {
return this.passwordCallback(updatePassword,
PasswordResponses.INCORRECT_PASSWORD);
}
this.workerReadyPromise.reject(data.exception.message, data.exception);
}, this);

View File

@ -15,7 +15,7 @@
* limitations under the License.
*/
/* globals bytesToString, DecryptStream, error, isInt, isName, Name,
PasswordException, stringToBytes */
PasswordException, PasswordResponses, stringToBytes */
'use strict';
@ -575,7 +575,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
ownerPassword, userPassword, flags,
revision, keyLength, encryptMetadata);
if (!encryptionKey && !password) {
throw new PasswordException('No password given', 'needpassword');
throw new PasswordException('No password given',
PasswordResponses.NEED_PASSWORD);
} else if (!encryptionKey && password) {
// Attempting use the password as an owner password
var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
@ -586,7 +587,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
}
if (!encryptionKey)
throw new PasswordException('Incorrect Password', 'incorrectpassword');
throw new PasswordException('Incorrect Password',
PasswordResponses.INCORRECT_PASSWORD);
this.encryptionKey = encryptionKey;

View File

@ -56,6 +56,13 @@ var BasePdfManager = (function BasePdfManagerClosure() {
requestLoadedStream: function BasePdfManager_requestLoadedStream() {
return new NotImplementedException();
},
updatePassword: function BasePdfManager_updatePassword(password) {
this.pdfModel.xref.password = this.password = password;
if (this.passwordChangedPromise) {
this.passwordChangedPromise.resolve();
}
}
};

View File

@ -139,6 +139,11 @@ function shadow(obj, prop, value) {
return value;
}
var PasswordResponses = PDFJS.PasswordResponses = {
NEED_PASSWORD: 1,
INCORRECT_PASSWORD: 2
};
var PasswordException = (function PasswordExceptionClosure() {
function PasswordException(msg, code) {
this.name = 'PasswordException';

View File

@ -18,7 +18,7 @@
MissingPDFException, PasswordException, PDFDocument, PDFJS, Promise,
Stream, UnknownErrorException, warn, NetworkManager, LocalPdfManager,
NetworkPdfManager, XRefParseException, NotImplementedException,
isInt */
isInt, PasswordResponses */
'use strict';
@ -267,11 +267,11 @@ var WorkerMessageHandler = {
var onFailure = function(e) {
if (e instanceof PasswordException) {
if (e.code === 'needpassword') {
if (e.code === PasswordResponses.NEED_PASSWORD) {
handler.send('NeedPassword', {
exception: e
});
} else if (e.code === 'incorrectpassword') {
} else if (e.code === PasswordResponses.INCORRECT_PASSWORD) {
handler.send('IncorrectPassword', {
exception: e
});
@ -291,10 +291,17 @@ var WorkerMessageHandler = {
}
};
getPdfManager(data).then(function() {
loadDocument(false).then(onSuccess, function(ex) {
getPdfManager(data).then(function pdfManagerReady() {
loadDocument(false).then(onSuccess, function loadFailure(ex) {
// Try again with recoveryMode == true
if (!(ex instanceof XRefParseException)) {
if (ex instanceof PasswordException) {
// after password exception prepare to receive a new password
// to repeat loading
pdfManager.passwordChangedPromise = new Promise();
pdfManager.passwordChangedPromise.then(pdfManagerReady);
}
onFailure(ex);
return;
}
@ -349,6 +356,10 @@ var WorkerMessageHandler = {
});
});
handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
pdfManager.updatePassword(data);
});
handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
pdfManager.getPage(data.pageIndex).then(function(page) {
pdfManager.ensure(page, 'getAnnotationsData', []).then(

View File

@ -1048,30 +1048,27 @@ var PDFView = {
this.pdfDocument = null;
var self = this;
self.loading = true;
PDFJS.getDocument(parameters, pdfDataRangeTransport).then(
var passwordNeeded = function passwordNeeded(updatePassword, reason) {
var promptString = mozL10n.get('request_password', null,
'PDF is protected by a password:');
if (reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) {
promptString += '\n' + mozL10n.get('invalid_password', null,
'Invalid Password.');
}
password = prompt(promptString);
if (password && password.length > 0) {
return updatePassword(password);
}
};
PDFJS.getDocument(parameters, pdfDataRangeTransport, passwordNeeded).then(
function getDocumentCallback(pdfDocument) {
self.load(pdfDocument, scale);
self.loading = false;
},
function getDocumentError(message, exception) {
if (exception && exception.name === 'PasswordException') {
if (exception.code === 'needpassword' ||
exception.code === 'incorrectpassword') {
var promptString = mozL10n.get('request_password', null,
'PDF is protected by a password:');
if (exception.code === 'incorrectpassword') {
promptString += '\n' + mozL10n.get('invalid_password', null,
'Invalid Password.');
}
password = prompt(promptString);
if (password && password.length > 0) {
return PDFView.open(url, scale, password);
}
}
}
var loadingErrorMessage = mozL10n.get('loading_error', null,
'An error occurred while loading the PDF.');