Skip to content

Commit e24a2a9

Browse files
committed
Make RUPS open document in read-only mode by default
Since the iText library upgrade we have an issue, that some of the information is missing from the trailer. For example, the /Info dictionary is always missing, if the PDF document is opened in the read-write mode. But even before that, there were some modifications happening to the data, like the modification date changing. As a workaround for now we will start opening all the files in the read-only mode by default. In this case it should show data much closer to what is in the original document. If you want to edit the document, you can use the "Reopen as Owner" option, which reuses the code added for user/owner password protection handling. This still leave the issue, that in the read-write mode the data doesn't match, but it would take more effort to solve...
1 parent 35db459 commit e24a2a9

File tree

2 files changed

+61
-45
lines changed

2 files changed

+61
-45
lines changed

src/main/java/com/itextpdf/rups/model/PdfFile.java

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ public static PdfFile openAsOwner(File file, byte[] content) throws IOException
112112
return openAsOwner(file, content, DialogPasswordProvider.ownerPassword());
113113
}
114114

115-
116115
public static PdfFile openAsOwner(File file, byte[] content, IPasswordProvider passwordProvider)
117116
throws IOException {
118117
final PdfFile pdfFile = new PdfFile(file, content);
@@ -148,24 +147,18 @@ public ByteArrayOutputStream getByteArrayOutputStream() {
148147
private void openDocument(IPasswordProvider passwordProvider, boolean requireEditable)
149148
throws IOException {
150149
/*
151-
* This should pass in the majority of cases (i.e. if the document is
152-
* non-encrypted).
153-
*/
154-
if (openDocumentReadWrite()) {
155-
return;
156-
}
157-
158-
/*
159-
* If it is, actually, protected, we will try to open it in a read-only
160-
* mode. This should pass, if the document is protected, but there is no
161-
* user password.
150+
* This block should succeed, if there is no password protection.
162151
*
163-
* In this case any editing operations in RUPS should be disabled.
152+
* By default, editing operations in RUPS should be disabled. Ideally
153+
* we would just open the document in the read-write mode everytime
154+
* for convenience. But, annoyingly, in iText, if you open the document
155+
* in the read-write mode, some of the original information will get
156+
* lost, like, for example, the /Info dictionary.
164157
*
165-
* If the requireEditable flag is set to true, we skip trying to open
166-
* the document in a read-only mode.
158+
* If the requireEditable flag is set to true, we only try to open the
159+
* document in the read-write mode.
167160
*/
168-
if (!requireEditable && openDocumentReadOnly()) {
161+
if (openDocument(requireEditable)) {
169162
return;
170163
}
171164

@@ -174,23 +167,17 @@ private void openDocument(IPasswordProvider passwordProvider, boolean requireEdi
174167
* password provider to get the password and will try to use it to open
175168
* the document.
176169
*
177-
* Since user can provide any of the two password, we will try first to
178-
* open as an owner (read/write) and then, if failed, as a user
179-
* (read-only). If both failed, we will keep asking for the correct
180-
* password until password provider signals cancellation.
181-
*
182-
* If the requireEditable flag is set to true, we skip trying to open
183-
* the document in a read-only mode.
170+
* Since user can provide any of the two passwords, if editing was
171+
* requested, but only a user password was provided, it will fail.
172+
* We will keep asking for the correct password until password
173+
* provider signals cancellation.
184174
*/
185175
while (true) {
186176
final byte[] password = passwordProvider.get(getOriginalFile());
187177
if (password == null) {
188178
throw new BadPasswordException(Language.ERROR_MISSING_PASSWORD.getString());
189179
}
190-
if (openDocumentReadWrite(password)) {
191-
return;
192-
}
193-
if (!requireEditable && openDocumentReadOnly(password)) {
180+
if (openDocument(password, requireEditable)) {
194181
return;
195182
}
196183
/*
@@ -203,6 +190,41 @@ private void openDocument(IPasswordProvider passwordProvider, boolean requireEdi
203190
}
204191
}
205192

193+
/**
194+
* Tries to open the PDF document without a password. Read-only or
195+
* read-write mode depends on the requireEditable parameter.
196+
* If the document is encrypted, returns {@code false}.
197+
*
198+
* @param requireEditable {@code true}, if document should be opened in a
199+
* read-write mode
200+
*
201+
* @return {@code true} on success; {@code false} if encrypted
202+
*/
203+
private boolean openDocument(boolean requireEditable) throws IOException {
204+
if (requireEditable) {
205+
return openDocumentReadWrite();
206+
}
207+
return openDocumentReadOnly();
208+
}
209+
210+
/**
211+
* Tries to open the PDF document with the provided password. Read-only or
212+
* read-write mode depends on the requireEditable parameter.
213+
* If the password is incorrect, returns {@code false}.
214+
*
215+
* @param password password to use, when decrypting
216+
* @param requireEditable {@code true}, if document should be opened in a
217+
* read-write mode
218+
*
219+
* @return {@code true} on success; {@code false} if encrypted
220+
*/
221+
private boolean openDocument(byte[] password, boolean requireEditable) throws IOException {
222+
if (requireEditable) {
223+
return openDocumentReadWrite(password);
224+
}
225+
return openDocumentReadOnly(password);
226+
}
227+
206228
/**
207229
* Tries to open the PDF document in a read/write mode without a password.
208230
* If the document is encrypted, returns {@code false}.

src/test/java/com/itextpdf/rups/model/PdfFileTest.java

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ class PdfFileTest {
6868
void open_RegularFileTest() throws IOException {
6969
PdfFile openedFile = openTestFile("regular.pdf", "");
7070
/*
71-
* Should be opened as owner (i.e. read/write), as it is not encrypted.
71+
* Should be opened in the read-only mode, as this is the default.
7272
*/
73-
Assertions.assertTrue(openedFile.isOpenedAsOwner());
74-
Assertions.assertNotNull(openedFile.getByteArrayOutputStream());
73+
Assertions.assertFalse(openedFile.isOpenedAsOwner());
74+
Assertions.assertNull(openedFile.getByteArrayOutputStream());
7575
// Sanity check, that it opened the document properly
7676
Assertions.assertEquals(
7777
"REGULAR",
@@ -83,8 +83,7 @@ void open_RegularFileTest() throws IOException {
8383
void open_OwnerProtectedFileWithoutPasswordTest() throws IOException {
8484
PdfFile openedFile = openTestFile("protected_with_owner_password.pdf", null);
8585
/*
86-
* Should be opened as user (i.e. read-only), as it is protected, and
87-
* we did not provide any password.
86+
* Should be opened in the read-only mode, as this is the default.
8887
*/
8988
Assertions.assertFalse(openedFile.isOpenedAsOwner());
9089
Assertions.assertNull(openedFile.getByteArrayOutputStream());
@@ -99,8 +98,7 @@ void open_OwnerProtectedFileWithoutPasswordTest() throws IOException {
9998
void open_OwnerProtectedFileWithIncorrectPasswordTest() throws IOException {
10099
PdfFile openedFile = openTestFile("protected_with_owner_password.pdf", "incorrect");
101100
/*
102-
* Should be opened as user (i.e. read-only), as it is protected, and
103-
* we did not provide a correct password.
101+
* Should be opened in the read-only mode, as this is the default.
104102
*/
105103
Assertions.assertFalse(openedFile.isOpenedAsOwner());
106104
Assertions.assertNull(openedFile.getByteArrayOutputStream());
@@ -115,9 +113,7 @@ void open_OwnerProtectedFileWithIncorrectPasswordTest() throws IOException {
115113
void open_OwnerProtectedFileWithCorrectPasswordTest() throws IOException {
116114
PdfFile openedFile = openTestFile("protected_with_owner_password.pdf", OWNER_PASSWORD);
117115
/*
118-
* Should still be opened as user (i.e. read-only), as it is protected,
119-
* and the open method does not request a password, if the file can be
120-
* opened in a read-only mode.
116+
* Should be opened in the read-only mode, as this is the default.
121117
*/
122118
Assertions.assertFalse(openedFile.isOpenedAsOwner());
123119
Assertions.assertNull(openedFile.getByteArrayOutputStream());
@@ -156,8 +152,7 @@ void open_UserProtectedFileWithIncorrectPasswordTest() {
156152
void open_UserProtectedFileWithUserPasswordTest() throws IOException {
157153
PdfFile openedFile = openTestFile("protected_with_both_passwords.pdf", USER_PASSWORD);
158154
/*
159-
* Should be opened as user (i.e. read-only), as it is protected, and
160-
* we only provided the user password.
155+
* Should be opened in the read-only mode, as this is the default.
161156
*/
162157
Assertions.assertFalse(openedFile.isOpenedAsOwner());
163158
Assertions.assertNull(openedFile.getByteArrayOutputStream());
@@ -172,11 +167,10 @@ void open_UserProtectedFileWithUserPasswordTest() throws IOException {
172167
void open_UserProtectedFileWithOwnerPasswordTest() throws IOException {
173168
PdfFile openedFile = openTestFile("protected_with_both_passwords.pdf", OWNER_PASSWORD);
174169
/*
175-
* Should be opened as owner (i.e. read/write), as it is protected, and
176-
* we provided the owner password.
170+
* Should be opened in the read-only mode, as this is the default.
177171
*/
178-
Assertions.assertTrue(openedFile.isOpenedAsOwner());
179-
Assertions.assertNotNull(openedFile.getByteArrayOutputStream());
172+
Assertions.assertFalse(openedFile.isOpenedAsOwner());
173+
Assertions.assertNull(openedFile.getByteArrayOutputStream());
180174
// Sanity check, that it opened the document properly
181175
Assertions.assertEquals(
182176
"DIFFERENT USER AND OWNER PASSWORDS",
@@ -195,7 +189,7 @@ void openAsOwner_RegularFileTest() throws IOException {
195189
}
196190

197191
@Test
198-
void openAsOwner_OwnerProtectedFileWithoutPasswordTest() throws IOException {
192+
void openAsOwner_OwnerProtectedFileWithoutPasswordTest() {
199193
/*
200194
* Here it should throw a bad password error, as it won't get opened as
201195
* an owner without a password.
@@ -207,7 +201,7 @@ void openAsOwner_OwnerProtectedFileWithoutPasswordTest() throws IOException {
207201
}
208202

209203
@Test
210-
void openAsOwner_OwnerProtectedFileWithIncorrectPasswordTest() throws IOException {
204+
void openAsOwner_OwnerProtectedFileWithIncorrectPasswordTest() {
211205
/*
212206
* Here it should throw a bad password error, as it won't get opened as
213207
* an owner with an incorrect password.

0 commit comments

Comments
 (0)