Skip to content

Commit 227a902

Browse files
committed
#2803: better logging for UFDR evidences with protection enabled
1 parent 8f388f0 commit 227a902

File tree

1 file changed

+77
-30
lines changed

1 file changed

+77
-30
lines changed

iped-engine/src/main/java/iped/engine/datasource/UfedXmlReader.java

Lines changed: 77 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.io.FileInputStream;
77
import java.io.IOException;
88
import java.io.InputStream;
9-
import java.io.InputStreamReader;
109
import java.io.OutputStreamWriter;
1110
import java.nio.charset.StandardCharsets;
1211
import java.nio.file.Files;
@@ -39,6 +38,8 @@
3938
import javax.xml.parsers.SAXParser;
4039
import javax.xml.parsers.SAXParserFactory;
4140

41+
import org.apache.commons.io.FileUtils;
42+
import org.apache.commons.io.FilenameUtils;
4243
import org.apache.commons.lang3.StringUtils;
4344
import org.apache.logging.log4j.Level;
4445
import org.apache.logging.log4j.LogManager;
@@ -99,6 +100,12 @@ public class UfedXmlReader extends DataSourceReader {
99100
private final Level CONSOLE = Level.getLevel("MSG"); //$NON-NLS-1$
100101

101102
private static final String[] HEADER_STRINGS = { "project id", "extractionType", "sourceExtractions" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
103+
private static final byte[] UFDR_PROTECTION_NO_PASSWORD_REPORT_XML_INITIAL_BYTES = new byte[] { 0x2D, 0x06, 0x52, 0x6D };
104+
private static final int UFDR_REPORT_XML_INITIAL_BYTES_TO_READ = 1024;
105+
106+
private static final String UFDR_EXTENSION = "ufdr";
107+
private static final String XML_REPORT_EXTENSION = "xml";
108+
102109

103110
private static final String AVATAR_PATH_META = ExtraProperties.UFED_META_PREFIX + "contactphoto_extracted_path"; //$NON-NLS-1$
104111
private static final String ATTACH_PATH_META = ExtraProperties.UFED_META_PREFIX + "attachment_extracted_path"; //$NON-NLS-1$
@@ -152,41 +159,40 @@ public UfedXmlReader(ICaseData caseData, File output, boolean listOnly) {
152159
@Override
153160
public boolean isSupported(File datasource) {
154161

155-
if (datasource.getName().toLowerCase().endsWith(".ufdr")) {
162+
if (FilenameUtils.isExtension(datasource.getName(), UFDR_EXTENSION)) {
156163
return true;
157164
}
158165

159-
InputStream xmlReport = lookUpXmlReportInputStream(datasource);
160-
IOUtil.closeQuietly(xmlReport);
161-
162-
if (xmlReport != null)
163-
return true;
164-
165-
return false;
166+
// supports any folder with valid XML report inside
167+
try (InputStream xmlReport = lookUpXmlReportInputStream(datasource)) {
168+
return xmlReport != null;
169+
} catch (Exception e) {
170+
return false;
171+
}
166172
}
167173

168174
private InputStream getXmlInputStream(File file) {
169-
if (file.getName().toLowerCase().endsWith(".xml")) { //$NON-NLS-1$
170-
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), "UTF-8")) { //$NON-NLS-1$
171-
char[] cbuf = new char[1024];
172-
int off = 0, i = 0;
173-
while (off < cbuf.length && (i = reader.read(cbuf, off, cbuf.length - off)) != -1)
174-
off += i;
175-
String header = new String(cbuf, 0, off);
176-
for (String str : HEADER_STRINGS)
177-
if (!header.contains(str))
178-
return null;
175+
if (FilenameUtils.isExtension(file.getName(), XML_REPORT_EXTENSION)) {
176+
try (InputStream fis = new FileInputStream(file)) {
177+
byte[] initialBytes = fis.readNBytes(UFDR_REPORT_XML_INITIAL_BYTES_TO_READ);
178+
if (!containsHeaderStrings(initialBytes)) {
179+
return null;
180+
}
181+
179182
return new FileInputStream(file);
180183

181184
} catch (IOException e) {
182185
throw new RuntimeException(e);
183186
}
184-
} else if (file.getName().toLowerCase().endsWith(".ufdr")) {
187+
} else if (FilenameUtils.isExtension(file.getName(), UFDR_EXTENSION)) {
185188
try {
186189
ufdrFile = file;
187190
String xml = "report.xml";
188191
if (!getUISF().entryExists(xml)) {
189192
xml = "Report.xml";
193+
if (!getUISF().entryExists(xml)) {
194+
return null;
195+
}
190196
}
191197
return getUISF().getSeekableInputStream(xml);
192198

@@ -197,6 +203,21 @@ private InputStream getXmlInputStream(File file) {
197203
return null;
198204
}
199205

206+
private boolean isReportXmlProtected(byte[] initialBytes) {
207+
int len = UFDR_PROTECTION_NO_PASSWORD_REPORT_XML_INITIAL_BYTES.length;
208+
return Arrays.equals(initialBytes, 0, len, UFDR_PROTECTION_NO_PASSWORD_REPORT_XML_INITIAL_BYTES, 0, len);
209+
}
210+
211+
private boolean containsHeaderStrings(byte[] initialBytes) {
212+
String header = new String(initialBytes, StandardCharsets.UTF_8);
213+
for (String str : HEADER_STRINGS)
214+
if (header.contains(str))
215+
return true;
216+
217+
return false;
218+
219+
}
220+
200221
private boolean entryExists(String entryPath) {
201222
if (ufdrFile != null) {
202223
return getUISF().entryExists(entryPath);
@@ -233,16 +254,13 @@ private FileInputStreamFactory getFISF() {
233254
private InputStream lookUpXmlReportInputStream(File root) {
234255
if (root.isFile())
235256
return getXmlInputStream(root);
236-
File[] files = root.listFiles();
237-
if (files != null) {
238-
for (File file : files) {
239-
if (file.getName().toLowerCase().endsWith(".xml")) {
240-
InputStream is = getXmlInputStream(file);
241-
if (is != null)
242-
return is;
243-
}
244-
}
257+
258+
for (File file : FileUtils.listFiles(root, new String[]{XML_REPORT_EXTENSION}, false)) {
259+
InputStream is = getXmlInputStream(file);
260+
if (is != null)
261+
return is;
245262
}
263+
246264
return null;
247265
}
248266

@@ -261,6 +279,8 @@ public void read(File root, Item parent) throws Exception {
261279
try {
262280
xmlStream = lookUpXmlReportInputStream(root);
263281

282+
validateXmlStream(xmlStream);
283+
264284
configureParsers();
265285

266286
SAXParserFactory spf = SAXParserFactory.newInstance();
@@ -275,6 +295,33 @@ public void read(File root, Item parent) throws Exception {
275295
}
276296
}
277297

298+
private void validateXmlStream(InputStream xmlStream) throws IOException {
299+
if (xmlStream == null) {
300+
if (root.isFile()) {
301+
throw new RuntimeException("Invalid UFDR file: XML report not found. File: " + root.getAbsolutePath());
302+
} else {
303+
throw new RuntimeException("Invalid UFDR folder: No XML report has been found. Folder: " + root.getAbsolutePath());
304+
}
305+
}
306+
307+
if (root.isFile()) {
308+
xmlStream.mark(0);
309+
byte[] initialBytes = xmlStream.readNBytes(UFDR_REPORT_XML_INITIAL_BYTES_TO_READ);
310+
311+
if (isReportXmlProtected(initialBytes)) {
312+
throw new RuntimeException("Unsupported UFDR file: protection is enabled. Generate the UFDR file again with protection disabled."
313+
+ (root != null ? " File: " + root.getAbsolutePath() : ""));
314+
}
315+
316+
if (!containsHeaderStrings(initialBytes)) {
317+
throw new RuntimeException("Invalid UFDR file: XML report is not valid. "
318+
+ "Protection may be enabled. Generate the UFDR file again with protection disabled."
319+
+ (root != null ? " File: " + root.getAbsolutePath() : ""));
320+
}
321+
xmlStream.reset();
322+
}
323+
}
324+
278325
private void configureParsers() {
279326
configureParsers(false);
280327
}
@@ -317,7 +364,7 @@ private void addRootItem(IItem parent) throws InterruptedException {
317364
rootItem.setDataSource(evidenceSource);
318365
rootItem.setIdInDataSource("");
319366
rootItem.setHasChildren(true);
320-
if (root.getName().endsWith(".ufdr")) {
367+
if (FilenameUtils.isExtension(root.getName(), UFDR_EXTENSION)) {
321368
rootItem.setLength(root.length());
322369
rootItem.setSumVolume(false);
323370
}

0 commit comments

Comments
 (0)