@@ -18,6 +18,7 @@ import {
18
18
JpegEmbedder ,
19
19
PageBoundingBox ,
20
20
PageEmbeddingMismatchedContextError ,
21
+ PDFArray ,
21
22
PDFCatalog ,
22
23
PDFContext ,
23
24
PDFDict ,
@@ -66,6 +67,7 @@ import FileEmbedder, { AFRelationship } from '../core/embedders/FileEmbedder';
66
67
import PDFEmbeddedFile from './PDFEmbeddedFile' ;
67
68
import PDFJavaScript from './PDFJavaScript' ;
68
69
import JavaScriptEmbedder from '../core/embedders/JavaScriptEmbedder' ;
70
+ import { CipherTransformFactory } from '../core/crypto' ;
69
71
70
72
/**
71
73
* Represents a PDF document.
@@ -147,7 +149,20 @@ export default class PDFDocument {
147
149
throwOnInvalidObject ,
148
150
capNumbers ,
149
151
) . parseDocument ( ) ;
150
- return new PDFDocument ( context , ignoreEncryption , updateMetadata ) ;
152
+ const pdfDoc = new PDFDocument ( context , ignoreEncryption , updateMetadata , false ) ;
153
+
154
+ if ( pdfDoc . isEncrypted ) {
155
+ // Decrypt
156
+ const context = await PDFParser . forBytesWithOptions (
157
+ bytes ,
158
+ parseSpeed ,
159
+ throwOnInvalidObject ,
160
+ capNumbers ,
161
+ pdfDoc . cryptoFactory
162
+ ) . parseDocument ( ) ;
163
+ return new PDFDocument ( context , true , updateMetadata , true ) ;
164
+ }
165
+ return pdfDoc ;
151
166
}
152
167
153
168
/**
@@ -163,7 +178,7 @@ export default class PDFDocument {
163
178
const catalog = PDFCatalog . withContextAndPages ( context , pageTreeRef ) ;
164
179
context . trailerInfo . Root = context . register ( catalog ) ;
165
180
166
- return new PDFDocument ( context , false , updateMetadata ) ;
181
+ return new PDFDocument ( context , false , updateMetadata , false ) ;
167
182
}
168
183
169
184
/** The low-level context of this document. */
@@ -175,6 +190,8 @@ export default class PDFDocument {
175
190
/** Whether or not this document is encrypted. */
176
191
readonly isEncrypted : boolean ;
177
192
193
+ readonly cryptoFactory ?: CipherTransformFactory ;
194
+
178
195
/** The default word breaks used in PDFPage.drawText */
179
196
defaultWordBreaks : string [ ] = [ ' ' ] ;
180
197
@@ -193,6 +210,7 @@ export default class PDFDocument {
193
210
context : PDFContext ,
194
211
ignoreEncryption : boolean ,
195
212
updateMetadata : boolean ,
213
+ isDecrypted : boolean
196
214
) {
197
215
assertIs ( context , 'context' , [ [ PDFContext , 'PDFContext' ] ] ) ;
198
216
assertIs ( ignoreEncryption , 'ignoreEncryption' , [ 'boolean' ] ) ;
@@ -201,6 +219,15 @@ export default class PDFDocument {
201
219
this . catalog = context . lookup ( context . trailerInfo . Root ) as PDFCatalog ;
202
220
this . isEncrypted = ! ! context . lookup ( context . trailerInfo . Encrypt ) ;
203
221
222
+ if ( this . isEncrypted && ! isDecrypted ) {
223
+ const encryptDict = context . lookup ( context . trailerInfo . Encrypt , PDFDict ) ;
224
+ const fileIds = context . lookup ( context . trailerInfo . ID , PDFArray ) ;
225
+ this . cryptoFactory = new CipherTransformFactory ( encryptDict , ( fileIds . get ( 0 ) as PDFHexString ) . asBytes ( ) )
226
+ } else if ( this . isEncrypted ) {
227
+ // context.delete(context.trailerInfo.Encrypt);
228
+ delete context . trailerInfo . Encrypt ;
229
+ }
230
+
204
231
this . pageCache = Cache . populatedBy ( this . computePages ) ;
205
232
this . pageMap = new Map ( ) ;
206
233
this . formCache = Cache . populatedBy ( this . getOrCreateForm ) ;
0 commit comments