@@ -31,6 +31,7 @@ import {
31
31
} from "./core_utils.js" ;
32
32
import { BaseStream } from "./base_stream.js" ;
33
33
import { CipherTransformFactory } from "./crypto.js" ;
34
+ import { NameTree } from "./name_number_tree.js" ;
34
35
35
36
class XRef {
36
37
#firstXRefStmPos = null ;
@@ -118,22 +119,6 @@ class XRef {
118
119
}
119
120
warn ( `XRef.parse - Invalid "Encrypt" reference: "${ ex } ".` ) ;
120
121
}
121
- if ( encrypt instanceof Dict ) {
122
- const ids = trailerDict . get ( "ID" ) ;
123
- const fileId = ids ?. length ? ids [ 0 ] : "" ;
124
- // The 'Encrypt' dictionary itself should not be encrypted, and by
125
- // setting `suppressEncryption` we can prevent an infinite loop inside
126
- // of `XRef_fetchUncompressed` if the dictionary contains indirect
127
- // objects (fixes issue7665.pdf).
128
- encrypt . suppressEncryption = true ;
129
- this . encrypt = new CipherTransformFactory (
130
- encrypt ,
131
- fileId ,
132
- this . pdfManager . password
133
- ) ;
134
- }
135
-
136
- // Get the root dictionary (catalog) object, and do some basic validation.
137
122
let root ;
138
123
try {
139
124
root = trailerDict . get ( "Root" ) ;
@@ -143,6 +128,51 @@ class XRef {
143
128
}
144
129
warn ( `XRef.parse - Invalid "Root" reference: "${ ex } ".` ) ;
145
130
}
131
+
132
+ if ( encrypt instanceof Dict ) {
133
+ const ids = trailerDict . get ( "ID" ) ;
134
+ const fileId = ids ?. length ? ids [ 0 ] : "" ;
135
+
136
+ const stmF = encrypt . get ( "StmF" ) ?. name ?? "Identity" ;
137
+ const strF = encrypt . get ( "StrF" ) ?. name ?? "Identity" ;
138
+ const eff = encrypt . has ( "EFF" ) ? encrypt . get ( "EFF" ) ?. name : strF ;
139
+ const cryptFilters = encrypt . get ( "CF" ) || Dict . empty ;
140
+ // Check if only the file attachments are encrypted.
141
+ if (
142
+ stmF === "Identity" &&
143
+ strF === "Identity" &&
144
+ eff !== "Identity" &&
145
+ cryptFilters . get ( eff ) ?. get ( "CFM" ) !== "None"
146
+ ) {
147
+ let hasEncryptedAttachments = false ;
148
+ if ( root instanceof Dict ) {
149
+ const names = root . get ( "Names" ) ;
150
+ if ( names instanceof Dict && names . has ( "EmbeddedFiles" ) ) {
151
+ const nameTree = new NameTree ( names . getRaw ( "EmbeddedFiles" ) , this ) ;
152
+ const attachments = nameTree . getAll ( ) ;
153
+ if ( attachments . size > 0 ) {
154
+ hasEncryptedAttachments = true ;
155
+ }
156
+ }
157
+ }
158
+ if ( ! hasEncryptedAttachments ) {
159
+ // If there are no encrypted attachments, encrypt dictionary is
160
+ // not needed.
161
+ encrypt = null ;
162
+ }
163
+ } else {
164
+ // The 'Encrypt' dictionary itself should not be encrypted, and by
165
+ // setting `suppressEncryption` we can prevent an infinite loop inside
166
+ // of `XRef_fetchUncompressed` if the dictionary contains indirect
167
+ // objects (fixes issue7665.pdf).
168
+ encrypt . suppressEncryption = true ;
169
+ this . encrypt = new CipherTransformFactory (
170
+ encrypt ,
171
+ fileId ,
172
+ this . pdfManager . password
173
+ ) ;
174
+ }
175
+ }
146
176
if ( root instanceof Dict ) {
147
177
try {
148
178
const pages = root . get ( "Pages" ) ;
0 commit comments