Skip to content

Commit 61a7738

Browse files
committed
Fixes password for range request loading
1 parent 220c827 commit 61a7738

File tree

6 files changed

+73
-29
lines changed

6 files changed

+73
-29
lines changed

src/api.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
/* globals CanvasGraphics, combineUrl, createScratchCanvas, error, ErrorFont,
1818
Font, FontLoader, globalScope, info, isArrayBuffer, loadJpegStream,
1919
MessageHandler, PDFJS, PDFObjects, Promise, StatTimer, warn,
20-
WorkerMessageHandler */
20+
WorkerMessageHandler, PasswordResponses */
2121

2222
'use strict';
2323

@@ -39,9 +39,16 @@
3939
* to manually serve range requests for data in the PDF. See viewer.js for
4040
* an example of pdfDataRangeTransport's interface.
4141
*
42+
* @param {function} passwordCallback is optional. It is used to request a
43+
* password if wrong or no password was provided. The callback receives two
44+
* parameters: function that needs to be called with new password and reason
45+
* (see {PasswordResponses}).
46+
*
4247
* @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
4348
*/
44-
PDFJS.getDocument = function getDocument(source, pdfDataRangeTransport) {
49+
PDFJS.getDocument = function getDocument(source,
50+
pdfDataRangeTransport,
51+
passwordCallback) {
4552
var workerInitializedPromise, workerReadyPromise, transport;
4653

4754
if (typeof source === 'string') {
@@ -71,6 +78,7 @@ PDFJS.getDocument = function getDocument(source, pdfDataRangeTransport) {
7178
transport = new WorkerTransport(workerInitializedPromise,
7279
workerReadyPromise, pdfDataRangeTransport);
7380
workerInitializedPromise.then(function transportInitialized() {
81+
transport.passwordCallback = passwordCallback;
7482
transport.fetchDocument(params);
7583
});
7684
return workerReadyPromise;
@@ -482,6 +490,8 @@ var WorkerTransport = (function WorkerTransportClosure() {
482490
this.pagePromises = [];
483491
this.embeddedFontsUsed = false;
484492

493+
this.passwordCallback = null;
494+
485495
// If worker support isn't disabled explicit and the browser has worker
486496
// support, create a new web worker and test if it/the browser fullfills
487497
// all requirements to run parts of pdf.js in a web worker.
@@ -559,6 +569,10 @@ var WorkerTransport = (function WorkerTransportClosure() {
559569
function WorkerTransport_setupMessageHandler(messageHandler) {
560570
this.messageHandler = messageHandler;
561571

572+
function updatePassword(password) {
573+
messageHandler.send('UpdatePassword', password);
574+
}
575+
562576
var pdfDataRangeTransport = this.pdfDataRangeTransport;
563577
if (pdfDataRangeTransport) {
564578
pdfDataRangeTransport.addRangeListener(function(begin, chunk) {
@@ -588,10 +602,18 @@ var WorkerTransport = (function WorkerTransportClosure() {
588602
}, this);
589603

590604
messageHandler.on('NeedPassword', function transportPassword(data) {
605+
if (this.passwordCallback) {
606+
return this.passwordCallback(updatePassword,
607+
PasswordResponses.NEED_PASSWORD);
608+
}
591609
this.workerReadyPromise.reject(data.exception.message, data.exception);
592610
}, this);
593611

594612
messageHandler.on('IncorrectPassword', function transportBadPass(data) {
613+
if (this.passwordCallback) {
614+
return this.passwordCallback(updatePassword,
615+
PasswordResponses.INCORRECT_PASSWORD);
616+
}
595617
this.workerReadyPromise.reject(data.exception.message, data.exception);
596618
}, this);
597619

src/crypto.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717
/* globals bytesToString, DecryptStream, error, isInt, isName, Name,
18-
PasswordException, stringToBytes */
18+
PasswordException, PasswordResponses, stringToBytes */
1919

2020
'use strict';
2121

@@ -575,7 +575,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
575575
ownerPassword, userPassword, flags,
576576
revision, keyLength, encryptMetadata);
577577
if (!encryptionKey && !password) {
578-
throw new PasswordException('No password given', 'needpassword');
578+
throw new PasswordException('No password given',
579+
PasswordResponses.NEED_PASSWORD);
579580
} else if (!encryptionKey && password) {
580581
// Attempting use the password as an owner password
581582
var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword,
@@ -586,7 +587,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
586587
}
587588

588589
if (!encryptionKey)
589-
throw new PasswordException('Incorrect Password', 'incorrectpassword');
590+
throw new PasswordException('Incorrect Password',
591+
PasswordResponses.INCORRECT_PASSWORD);
590592

591593
this.encryptionKey = encryptionKey;
592594

src/pdf_manager.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ var BasePdfManager = (function BasePdfManagerClosure() {
5656

5757
requestLoadedStream: function BasePdfManager_requestLoadedStream() {
5858
return new NotImplementedException();
59+
},
60+
61+
updatePassword: function BasePdfManager_updatePassword(password) {
62+
this.pdfModel.xref.password = this.password = password;
63+
if (this.passwordChangedPromise) {
64+
this.passwordChangedPromise.resolve();
65+
}
5966
}
6067
};
6168

src/util.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ function shadow(obj, prop, value) {
139139
return value;
140140
}
141141

142+
var PasswordResponses = PDFJS.PasswordResponses = {
143+
NEED_PASSWORD: 1,
144+
INCORRECT_PASSWORD: 2
145+
};
146+
142147
var PasswordException = (function PasswordExceptionClosure() {
143148
function PasswordException(msg, code) {
144149
this.name = 'PasswordException';

src/worker.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
MissingPDFException, PasswordException, PDFDocument, PDFJS, Promise,
1919
Stream, UnknownErrorException, warn, NetworkManager, LocalPdfManager,
2020
NetworkPdfManager, XRefParseException, NotImplementedException,
21-
isInt */
21+
isInt, PasswordResponses */
2222

2323
'use strict';
2424

@@ -267,11 +267,11 @@ var WorkerMessageHandler = {
267267

268268
var onFailure = function(e) {
269269
if (e instanceof PasswordException) {
270-
if (e.code === 'needpassword') {
270+
if (e.code === PasswordResponses.NEED_PASSWORD) {
271271
handler.send('NeedPassword', {
272272
exception: e
273273
});
274-
} else if (e.code === 'incorrectpassword') {
274+
} else if (e.code === PasswordResponses.INCORRECT_PASSWORD) {
275275
handler.send('IncorrectPassword', {
276276
exception: e
277277
});
@@ -291,10 +291,17 @@ var WorkerMessageHandler = {
291291
}
292292
};
293293

294-
getPdfManager(data).then(function() {
295-
loadDocument(false).then(onSuccess, function(ex) {
294+
getPdfManager(data).then(function pdfManagerReady() {
295+
loadDocument(false).then(onSuccess, function loadFailure(ex) {
296296
// Try again with recoveryMode == true
297297
if (!(ex instanceof XRefParseException)) {
298+
if (ex instanceof PasswordException) {
299+
// after password exception prepare to receive a new password
300+
// to repeat loading
301+
pdfManager.passwordChangedPromise = new Promise();
302+
pdfManager.passwordChangedPromise.then(pdfManagerReady);
303+
}
304+
298305
onFailure(ex);
299306
return;
300307
}
@@ -349,6 +356,10 @@ var WorkerMessageHandler = {
349356
});
350357
});
351358

359+
handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
360+
pdfManager.updatePassword(data);
361+
});
362+
352363
handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
353364
pdfManager.getPage(data.pageIndex).then(function(page) {
354365
pdfManager.ensure(page, 'getAnnotationsData', []).then(

web/viewer.js

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,30 +1048,27 @@ var PDFView = {
10481048
this.pdfDocument = null;
10491049
var self = this;
10501050
self.loading = true;
1051-
PDFJS.getDocument(parameters, pdfDataRangeTransport).then(
1051+
var passwordNeeded = function passwordNeeded(updatePassword, reason) {
1052+
var promptString = mozL10n.get('request_password', null,
1053+
'PDF is protected by a password:');
1054+
1055+
if (reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) {
1056+
promptString += '\n' + mozL10n.get('invalid_password', null,
1057+
'Invalid Password.');
1058+
}
1059+
1060+
password = prompt(promptString);
1061+
if (password && password.length > 0) {
1062+
return updatePassword(password);
1063+
}
1064+
};
1065+
1066+
PDFJS.getDocument(parameters, pdfDataRangeTransport, passwordNeeded).then(
10521067
function getDocumentCallback(pdfDocument) {
10531068
self.load(pdfDocument, scale);
10541069
self.loading = false;
10551070
},
10561071
function getDocumentError(message, exception) {
1057-
if (exception && exception.name === 'PasswordException') {
1058-
if (exception.code === 'needpassword' ||
1059-
exception.code === 'incorrectpassword') {
1060-
var promptString = mozL10n.get('request_password', null,
1061-
'PDF is protected by a password:');
1062-
1063-
if (exception.code === 'incorrectpassword') {
1064-
promptString += '\n' + mozL10n.get('invalid_password', null,
1065-
'Invalid Password.');
1066-
}
1067-
1068-
password = prompt(promptString);
1069-
if (password && password.length > 0) {
1070-
return PDFView.open(url, scale, password);
1071-
}
1072-
}
1073-
}
1074-
10751072
var loadingErrorMessage = mozL10n.get('loading_error', null,
10761073
'An error occurred while loading the PDF.');
10771074

0 commit comments

Comments
 (0)