23 package org.sleuthkit.autopsy.recentactivity;
25 import com.google.gson.JsonArray;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonIOException;
28 import com.google.gson.JsonObject;
29 import com.google.gson.JsonParser;
30 import com.google.gson.JsonSyntaxException;
32 import java.io.FileNotFoundException;
33 import java.io.FileReader;
34 import java.io.IOException;
35 import java.io.UnsupportedEncodingException;
36 import java.net.URLDecoder;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collection;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.List;
44 import java.util.logging.Level;
45 import org.apache.commons.io.FilenameUtils;
47 import org.openide.util.NbBundle;
48 import org.openide.util.NbBundle.Messages;
62 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
64 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
66 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
70 "Progress_Message_Firefox_History=Firefox History",
71 "Progress_Message_Firefox_Bookmarks=Firefox Bookmarks",
72 "Progress_Message_Firefox_Cookies=Firefox Cookies",
73 "Progress_Message_Firefox_Downloads=Firefox Downloads",
74 "Progress_Message_Firefox_FormHistory=Firefox Form History",
75 "Progress_Message_Firefox_AutoFill=Firefox Auto Fill"
81 class Firefox extends Extract {
83 private static final Logger logger = Logger.getLogger(Firefox.class.getName());
84 private static final String PLACE_URL_PREFIX =
"place:";
85 private static final String HISTORY_QUERY =
"SELECT moz_historyvisits.id, url, title, visit_count,(visit_date/1000000) AS visit_date,from_visit,"
86 +
"(SELECT url FROM moz_historyvisits history, moz_places places where history.id = moz_historyvisits.from_visit and history.place_id = places.id ) as ref "
87 +
"FROM moz_places, moz_historyvisits "
88 +
"WHERE moz_places.id = moz_historyvisits.place_id "
90 private static final String COOKIE_QUERY =
"SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed,(creationTime/1000000) AS creationTime FROM moz_cookies";
91 private static final String COOKIE_QUERY_V3 =
"SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed FROM moz_cookies";
92 private static final String BOOKMARK_QUERY =
"SELECT fk, moz_bookmarks.title, url, (moz_bookmarks.dateAdded/1000000) AS dateAdded FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id";
93 private static final String DOWNLOAD_QUERY =
"SELECT target, source,(startTime/1000000) AS startTime, maxBytes FROM moz_downloads";
94 private static final String DOWNLOAD_QUERY_V24 =
"SELECT url, content AS target, (lastModified/1000000) AS lastModified "
95 +
" FROM moz_places, moz_annos, moz_anno_attributes "
96 +
" WHERE moz_places.id = moz_annos.place_id"
97 +
" AND moz_annos.anno_attribute_id = moz_anno_attributes.id"
98 +
" AND moz_anno_attributes.name='downloads/destinationFileURI'";
99 private static final String FORMHISTORY_QUERY =
"SELECT fieldname, value FROM moz_formhistory";
100 private static final String FORMHISTORY_QUERY_V64 =
"SELECT fieldname, value, timesUsed, firstUsed, lastUsed FROM moz_formhistory";
101 private final IngestServices services = IngestServices.getInstance();
102 private Content dataSource;
103 private IngestJobContext context;
106 moduleName = NbBundle.getMessage(Firefox.class,
"Firefox.moduleName");
110 public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
111 this.dataSource = dataSource;
112 this.context = context;
115 progressBar.progress(Bundle.Progress_Message_Firefox_History());
118 progressBar.progress(Bundle.Progress_Message_Firefox_Bookmarks());
121 progressBar.progress(Bundle.Progress_Message_Firefox_Downloads());
124 progressBar.progress(Bundle.Progress_Message_Firefox_Cookies());
127 progressBar.progress(Bundle.Progress_Message_Firefox_FormHistory());
128 this.getFormsHistory();
130 progressBar.progress(Bundle.Progress_Message_Firefox_AutoFill());
131 this.getAutofillProfiles();
134 private void getHistory() {
135 FileManager fileManager = currentCase.getServices().getFileManager();
136 List<AbstractFile> historyFiles;
138 historyFiles = fileManager.findFiles(dataSource,
"places.sqlite",
"Firefox");
139 }
catch (TskCoreException ex) {
140 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getHistory.errMsg.errFetchingFiles");
141 logger.log(Level.WARNING, msg);
142 this.addErrorMessage(this.getName() +
": " + msg);
146 if (historyFiles.isEmpty()) {
147 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getHistory.errMsg.noFilesFound");
148 logger.log(Level.INFO, msg);
153 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
155 for (AbstractFile historyFile : historyFiles) {
156 if (historyFile.getSize() == 0) {
160 String fileName = historyFile.getName();
161 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
163 ContentUtils.writeToFile(historyFile,
new File(temps), context::dataSourceIngestIsCancelled);
164 }
catch (ReadContentInputStreamException ex) {
165 logger.log(Level.WARNING, String.format(
"Error reading Firefox web history artifacts file '%s' (id=%d).",
166 fileName, historyFile.getId()), ex);
167 this.addErrorMessage(
168 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
171 }
catch (IOException ex) {
172 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
173 temps, fileName, historyFile.getId()), ex);
174 this.addErrorMessage(
175 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
179 File dbFile =
new File(temps);
180 if (context.dataSourceIngestIsCancelled()) {
184 List<HashMap<String, Object>> tempList = this.dbConnect(temps, HISTORY_QUERY);
185 logger.log(Level.INFO,
"{0} - Now getting history from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
186 for (HashMap<String, Object> result : tempList) {
187 String url = result.get(
"url").toString();
189 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
190 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
191 RecentActivityExtracterModuleFactory.getModuleName(),
192 ((url != null) ? url :
"")));
194 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
195 RecentActivityExtracterModuleFactory.getModuleName(),
196 (Long.valueOf(result.get(
"visit_date").toString()))));
197 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
198 RecentActivityExtracterModuleFactory.getModuleName(),
199 ((result.get(
"ref").toString() != null) ? result.get(
"ref").toString() :
"")));
200 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
201 RecentActivityExtracterModuleFactory.getModuleName(),
202 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
203 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
204 RecentActivityExtracterModuleFactory.getModuleName(),
205 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
206 String domain = extractDomain(url);
207 if (domain != null && domain.isEmpty() ==
false) {
208 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
209 RecentActivityExtracterModuleFactory.getModuleName(), domain));
212 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
214 bbartifacts.add(bbart);
221 services.fireModuleDataEvent(
new ModuleDataEvent(
222 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
223 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, bbartifacts));
229 private void getBookmark() {
231 FileManager fileManager = currentCase.getServices().getFileManager();
232 List<AbstractFile> bookmarkFiles;
234 bookmarkFiles = fileManager.findFiles(dataSource,
"places.sqlite",
"Firefox");
235 }
catch (TskCoreException ex) {
236 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getBookmark.errMsg.errFetchFiles");
237 logger.log(Level.WARNING, msg);
238 this.addErrorMessage(this.getName() +
": " + msg);
242 if (bookmarkFiles.isEmpty()) {
243 logger.log(Level.INFO,
"Didn't find any firefox bookmark files.");
248 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
250 for (AbstractFile bookmarkFile : bookmarkFiles) {
251 if (bookmarkFile.getSize() == 0) {
254 String fileName = bookmarkFile.getName();
255 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
257 ContentUtils.writeToFile(bookmarkFile,
new File(temps), context::dataSourceIngestIsCancelled);
258 }
catch (ReadContentInputStreamException ex) {
259 logger.log(Level.WARNING, String.format(
"Error reading Firefox bookmark artifacts file '%s' (id=%d).",
260 fileName, bookmarkFile.getId()), ex);
261 this.addErrorMessage(
262 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
265 }
catch (IOException ex) {
266 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox bookmark artifacts file '%s' (id=%d).",
267 temps, fileName, bookmarkFile.getId()), ex);
268 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getBookmark.errMsg.errAnalyzeFile",
269 this.getName(), fileName));
272 File dbFile =
new File(temps);
273 if (context.dataSourceIngestIsCancelled()) {
277 List<HashMap<String, Object>> tempList = this.dbConnect(temps, BOOKMARK_QUERY);
278 logger.log(Level.INFO,
"{0} - Now getting bookmarks from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
279 for (HashMap<String, Object> result : tempList) {
280 String url = result.get(
"url").toString();
282 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
283 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
284 RecentActivityExtracterModuleFactory.getModuleName(),
285 ((url != null) ? url :
"")));
286 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
287 RecentActivityExtracterModuleFactory.getModuleName(),
288 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
289 if (Long.valueOf(result.get(
"dateAdded").toString()) > 0) {
290 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
291 RecentActivityExtracterModuleFactory.getModuleName(),
292 (Long.valueOf(result.get(
"dateAdded").toString()))));
294 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
295 RecentActivityExtracterModuleFactory.getModuleName(),
296 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
297 String domain = extractDomain(url);
298 if (domain != null && domain.isEmpty() ==
false) {
299 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
300 RecentActivityExtracterModuleFactory.getModuleName(), domain));
303 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes);
305 bbartifacts.add(bbart);
312 services.fireModuleDataEvent(
new ModuleDataEvent(
313 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
314 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bbartifacts));
320 private void getCookie() {
321 FileManager fileManager = currentCase.getServices().getFileManager();
322 List<AbstractFile> cookiesFiles;
324 cookiesFiles = fileManager.findFiles(dataSource,
"cookies.sqlite",
"Firefox");
325 }
catch (TskCoreException ex) {
326 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getCookie.errMsg.errFetchFile");
327 logger.log(Level.WARNING, msg);
328 this.addErrorMessage(this.getName() +
": " + msg);
332 if (cookiesFiles.isEmpty()) {
333 logger.log(Level.INFO,
"Didn't find any Firefox cookie files.");
338 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
340 for (AbstractFile cookiesFile : cookiesFiles) {
341 if (cookiesFile.getSize() == 0) {
344 String fileName = cookiesFile.getName();
345 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
347 ContentUtils.writeToFile(cookiesFile,
new File(temps), context::dataSourceIngestIsCancelled);
348 }
catch (ReadContentInputStreamException ex) {
349 logger.log(Level.WARNING, String.format(
"Error reading Firefox cookie artifacts file '%s' (id=%d).",
350 fileName, cookiesFile.getId()), ex);
351 this.addErrorMessage(
352 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
355 }
catch (IOException ex) {
356 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox cookie artifacts file '%s' (id=%d).",
357 temps, fileName, cookiesFile.getId()), ex);
358 this.addErrorMessage(
359 NbBundle.getMessage(
this.getClass(),
"Firefox.getCookie.errMsg.errAnalyzeFile", this.getName(),
363 File dbFile =
new File(temps);
364 if (context.dataSourceIngestIsCancelled()) {
368 boolean checkColumn = Util.checkColumn(
"creationTime",
"moz_cookies", temps);
371 query = COOKIE_QUERY;
373 query = COOKIE_QUERY_V3;
376 List<HashMap<String, Object>> tempList = this.dbConnect(temps, query);
377 logger.log(Level.INFO,
"{0} - Now getting cookies from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
378 for (HashMap<String, Object> result : tempList) {
379 String host = result.get(
"host").toString();
381 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
382 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
383 RecentActivityExtracterModuleFactory.getModuleName(),
384 ((host != null) ? host :
"")));
385 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
386 RecentActivityExtracterModuleFactory.getModuleName(),
387 (Long.valueOf(result.get(
"lastAccessed").toString()))));
388 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
389 RecentActivityExtracterModuleFactory.getModuleName(),
390 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
391 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
392 RecentActivityExtracterModuleFactory.getModuleName(),
393 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
394 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
395 RecentActivityExtracterModuleFactory.getModuleName(),
396 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
398 if (checkColumn ==
true) {
399 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
400 RecentActivityExtracterModuleFactory.getModuleName(),
401 (Long.valueOf(result.get(
"creationTime").toString()))));
403 String domain = extractDomain(host);
404 if (domain != null && domain.isEmpty() ==
false) {
405 domain = domain.replaceFirst(
"^\\.+(?!$)",
"");
406 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
407 RecentActivityExtracterModuleFactory.getModuleName(), domain));
410 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
412 bbartifacts.add(bbart);
419 services.fireModuleDataEvent(
new ModuleDataEvent(
420 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
421 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, bbartifacts));
427 private void getDownload() {
428 getDownloadPreVersion24();
429 getDownloadVersion24();
437 private void getDownloadPreVersion24() {
439 FileManager fileManager = currentCase.getServices().getFileManager();
440 List<AbstractFile> downloadsFiles;
442 downloadsFiles = fileManager.findFiles(dataSource,
"downloads.sqlite",
"Firefox");
443 }
catch (TskCoreException ex) {
444 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getDlPre24.errMsg.errFetchFiles");
445 logger.log(Level.WARNING, msg);
446 this.addErrorMessage(this.getName() +
": " + msg);
450 if (downloadsFiles.isEmpty()) {
451 logger.log(Level.INFO,
"Didn't find any pre-version-24.0 Firefox download files.");
456 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
458 for (AbstractFile downloadsFile : downloadsFiles) {
459 if (downloadsFile.getSize() == 0) {
462 String fileName = downloadsFile.getName();
463 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
466 ContentUtils.writeToFile(downloadsFile,
new File(temps), context::dataSourceIngestIsCancelled);
467 }
catch (ReadContentInputStreamException ex) {
468 logger.log(Level.WARNING, String.format(
"Error reading Firefox download artifacts file '%s' (id=%d).",
469 fileName, downloadsFile.getId()), ex);
470 this.addErrorMessage(
471 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
474 }
catch (IOException ex) {
475 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
476 temps, fileName, downloadsFile.getId()), ex);
477 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getDlPre24.errMsg.errAnalyzeFiles",
478 this.getName(), fileName));
481 File dbFile =
new File(temps);
482 if (context.dataSourceIngestIsCancelled()) {
487 List<HashMap<String, Object>> tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
488 logger.log(Level.INFO,
"{0}- Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
489 for (HashMap<String, Object> result : tempList) {
490 String source = result.get(
"source").toString();
492 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
494 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
495 RecentActivityExtracterModuleFactory.getModuleName(),
498 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
499 RecentActivityExtracterModuleFactory.getModuleName(),
500 (Long.valueOf(result.get(
"startTime").toString()))));
502 String target = result.get(
"target").toString();
503 String downloadedFilePath =
"";
504 if (target != null) {
506 downloadedFilePath = URLDecoder.decode(target.replaceAll(
"file:///",
""),
"UTF-8");
507 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
508 RecentActivityExtracterModuleFactory.getModuleName(),
509 downloadedFilePath));
510 long pathID = Util.findID(dataSource, downloadedFilePath);
512 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
513 RecentActivityExtracterModuleFactory.getModuleName(),
516 }
catch (UnsupportedEncodingException ex) {
517 logger.log(Level.SEVERE,
"Error decoding Firefox download URL in " + temps, ex);
522 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
523 RecentActivityExtracterModuleFactory.getModuleName(),
524 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
525 String domain = extractDomain(source);
526 if (domain != null && domain.isEmpty() ==
false) {
527 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
528 RecentActivityExtracterModuleFactory.getModuleName(),
532 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
534 bbartifacts.add(bbart);
539 for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
540 BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
541 downloadSourceArt.addAttributes(createDownloadSourceAttributes(source));
542 bbartifacts.add(downloadSourceArt);
545 }
catch (TskCoreException ex) {
546 logger.log(Level.SEVERE, String.format(
"Error creating download source artifact for file '%s'",
547 downloadedFilePath), ex);
551 this.addErrorMessage(
552 NbBundle.getMessage(
this.getClass(),
"Firefox.getDlPre24.errMsg.errParsingArtifacts",
553 this.getName(), errors));
560 services.fireModuleDataEvent(
new ModuleDataEvent(
561 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
562 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
570 private void getDownloadVersion24() {
571 FileManager fileManager = currentCase.getServices().getFileManager();
572 List<AbstractFile> downloadsFiles;
574 downloadsFiles = fileManager.findFiles(dataSource,
"places.sqlite",
"Firefox");
575 }
catch (TskCoreException ex) {
576 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getDlV24.errMsg.errFetchFiles");
577 logger.log(Level.WARNING, msg);
578 this.addErrorMessage(this.getName() +
": " + msg);
582 if (downloadsFiles.isEmpty()) {
583 logger.log(Level.INFO,
"Didn't find any version-24.0 Firefox download files.");
588 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
590 for (AbstractFile downloadsFile : downloadsFiles) {
591 if (downloadsFile.getSize() == 0) {
594 String fileName = downloadsFile.getName();
595 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName +
"-downloads" + j +
".db";
598 ContentUtils.writeToFile(downloadsFile,
new File(temps), context::dataSourceIngestIsCancelled);
599 }
catch (ReadContentInputStreamException ex) {
600 logger.log(Level.WARNING, String.format(
"Error reading Firefox download artifacts file '%s' (id=%d).",
601 fileName, downloadsFile.getId()), ex);
602 this.addErrorMessage(
603 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
606 }
catch (IOException ex) {
607 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
608 temps, fileName, downloadsFile.getId()), ex);
609 this.addErrorMessage(
610 NbBundle.getMessage(
this.getClass(),
"Firefox.getDlV24.errMsg.errAnalyzeFile", this.getName(),
614 File dbFile =
new File(temps);
615 if (context.dataSourceIngestIsCancelled()) {
620 List<HashMap<String, Object>> tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V24);
622 logger.log(Level.INFO,
"{0} - Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
623 for (HashMap<String, Object> result : tempList) {
624 String url = result.get(
"url").toString();
626 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
628 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
629 RecentActivityExtracterModuleFactory.getModuleName(),
635 String target = result.get(
"target").toString();
636 String downloadedFilePath =
"";
637 if (target != null) {
639 downloadedFilePath = URLDecoder.decode(target.replaceAll(
"file:///",
""),
"UTF-8");
640 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
641 RecentActivityExtracterModuleFactory.getModuleName(),
642 downloadedFilePath));
643 long pathID = Util.findID(dataSource, downloadedFilePath);
645 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
646 RecentActivityExtracterModuleFactory.getModuleName(),
649 }
catch (UnsupportedEncodingException ex) {
650 logger.log(Level.SEVERE,
"Error decoding Firefox download URL in " + temps, ex);
654 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
655 RecentActivityExtracterModuleFactory.getModuleName(),
656 Long.valueOf(result.get(
"lastModified").toString())));
657 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
658 RecentActivityExtracterModuleFactory.getModuleName(),
659 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
660 String domain = extractDomain(url);
661 if (domain != null && domain.isEmpty() ==
false) {
662 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
663 RecentActivityExtracterModuleFactory.getModuleName(), domain));
666 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
668 bbartifacts.add(bbart);
673 for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
674 BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
675 downloadSourceArt.addAttributes(createDownloadSourceAttributes(url));
676 bbartifacts.add(downloadSourceArt);
679 }
catch (TskCoreException ex) {
680 logger.log(Level.SEVERE, String.format(
"Error creating download source artifact for file '%s'",
681 downloadedFilePath), ex);
685 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getDlV24.errMsg.errParsingArtifacts",
686 this.getName(), errors));
693 services.fireModuleDataEvent(
new ModuleDataEvent(
694 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
695 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
702 private void getFormsHistory() {
703 FileManager fileManager = currentCase.getServices().getFileManager();
704 List<AbstractFile> formHistoryFiles;
707 Set<String> excludedFieldNames =
new HashSet<>(Arrays.asList(
713 formHistoryFiles = fileManager.findFiles(dataSource,
"formhistory.sqlite",
"Firefox");
714 }
catch (TskCoreException ex) {
715 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getFormsAutofill.errMsg.errFetchingFiles");
716 logger.log(Level.WARNING, msg);
717 this.addErrorMessage(this.getName() +
": " + msg);
721 if (formHistoryFiles.isEmpty()) {
722 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getFormsAutofill.errMsg.noFilesFound");
723 logger.log(Level.INFO, msg);
728 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
730 for (AbstractFile formHistoryFile : formHistoryFiles) {
731 if (formHistoryFile.getSize() == 0) {
735 String fileName = formHistoryFile.getName();
736 String tempFilePath = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
738 ContentUtils.writeToFile(formHistoryFile,
new File(tempFilePath), context::dataSourceIngestIsCancelled);
739 }
catch (ReadContentInputStreamException ex) {
740 logger.log(Level.WARNING, String.format(
"Error reading Firefox web history artifacts file '%s' (id=%d).",
741 fileName, formHistoryFile.getId()), ex);
742 this.addErrorMessage(
743 NbBundle.getMessage(
this.getClass(),
"Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getName(),
746 }
catch (IOException ex) {
747 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
748 tempFilePath, fileName, formHistoryFile.getId()), ex);
749 this.addErrorMessage(
750 NbBundle.getMessage(
this.getClass(),
"Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getName(),
754 File dbFile =
new File(tempFilePath);
755 if (context.dataSourceIngestIsCancelled()) {
761 boolean isFirefoxV64 = Util.checkColumn(
"timesUsed",
"moz_formhistory", tempFilePath);
762 String formHistoryQuery = (isFirefoxV64) ? FORMHISTORY_QUERY_V64 : FORMHISTORY_QUERY;
764 List<HashMap<String, Object>> tempList = this.dbConnect(tempFilePath, formHistoryQuery);
765 logger.log(Level.INFO,
"{0} - Now getting history from {1} with {2} artifacts identified.",
new Object[]{moduleName, tempFilePath, tempList.size()});
766 for (HashMap<String, Object> result : tempList) {
767 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
769 String fieldName = ((result.get(
"fieldname").toString() != null) ? result.get(
"fieldname").toString() :
"");
771 if (excludedFieldNames.contains(fieldName.toLowerCase())) {
775 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
776 RecentActivityExtracterModuleFactory.getModuleName(),
779 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
780 RecentActivityExtracterModuleFactory.getModuleName(),
781 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
785 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
786 RecentActivityExtracterModuleFactory.getModuleName(),
787 (Long.valueOf(result.get(
"firstUsed").toString()) / 1000000)));
789 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
790 RecentActivityExtracterModuleFactory.getModuleName(),
791 (Long.valueOf(result.get(
"lastUsed").toString()) / 1000000)));
793 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
794 RecentActivityExtracterModuleFactory.getModuleName(),
795 (Integer.valueOf(result.get(
"timesUsed").toString()))));
799 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, formHistoryFile, bbattributes);
801 this.indexArtifact(bbart);
802 bbartifacts.add(bbart);
809 services.fireModuleDataEvent(
new ModuleDataEvent(
810 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
811 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, bbartifacts));
820 private void getAutofillProfiles() {
821 FileManager fileManager = currentCase.getServices().getFileManager();
822 List<AbstractFile> autofillProfilesFiles;
824 autofillProfilesFiles = fileManager.findFiles(dataSource,
"autofill-profiles.json",
"Firefox");
825 }
catch (TskCoreException ex) {
826 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errGettingFiles");
827 logger.log(Level.SEVERE, msg, ex);
828 this.addErrorMessage(this.getName() +
": " + msg);
832 if (autofillProfilesFiles.isEmpty()) {
833 logger.log(Level.INFO,
"Didn't find any Firefox Autofill Profiles files.");
838 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
841 while (j < autofillProfilesFiles.size()) {
842 AbstractFile profileFile = autofillProfilesFiles.get(j++);
843 if (profileFile.getSize() == 0) {
846 String temps = RAImageIngestModule.getRATempPath(currentCase,
"Firefox") + File.separator + profileFile.getName() + j +
".json";
848 ContentUtils.writeToFile(profileFile,
new File(temps), context::dataSourceIngestIsCancelled);
849 }
catch (ReadContentInputStreamException ex) {
850 logger.log(Level.WARNING, String.format(
"Error reading Firefox Autofill profiles artifacts file '%s' (id=%d).",
851 profileFile.getName(), profileFile.getId()), ex);
852 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
853 this.getName(), profileFile.getName()));
855 }
catch (IOException ex) {
856 logger.log(Level.SEVERE, String.format(
"Error writing temp file '%s' for Firefox Autofill profiles file '%s' (id=%d).",
857 temps, profileFile.getName(), profileFile.getId()), ex);
858 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
859 this.getName(), profileFile.getName()));
863 logger.log(Level.INFO,
"{0}- Now getting Bookmarks from {1}",
new Object[]{moduleName, temps});
864 File dbFile =
new File(temps);
865 if (context.dataSourceIngestIsCancelled()) {
870 FileReader tempReader;
872 tempReader =
new FileReader(temps);
873 }
catch (FileNotFoundException ex) {
874 logger.log(Level.SEVERE,
"Error while trying to read the Autofill profiles json file for Firefox.", ex);
875 this.addErrorMessage(
876 NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzeFile", this.getName(),
877 profileFile.getName()));
881 final JsonParser parser =
new JsonParser();
883 JsonObject jsonRootObject;
884 JsonArray jAddressesArray;
887 jsonRootObject = parser.parse(tempReader).getAsJsonObject();
888 jAddressesArray = jsonRootObject.getAsJsonArray(
"addresses");
889 }
catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
890 logger.log(Level.WARNING,
"Error parsing Json for Firefox Autofill profiles.", ex);
891 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile3",
892 this.getName(), profileFile.getName()));
896 for (JsonElement result : jAddressesArray) {
897 JsonObject address = result.getAsJsonObject();
898 if (address == null) {
902 JsonElement nameEl = address.get(
"name");
903 String name = (nameEl != null) ? nameEl.getAsString() :
"";
905 JsonElement emailEl = address.get(
"email");
906 String email = (emailEl != null) ? emailEl.getAsString() :
"";
908 JsonElement telEl = address.get(
"tel");
909 String tel = (telEl != null) ? telEl.getAsString() :
"";
910 JsonElement telCountryCodeEl = address.get(
"tel-country-code");
911 String telCountryCode = (telCountryCodeEl != null) ? telCountryCodeEl.getAsString() :
"";
912 JsonElement telNationalEl = address.get(
"tel-national");
913 String telNational = (telNationalEl != null) ? telNationalEl.getAsString() :
"";
915 String phoneNumber = makeTelNumber(tel, telCountryCode, telNational);
917 JsonElement createdEl = address.get(
"timeCreated");
918 Long datetimeCreated = (createdEl != null) ? createdEl.getAsLong()/1000 : Long.valueOf(0);
919 JsonElement lastusedEl = address.get(
"timeLastUsed");
920 Long datetimeLastUsed = (lastusedEl != null) ? lastusedEl.getAsLong()/1000 : Long.valueOf(0);
921 JsonElement timesUsedEl = address.get(
"timesUsed");
922 Integer timesUsed = (timesUsedEl != null) ? timesUsedEl.getAsShort() : Integer.valueOf(0);
924 JsonElement addressLine1El = address.get(
"address-line1");
925 String addressLine1 = (addressLine1El != null) ? addressLine1El.getAsString() :
"";
926 JsonElement addressLine2El = address.get(
"address-line2");
927 String addressLine2 = (addressLine2El != null) ? addressLine2El.getAsString() :
"";
928 JsonElement addressLine3El = address.get(
"address-line3");
929 String addressLine3 = (addressLine3El != null) ? addressLine3El.getAsString() :
"";
931 JsonElement postalCodeEl = address.get(
"postal-code");
932 String postalCode = (postalCodeEl != null) ? postalCodeEl.getAsString() :
"";
933 JsonElement countryEl = address.get(
"country");
934 String country = (countryEl != null) ? countryEl.getAsString() :
"";
936 String mailingAddress = makeFullAddress(addressLine1, addressLine2, addressLine3, postalCode, country );
939 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
940 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME_PERSON,
941 RecentActivityExtracterModuleFactory.getModuleName(),
944 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
945 RecentActivityExtracterModuleFactory.getModuleName(),
948 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
949 RecentActivityExtracterModuleFactory.getModuleName(),
952 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCATION,
953 RecentActivityExtracterModuleFactory.getModuleName(),
956 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
957 RecentActivityExtracterModuleFactory.getModuleName(),
960 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
961 RecentActivityExtracterModuleFactory.getModuleName(),
964 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
965 RecentActivityExtracterModuleFactory.getModuleName(),
968 BlackboardArtifact bbart = profileFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS);
972 bbart.addAttributes(bbattributes);
973 this.indexArtifact(bbart);
974 bbartifacts.add(bbart);
978 if (email != null && !email.isEmpty()) {
980 Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, email, NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"), profileFile);
981 }
catch (NoCurrentCaseException | TskCoreException ex) {
982 logger.log(Level.SEVERE, String.format(
"Error creating email account instance for '%s' from Firefox profiles file '%s' .",
983 email, profileFile.getName()), ex);
988 if (phoneNumber != null && !phoneNumber.isEmpty()) {
990 Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, phoneNumber, NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"), profileFile);
991 }
catch (NoCurrentCaseException | TskCoreException ex) {
992 logger.log(Level.SEVERE, String.format(
"Error creating phone number account instance for '%s' from Chrome profiles file '%s' .",
993 phoneNumber, profileFile.getName()), ex);
997 }
catch (TskCoreException ex) {
998 logger.log(Level.SEVERE,
"Error while trying to insert Firefox Autofill profile artifact{0}", ex);
999 this.addErrorMessage(
1000 NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile4",
1001 this.getName(), profileFile.getName()));
1007 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
1008 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
1009 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS, bbartifacts));
1020 private String extractDomain(String url) {
1021 if (url == null || url.isEmpty()) {
1025 if (url.toLowerCase().startsWith(PLACE_URL_PREFIX)) {
1032 return NetworkUtils.extractDomain(url);
1045 private String makeTelNumber(String tel, String telCountryCode, String telNational) {
1047 if (tel != null && !tel.isEmpty()) {
1051 if ((telCountryCode != null && !telCountryCode.isEmpty()) &&
1052 (telNational != null && !telNational.isEmpty())) {
1053 return telCountryCode + telNational;
1070 private String makeFullAddress(String addressLine1, String addressLine2, String addressLine3, String postalCode, String country ) {
1071 String fullAddress =
"";
1072 fullAddress = appendAddressField(fullAddress, addressLine1 );
1073 fullAddress = appendAddressField(fullAddress, addressLine2 );
1074 fullAddress = appendAddressField(fullAddress, addressLine3 );
1075 fullAddress = appendAddressField(fullAddress, postalCode );
1076 fullAddress = appendAddressField(fullAddress, country );
1089 private String appendAddressField(String address, String addressfield) {
1091 String updatedAddress = address;
1092 if (addressfield != null && !addressfield.isEmpty()) {
1093 if (!updatedAddress.isEmpty()) {
1094 updatedAddress +=
", ";
1096 updatedAddress += addressfield;
1099 return updatedAddress;