Browse Source

Fixes password for range request loading

Yury Delendik 12 years ago
parent
commit
61a7738a5d
  1. 26
      src/api.js
  2. 8
      src/crypto.js
  3. 7
      src/pdf_manager.js
  4. 5
      src/util.js
  5. 21
      src/worker.js
  6. 23
      web/viewer.js

26
src/api.js

@ -17,7 +17,7 @@
/* globals CanvasGraphics, combineUrl, createScratchCanvas, error, ErrorFont, /* globals CanvasGraphics, combineUrl, createScratchCanvas, error, ErrorFont,
Font, FontLoader, globalScope, info, isArrayBuffer, loadJpegStream, Font, FontLoader, globalScope, info, isArrayBuffer, loadJpegStream,
MessageHandler, PDFJS, PDFObjects, Promise, StatTimer, warn, MessageHandler, PDFJS, PDFObjects, Promise, StatTimer, warn,
WorkerMessageHandler */ WorkerMessageHandler, PasswordResponses */
'use strict'; 'use strict';
@ -39,9 +39,16 @@
* to manually serve range requests for data in the PDF. See viewer.js for * to manually serve range requests for data in the PDF. See viewer.js for
* an example of pdfDataRangeTransport's interface. * 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. * @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; var workerInitializedPromise, workerReadyPromise, transport;
if (typeof source === 'string') { if (typeof source === 'string') {
@ -71,6 +78,7 @@ PDFJS.getDocument = function getDocument(source, pdfDataRangeTransport) {
transport = new WorkerTransport(workerInitializedPromise, transport = new WorkerTransport(workerInitializedPromise,
workerReadyPromise, pdfDataRangeTransport); workerReadyPromise, pdfDataRangeTransport);
workerInitializedPromise.then(function transportInitialized() { workerInitializedPromise.then(function transportInitialized() {
transport.passwordCallback = passwordCallback;
transport.fetchDocument(params); transport.fetchDocument(params);
}); });
return workerReadyPromise; return workerReadyPromise;
@ -482,6 +490,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.pagePromises = []; this.pagePromises = [];
this.embeddedFontsUsed = false; this.embeddedFontsUsed = false;
this.passwordCallback = null;
// If worker support isn't disabled explicit and the browser has worker // 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 // 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. // all requirements to run parts of pdf.js in a web worker.
@ -559,6 +569,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
function WorkerTransport_setupMessageHandler(messageHandler) { function WorkerTransport_setupMessageHandler(messageHandler) {
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
function updatePassword(password) {
messageHandler.send('UpdatePassword', password);
}
var pdfDataRangeTransport = this.pdfDataRangeTransport; var pdfDataRangeTransport = this.pdfDataRangeTransport;
if (pdfDataRangeTransport) { if (pdfDataRangeTransport) {
pdfDataRangeTransport.addRangeListener(function(begin, chunk) { pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
@ -588,10 +602,18 @@ var WorkerTransport = (function WorkerTransportClosure() {
}, this); }, this);
messageHandler.on('NeedPassword', function transportPassword(data) { 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.workerReadyPromise.reject(data.exception.message, data.exception);
}, this); }, this);
messageHandler.on('IncorrectPassword', function transportBadPass(data) { 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.workerReadyPromise.reject(data.exception.message, data.exception);
}, this); }, this);

8
src/crypto.js

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

7
src/pdf_manager.js

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

5
src/util.js

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

21
src/worker.js

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

23
web/viewer.js

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

Loading…
Cancel
Save