Support password and add the relevant l10n strings
This commit is contained in:
		
							parent
							
								
									b7ea788b0c
								
							
						
					
					
						commit
						0a30d3961b
					
				| @ -29,3 +29,4 @@ page_of=af {{pageCount}} | |||||||
| no_outline=Ingen dokumentoversigt tilgængelig | no_outline=Ingen dokumentoversigt tilgængelig | ||||||
| open_file.title=Åbn fil | open_file.title=Åbn fil | ||||||
| text_annotation_type=[{{type}} Kommentar] | text_annotation_type=[{{type}} Kommentar] | ||||||
|  | request_password=PDF filen er beskyttet med et kodeord: | ||||||
|  | |||||||
| @ -42,3 +42,4 @@ zoom_in_label=Zoom In | |||||||
| zoom.title=Zoom | zoom.title=Zoom | ||||||
| thumb_page_title=Page {{page}} | thumb_page_title=Page {{page}} | ||||||
| thumb_page_canvas=Thumbnail of Page {{page}} | thumb_page_canvas=Thumbnail of Page {{page}} | ||||||
|  | request_password=PDF is protected by a password: | ||||||
|  | |||||||
							
								
								
									
										63
									
								
								src/api.js
									
									
									
									
									
								
							
							
						
						
									
										63
									
								
								src/api.js
									
									
									
									
									
								
							| @ -7,20 +7,46 @@ | |||||||
|  * is used, which means it must follow the same origin rules that any XHR does |  * is used, which means it must follow the same origin rules that any XHR does | ||||||
|  * e.g. No cross domain requests without CORS. |  * e.g. No cross domain requests without CORS. | ||||||
|  * |  * | ||||||
|  * @param {string|TypedAray} source Either a url to a PDF is located or a |  * @param {string|TypedAray|object} source Can be an url to where a PDF is | ||||||
|  * typed array (Uint8Array) already populated with data. |  * located, a typed array (Uint8Array) already populated with data or | ||||||
|  * @param {Object} headers An object containing the http headers like this: |  * and parameter object with the following possible fields: | ||||||
|  * { Authorization: "BASIC XXX" }. |  *  - url   - The URL of the PDF. | ||||||
|  |  *  - data  - A typed array with PDF data. | ||||||
|  |  *  - httpHeaders - Basic authentication headers. | ||||||
|  |  *  - password - For decrypting password-protected PDFs. | ||||||
|  |  * | ||||||
|  * @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, headers) { | PDFJS.getDocument = function getDocument(source) { | ||||||
|  |   var url, data, headers, password, parameters = {}; | ||||||
|  |   if (typeof source === 'string') { | ||||||
|  |     url = params; | ||||||
|  |   } else if (isArrayBuffer(source)) { | ||||||
|  |     data = source; | ||||||
|  |   } else if (typeof source === 'object') { | ||||||
|  |     url = source.url; | ||||||
|  |     data = source.data; | ||||||
|  |     headers = source.httpHeaders; | ||||||
|  |     password = source.password; | ||||||
|  |     parameters.password = password || null; | ||||||
|  | 
 | ||||||
|  |     if (!url && !data) | ||||||
|  |       error('Invalid parameter array, need either .data or .url'); | ||||||
|  |   } else { | ||||||
|  |     error('Invalid parameter in getDocument, need either Uint8Array, ' + | ||||||
|  |           'string or a parameter object'); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   var promise = new PDFJS.Promise(); |   var promise = new PDFJS.Promise(); | ||||||
|   var transport = new WorkerTransport(promise); |   var transport = new WorkerTransport(promise); | ||||||
|   if (typeof source === 'string') { |   if (data) { | ||||||
|  |     // assuming the data is array, instantiating directly from it
 | ||||||
|  |     transport.sendData(data, parameters); | ||||||
|  |   } else if (url) { | ||||||
|     // fetch url
 |     // fetch url
 | ||||||
|     PDFJS.getPdf( |     PDFJS.getPdf( | ||||||
|       { |       { | ||||||
|         url: source, |         url: url, | ||||||
|         progress: function getPDFProgress(evt) { |         progress: function getPDFProgress(evt) { | ||||||
|           if (evt.lengthComputable) |           if (evt.lengthComputable) | ||||||
|             promise.progress({ |             promise.progress({ | ||||||
| @ -35,12 +61,10 @@ PDFJS.getDocument = function getDocument(source, headers) { | |||||||
|         headers: headers |         headers: headers | ||||||
|       }, |       }, | ||||||
|       function getPDFLoad(data) { |       function getPDFLoad(data) { | ||||||
|         transport.sendData(data); |         transport.sendData(data, parameters); | ||||||
|       }); |       }); | ||||||
|   } else { |  | ||||||
|     // assuming the source is array, instantiating directly from it
 |  | ||||||
|     transport.sendData(source); |  | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   return promise; |   return promise; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -122,6 +146,11 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() { | |||||||
|       }); |       }); | ||||||
|       return promise; |       return promise; | ||||||
|     }, |     }, | ||||||
|  |     isEncrypted: function PDFDocumentProxy_isEncrypted() { | ||||||
|  |       var promise = new PDFJS.Promise(); | ||||||
|  |       promise.resolve(this.pdfInfo.encrypted); | ||||||
|  |       return promise; | ||||||
|  |     }, | ||||||
|     destroy: function PDFDocumentProxy_destroy() { |     destroy: function PDFDocumentProxy_destroy() { | ||||||
|       this.transport.destroy(); |       this.transport.destroy(); | ||||||
|     } |     } | ||||||
| @ -467,6 +496,14 @@ var WorkerTransport = (function WorkerTransportClosure() { | |||||||
|         this.workerReadyPromise.resolve(pdfDocument); |         this.workerReadyPromise.resolve(pdfDocument); | ||||||
|       }, this); |       }, this); | ||||||
| 
 | 
 | ||||||
|  |       messageHandler.on('NeedPassword', function transportPassword(data) { | ||||||
|  |         this.workerReadyPromise.reject(data.exception.message, data.exception); | ||||||
|  |       }, this); | ||||||
|  | 
 | ||||||
|  |       messageHandler.on('IncorrectPassword', function transportBadPass(data) { | ||||||
|  |         this.workerReadyPromise.reject(data.exception.message, data.exception); | ||||||
|  |       }, this); | ||||||
|  | 
 | ||||||
|       messageHandler.on('GetPage', function transportPage(data) { |       messageHandler.on('GetPage', function transportPage(data) { | ||||||
|         var pageInfo = data.pageInfo; |         var pageInfo = data.pageInfo; | ||||||
|         var page = new PDFPageProxy(pageInfo, this); |         var page = new PDFPageProxy(pageInfo, this); | ||||||
| @ -569,8 +606,8 @@ var WorkerTransport = (function WorkerTransportClosure() { | |||||||
|       }); |       }); | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     sendData: function WorkerTransport_sendData(data) { |     sendData: function WorkerTransport_sendData(data, params) { | ||||||
|       this.messageHandler.send('GetDocRequest', data); |       this.messageHandler.send('GetDocRequest', {data: data, params: params}); | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     getPage: function WorkerTransport_getPage(pageNumber, promise) { |     getPage: function WorkerTransport_getPage(pageNumber, promise) { | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								src/core.js
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/core.js
									
									
									
									
									
								
							| @ -320,19 +320,19 @@ var Page = (function PageClosure() { | |||||||
|  * `PDFDocument` objects on the main thread created. |  * `PDFDocument` objects on the main thread created. | ||||||
|  */ |  */ | ||||||
| var PDFDocument = (function PDFDocumentClosure() { | var PDFDocument = (function PDFDocumentClosure() { | ||||||
|   function PDFDocument(arg, callback) { |   function PDFDocument(arg, password) { | ||||||
|     if (isStream(arg)) |     if (isStream(arg)) | ||||||
|       init.call(this, arg); |       init.call(this, arg, password); | ||||||
|     else if (isArrayBuffer(arg)) |     else if (isArrayBuffer(arg)) | ||||||
|       init.call(this, new Stream(arg)); |       init.call(this, new Stream(arg), password); | ||||||
|     else |     else | ||||||
|       error('PDFDocument: Unknown argument type'); |       error('PDFDocument: Unknown argument type'); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function init(stream) { |   function init(stream, password) { | ||||||
|     assertWellFormed(stream.length > 0, 'stream must have data'); |     assertWellFormed(stream.length > 0, 'stream must have data'); | ||||||
|     this.stream = stream; |     this.stream = stream; | ||||||
|     this.setup(); |     this.setup(password); | ||||||
|     this.acroForm = this.catalog.catDict.get('AcroForm'); |     this.acroForm = this.catalog.catDict.get('AcroForm'); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -423,11 +423,12 @@ var PDFDocument = (function PDFDocumentClosure() { | |||||||
|       } |       } | ||||||
|       // May not be a PDF file, continue anyway.
 |       // May not be a PDF file, continue anyway.
 | ||||||
|     }, |     }, | ||||||
|     setup: function PDFDocument_setup(ownerPassword, userPassword) { |     setup: function PDFDocument_setup(password) { | ||||||
|       this.checkHeader(); |       this.checkHeader(); | ||||||
|       var xref = new XRef(this.stream, |       var xref = new XRef(this.stream, | ||||||
|                           this.startXRef, |                           this.startXRef, | ||||||
|                           this.mainXRefEntriesOffset); |                           this.mainXRefEntriesOffset, | ||||||
|  |                           password); | ||||||
|       this.xref = xref; |       this.xref = xref; | ||||||
|       this.catalog = new Catalog(xref); |       this.catalog = new Catalog(xref); | ||||||
|     }, |     }, | ||||||
|  | |||||||
| @ -556,7 +556,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { | |||||||
|     var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, |     var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, | ||||||
|                                        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'); | ||||||
|  |     } 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, | ||||||
|                                                revision, keyLength); |                                                revision, keyLength); | ||||||
| @ -566,7 +568,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!encryptionKey) |     if (!encryptionKey) | ||||||
|       error('incorrect password or encryption data'); |       throw new PasswordException('Incorrect Password', 'incorrectpassword'); | ||||||
| 
 | 
 | ||||||
|     this.encryptionKey = encryptionKey; |     this.encryptionKey = encryptionKey; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -298,7 +298,7 @@ var Catalog = (function CatalogClosure() { | |||||||
| })(); | })(); | ||||||
| 
 | 
 | ||||||
| var XRef = (function XRefClosure() { | var XRef = (function XRefClosure() { | ||||||
|   function XRef(stream, startXRef, mainXRefEntriesOffset) { |   function XRef(stream, startXRef, mainXRefEntriesOffset, password) { | ||||||
|     this.stream = stream; |     this.stream = stream; | ||||||
|     this.entries = []; |     this.entries = []; | ||||||
|     this.xrefstms = {}; |     this.xrefstms = {}; | ||||||
| @ -311,8 +311,7 @@ var XRef = (function XRefClosure() { | |||||||
|     var encrypt = trailerDict.get('Encrypt'); |     var encrypt = trailerDict.get('Encrypt'); | ||||||
|     if (encrypt) { |     if (encrypt) { | ||||||
|       var fileId = trailerDict.get('ID'); |       var fileId = trailerDict.get('ID'); | ||||||
|       this.encrypt = new CipherTransformFactory(encrypt, |       this.encrypt = new CipherTransformFactory(encrypt, fileId[0], password); | ||||||
|                                                 fileId[0] /*, password */); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // get the root dictionary (catalog) object
 |     // get the root dictionary (catalog) object
 | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								src/util.js
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/util.js
									
									
									
									
									
								
							| @ -58,6 +58,14 @@ function shadow(obj, prop, value) { | |||||||
|   return value; |   return value; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function PasswordException(msg, code) { | ||||||
|  |   this.name = 'PasswordException'; | ||||||
|  |   this.message = msg; | ||||||
|  |   this.code = code; | ||||||
|  | } | ||||||
|  | PasswordException.prototype = new Error(); | ||||||
|  | PasswordException.constructor = PasswordException; | ||||||
|  | 
 | ||||||
| function bytesToString(bytes) { | function bytesToString(bytes) { | ||||||
|   var str = ''; |   var str = ''; | ||||||
|   var length = bytes.length; |   var length = bytes.length; | ||||||
| @ -456,7 +464,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() { | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       this.isResolved = true; |       this.isResolved = true; | ||||||
|       this.data = data || null; |       this.data = (typeof data !== 'undefined') ? data : null; | ||||||
|       var callbacks = this.callbacks; |       var callbacks = this.callbacks; | ||||||
| 
 | 
 | ||||||
|       for (var i = 0, ii = callbacks.length; i < ii; i++) { |       for (var i = 0, ii = callbacks.length; i < ii; i++) { | ||||||
| @ -471,7 +479,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() { | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|     reject: function Promise_reject(reason) { |     reject: function Promise_reject(reason, exception) { | ||||||
|       if (this.isRejected) { |       if (this.isRejected) { | ||||||
|         error('A Promise can be rejected only once ' + this.name); |         error('A Promise can be rejected only once ' + this.name); | ||||||
|       } |       } | ||||||
| @ -484,7 +492,7 @@ var Promise = PDFJS.Promise = (function PromiseClosure() { | |||||||
|       var errbacks = this.errbacks; |       var errbacks = this.errbacks; | ||||||
| 
 | 
 | ||||||
|       for (var i = 0, ii = errbacks.length; i < ii; i++) { |       for (var i = 0, ii = errbacks.length; i < ii; i++) { | ||||||
|         errbacks[i].call(null, reason); |         errbacks[i].call(null, reason, exception); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -88,14 +88,35 @@ var WorkerMessageHandler = { | |||||||
|     handler.on('GetDocRequest', function wphSetupDoc(data) { |     handler.on('GetDocRequest', function wphSetupDoc(data) { | ||||||
|       // Create only the model of the PDFDoc, which is enough for
 |       // Create only the model of the PDFDoc, which is enough for
 | ||||||
|       // processing the content of the pdf.
 |       // processing the content of the pdf.
 | ||||||
|       pdfModel = new PDFDocument(new Stream(data)); |       var pdfData = data.data; | ||||||
|  |       var pdfPassword = data.params.password; | ||||||
|  |       try { | ||||||
|  |         pdfModel = new PDFDocument(new Stream(pdfData), pdfPassword); | ||||||
|  |       } catch (e) { | ||||||
|  |         if (e instanceof PasswordException) { | ||||||
|  |           if (e.code === 'needpassword') { | ||||||
|  |             handler.send('NeedPassword', { | ||||||
|  |               exception: e | ||||||
|  |             }); | ||||||
|  |           } else if (e.code === 'incorrectpassword') { | ||||||
|  |             handler.send('IncorrectPassword', { | ||||||
|  |               exception: e | ||||||
|  |             }); | ||||||
|  |           } | ||||||
|  | 
 | ||||||
|  |           return; | ||||||
|  |         } else { | ||||||
|  |           throw e; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|       var doc = { |       var doc = { | ||||||
|         numPages: pdfModel.numPages, |         numPages: pdfModel.numPages, | ||||||
|         fingerprint: pdfModel.getFingerprint(), |         fingerprint: pdfModel.getFingerprint(), | ||||||
|         destinations: pdfModel.catalog.destinations, |         destinations: pdfModel.catalog.destinations, | ||||||
|         outline: pdfModel.catalog.documentOutline, |         outline: pdfModel.catalog.documentOutline, | ||||||
|         info: pdfModel.getDocumentInfo(), |         info: pdfModel.getDocumentInfo(), | ||||||
|         metadata: pdfModel.catalog.metadata |         metadata: pdfModel.catalog.metadata, | ||||||
|  |         encrypted: !!pdfModel.xref.encrypt | ||||||
|       }; |       }; | ||||||
|       handler.send('GetDoc', {pdfInfo: doc}); |       handler.send('GetDoc', {pdfInfo: doc}); | ||||||
|     }); |     }); | ||||||
|  | |||||||
| @ -331,10 +331,15 @@ var PDFView = { | |||||||
|     return currentPageNumber; |     return currentPageNumber; | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
|   open: function pdfViewOpen(url, scale) { |   open: function pdfViewOpen(url, scale, password) { | ||||||
|  |     var parameters = {password: password}; | ||||||
|  |     if (typeof url === 'string') { | ||||||
|       this.url = url; |       this.url = url; | ||||||
| 
 |  | ||||||
|       document.title = decodeURIComponent(getFileName(url)) || url; |       document.title = decodeURIComponent(getFileName(url)) || url; | ||||||
|  |       parameters.url = url; | ||||||
|  |     } else if (isArrayBuffer(url)) { | ||||||
|  |       parameters.data = url; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     if (!PDFView.loadingBar) { |     if (!PDFView.loadingBar) { | ||||||
|       PDFView.loadingBar = new ProgressBar('#loadingBar', {}); |       PDFView.loadingBar = new ProgressBar('#loadingBar', {}); | ||||||
| @ -342,12 +347,23 @@ var PDFView = { | |||||||
| 
 | 
 | ||||||
|     var self = this; |     var self = this; | ||||||
|     self.loading = true; |     self.loading = true; | ||||||
|     PDFJS.getDocument(url).then( |     PDFJS.getDocument(parameters).then( | ||||||
|       function getDocumentCallback(pdfDocument) { |       function getDocumentCallback(pdfDocument) { | ||||||
|         self.load(pdfDocument, scale); |         self.load(pdfDocument, scale); | ||||||
|         self.loading = false; |         self.loading = false; | ||||||
|       }, |       }, | ||||||
|       function getDocumentError(message, exception) { |       function getDocumentError(message, exception) { | ||||||
|  |         if (exception.name === 'PasswordException') { | ||||||
|  |           if (exception.code === 'needpassword') { | ||||||
|  |             var promptString = mozL10n.get('request_password', null, | ||||||
|  |                                       'PDF is protected by a password:'); | ||||||
|  |             password = prompt(promptString); | ||||||
|  |             if (password && password.length > 0) { | ||||||
|  |               return PDFView.open(url, scale, password); | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         var loadingIndicator = document.getElementById('loading'); |         var loadingIndicator = document.getElementById('loading'); | ||||||
|         loadingIndicator.textContent = mozL10n.get('loading_error_indicator', |         loadingIndicator.textContent = mozL10n.get('loading_error_indicator', | ||||||
|           null, 'Error'); |           null, 'Error'); | ||||||
| @ -1530,10 +1546,7 @@ window.addEventListener('change', function webViewerChange(evt) { | |||||||
|     for (var i = 0; i < data.length; i++) |     for (var i = 0; i < data.length; i++) | ||||||
|       uint8Array[i] = data.charCodeAt(i); |       uint8Array[i] = data.charCodeAt(i); | ||||||
| 
 | 
 | ||||||
|     // TODO using blob instead?
 |     PDFView.open(uint8Array, 0); | ||||||
|     PDFJS.getDocument(uint8Array).then(function(pdfDocument) { |  | ||||||
|       PDFView.load(pdfDocument); |  | ||||||
|     }); |  | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   // Read as a binary string since "readAsArrayBuffer" is not yet
 |   // Read as a binary string since "readAsArrayBuffer" is not yet
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user