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) {
157 if (context.dataSourceIngestIsCancelled()) {
161 if (historyFile.getSize() == 0) {
165 String fileName = historyFile.getName();
166 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
168 ContentUtils.writeToFile(historyFile,
new File(temps), context::dataSourceIngestIsCancelled);
169 }
catch (ReadContentInputStreamException ex) {
170 logger.log(Level.WARNING, String.format(
"Error reading Firefox web history artifacts file '%s' (id=%d).",
171 fileName, historyFile.getId()), ex);
172 this.addErrorMessage(
173 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
176 }
catch (IOException ex) {
177 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
178 temps, fileName, historyFile.getId()), ex);
179 this.addErrorMessage(
180 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
184 File dbFile =
new File(temps);
185 if (context.dataSourceIngestIsCancelled()) {
189 List<HashMap<String, Object>> tempList = this.dbConnect(temps, HISTORY_QUERY);
190 logger.log(Level.INFO,
"{0} - Now getting history from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
191 for (HashMap<String, Object> result : tempList) {
193 if (context.dataSourceIngestIsCancelled()) {
197 String url = result.get(
"url").toString();
199 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
200 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
201 RecentActivityExtracterModuleFactory.getModuleName(),
202 ((url != null) ? url :
"")));
204 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
205 RecentActivityExtracterModuleFactory.getModuleName(),
206 (Long.valueOf(result.get(
"visit_date").toString()))));
207 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
208 RecentActivityExtracterModuleFactory.getModuleName(),
209 ((result.get(
"ref").toString() != null) ? result.get(
"ref").toString() :
"")));
210 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
211 RecentActivityExtracterModuleFactory.getModuleName(),
212 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
213 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
214 RecentActivityExtracterModuleFactory.getModuleName(),
215 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
216 String domain = extractDomain(url);
217 if (domain != null && domain.isEmpty() ==
false) {
218 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
219 RecentActivityExtracterModuleFactory.getModuleName(), domain));
222 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
224 bbartifacts.add(bbart);
231 services.fireModuleDataEvent(
new ModuleDataEvent(
232 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
233 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, bbartifacts));
239 private void getBookmark() {
241 FileManager fileManager = currentCase.getServices().getFileManager();
242 List<AbstractFile> bookmarkFiles;
244 bookmarkFiles = fileManager.findFiles(dataSource,
"places.sqlite",
"Firefox");
245 }
catch (TskCoreException ex) {
246 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getBookmark.errMsg.errFetchFiles");
247 logger.log(Level.WARNING, msg);
248 this.addErrorMessage(this.getName() +
": " + msg);
252 if (bookmarkFiles.isEmpty()) {
253 logger.log(Level.INFO,
"Didn't find any firefox bookmark files.");
258 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
260 for (AbstractFile bookmarkFile : bookmarkFiles) {
261 if (bookmarkFile.getSize() == 0) {
264 String fileName = bookmarkFile.getName();
265 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
267 ContentUtils.writeToFile(bookmarkFile,
new File(temps), context::dataSourceIngestIsCancelled);
268 }
catch (ReadContentInputStreamException ex) {
269 logger.log(Level.WARNING, String.format(
"Error reading Firefox bookmark artifacts file '%s' (id=%d).",
270 fileName, bookmarkFile.getId()), ex);
271 this.addErrorMessage(
272 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
275 }
catch (IOException ex) {
276 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox bookmark artifacts file '%s' (id=%d).",
277 temps, fileName, bookmarkFile.getId()), ex);
278 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getBookmark.errMsg.errAnalyzeFile",
279 this.getName(), fileName));
282 File dbFile =
new File(temps);
283 if (context.dataSourceIngestIsCancelled()) {
287 List<HashMap<String, Object>> tempList = this.dbConnect(temps, BOOKMARK_QUERY);
288 logger.log(Level.INFO,
"{0} - Now getting bookmarks from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
289 for (HashMap<String, Object> result : tempList) {
291 if (context.dataSourceIngestIsCancelled()) {
295 String url = result.get(
"url").toString();
297 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
298 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
299 RecentActivityExtracterModuleFactory.getModuleName(),
300 ((url != null) ? url :
"")));
301 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
302 RecentActivityExtracterModuleFactory.getModuleName(),
303 ((result.get(
"title").toString() != null) ? result.get(
"title").toString() :
"")));
304 if (Long.valueOf(result.get(
"dateAdded").toString()) > 0) {
305 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
306 RecentActivityExtracterModuleFactory.getModuleName(),
307 (Long.valueOf(result.get(
"dateAdded").toString()))));
309 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
310 RecentActivityExtracterModuleFactory.getModuleName(),
311 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
312 String domain = extractDomain(url);
313 if (domain != null && domain.isEmpty() ==
false) {
314 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
315 RecentActivityExtracterModuleFactory.getModuleName(), domain));
318 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes);
320 bbartifacts.add(bbart);
327 services.fireModuleDataEvent(
new ModuleDataEvent(
328 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
329 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bbartifacts));
335 private void getCookie() {
336 FileManager fileManager = currentCase.getServices().getFileManager();
337 List<AbstractFile> cookiesFiles;
339 cookiesFiles = fileManager.findFiles(dataSource,
"cookies.sqlite",
"Firefox");
340 }
catch (TskCoreException ex) {
341 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getCookie.errMsg.errFetchFile");
342 logger.log(Level.WARNING, msg);
343 this.addErrorMessage(this.getName() +
": " + msg);
347 if (cookiesFiles.isEmpty()) {
348 logger.log(Level.INFO,
"Didn't find any Firefox cookie files.");
353 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
355 for (AbstractFile cookiesFile : cookiesFiles) {
356 if (cookiesFile.getSize() == 0) {
359 String fileName = cookiesFile.getName();
360 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
362 ContentUtils.writeToFile(cookiesFile,
new File(temps), context::dataSourceIngestIsCancelled);
363 }
catch (ReadContentInputStreamException ex) {
364 logger.log(Level.WARNING, String.format(
"Error reading Firefox cookie artifacts file '%s' (id=%d).",
365 fileName, cookiesFile.getId()), ex);
366 this.addErrorMessage(
367 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
370 }
catch (IOException ex) {
371 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox cookie artifacts file '%s' (id=%d).",
372 temps, fileName, cookiesFile.getId()), ex);
373 this.addErrorMessage(
374 NbBundle.getMessage(
this.getClass(),
"Firefox.getCookie.errMsg.errAnalyzeFile", this.getName(),
378 File dbFile =
new File(temps);
379 if (context.dataSourceIngestIsCancelled()) {
383 boolean checkColumn = Util.checkColumn(
"creationTime",
"moz_cookies", temps);
386 query = COOKIE_QUERY;
388 query = COOKIE_QUERY_V3;
391 List<HashMap<String, Object>> tempList = this.dbConnect(temps, query);
392 logger.log(Level.INFO,
"{0} - Now getting cookies from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
393 for (HashMap<String, Object> result : tempList) {
395 if (context.dataSourceIngestIsCancelled()) {
399 String host = result.get(
"host").toString();
401 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
402 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
403 RecentActivityExtracterModuleFactory.getModuleName(),
404 ((host != null) ? host :
"")));
405 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
406 RecentActivityExtracterModuleFactory.getModuleName(),
407 (Long.valueOf(result.get(
"lastAccessed").toString()))));
408 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
409 RecentActivityExtracterModuleFactory.getModuleName(),
410 ((result.get(
"name").toString() != null) ? result.get(
"name").toString() :
"")));
411 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
412 RecentActivityExtracterModuleFactory.getModuleName(),
413 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
414 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
415 RecentActivityExtracterModuleFactory.getModuleName(),
416 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
418 if (checkColumn ==
true) {
419 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
420 RecentActivityExtracterModuleFactory.getModuleName(),
421 (Long.valueOf(result.get(
"creationTime").toString()))));
423 String domain = extractDomain(host);
424 if (domain != null && domain.isEmpty() ==
false) {
425 domain = domain.replaceFirst(
"^\\.+(?!$)",
"");
426 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
427 RecentActivityExtracterModuleFactory.getModuleName(), domain));
430 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
432 bbartifacts.add(bbart);
439 services.fireModuleDataEvent(
new ModuleDataEvent(
440 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
441 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, bbartifacts));
447 private void getDownload() {
448 getDownloadPreVersion24();
449 getDownloadVersion24();
457 private void getDownloadPreVersion24() {
459 FileManager fileManager = currentCase.getServices().getFileManager();
460 List<AbstractFile> downloadsFiles;
462 downloadsFiles = fileManager.findFiles(dataSource,
"downloads.sqlite",
"Firefox");
463 }
catch (TskCoreException ex) {
464 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getDlPre24.errMsg.errFetchFiles");
465 logger.log(Level.WARNING, msg);
466 this.addErrorMessage(this.getName() +
": " + msg);
470 if (downloadsFiles.isEmpty()) {
471 logger.log(Level.INFO,
"Didn't find any pre-version-24.0 Firefox download files.");
476 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
478 for (AbstractFile downloadsFile : downloadsFiles) {
479 if (downloadsFile.getSize() == 0) {
482 String fileName = downloadsFile.getName();
483 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
486 ContentUtils.writeToFile(downloadsFile,
new File(temps), context::dataSourceIngestIsCancelled);
487 }
catch (ReadContentInputStreamException ex) {
488 logger.log(Level.WARNING, String.format(
"Error reading Firefox download artifacts file '%s' (id=%d).",
489 fileName, downloadsFile.getId()), ex);
490 this.addErrorMessage(
491 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
494 }
catch (IOException ex) {
495 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
496 temps, fileName, downloadsFile.getId()), ex);
497 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getDlPre24.errMsg.errAnalyzeFiles",
498 this.getName(), fileName));
501 File dbFile =
new File(temps);
502 if (context.dataSourceIngestIsCancelled()) {
507 List<HashMap<String, Object>> tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
508 logger.log(Level.INFO,
"{0}- Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
509 for (HashMap<String, Object> result : tempList) {
511 if (context.dataSourceIngestIsCancelled()) {
515 String source = result.get(
"source").toString();
517 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
519 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
520 RecentActivityExtracterModuleFactory.getModuleName(),
523 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
524 RecentActivityExtracterModuleFactory.getModuleName(),
525 (Long.valueOf(result.get(
"startTime").toString()))));
527 String target = result.get(
"target").toString();
528 String downloadedFilePath =
"";
529 if (target != null) {
531 downloadedFilePath = URLDecoder.decode(target.replaceAll(
"file:///",
""),
"UTF-8");
532 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
533 RecentActivityExtracterModuleFactory.getModuleName(),
534 downloadedFilePath));
535 long pathID = Util.findID(dataSource, downloadedFilePath);
537 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
538 RecentActivityExtracterModuleFactory.getModuleName(),
541 }
catch (UnsupportedEncodingException ex) {
542 logger.log(Level.SEVERE,
"Error decoding Firefox download URL in " + temps, ex);
547 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
548 RecentActivityExtracterModuleFactory.getModuleName(),
549 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
550 String domain = extractDomain(source);
551 if (domain != null && domain.isEmpty() ==
false) {
552 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
553 RecentActivityExtracterModuleFactory.getModuleName(),
557 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
559 bbartifacts.add(bbart);
564 for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
565 BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
566 downloadSourceArt.addAttributes(createDownloadSourceAttributes(source));
567 bbartifacts.add(downloadSourceArt);
570 }
catch (TskCoreException ex) {
571 logger.log(Level.SEVERE, String.format(
"Error creating download source artifact for file '%s'",
572 downloadedFilePath), ex);
576 this.addErrorMessage(
577 NbBundle.getMessage(
this.getClass(),
"Firefox.getDlPre24.errMsg.errParsingArtifacts",
578 this.getName(), errors));
585 services.fireModuleDataEvent(
new ModuleDataEvent(
586 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
587 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
595 private void getDownloadVersion24() {
596 FileManager fileManager = currentCase.getServices().getFileManager();
597 List<AbstractFile> downloadsFiles;
599 downloadsFiles = fileManager.findFiles(dataSource,
"places.sqlite",
"Firefox");
600 }
catch (TskCoreException ex) {
601 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getDlV24.errMsg.errFetchFiles");
602 logger.log(Level.WARNING, msg);
603 this.addErrorMessage(this.getName() +
": " + msg);
607 if (downloadsFiles.isEmpty()) {
608 logger.log(Level.INFO,
"Didn't find any version-24.0 Firefox download files.");
613 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
615 for (AbstractFile downloadsFile : downloadsFiles) {
616 if (downloadsFile.getSize() == 0) {
619 String fileName = downloadsFile.getName();
620 String temps = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName +
"-downloads" + j +
".db";
623 ContentUtils.writeToFile(downloadsFile,
new File(temps), context::dataSourceIngestIsCancelled);
624 }
catch (ReadContentInputStreamException ex) {
625 logger.log(Level.WARNING, String.format(
"Error reading Firefox download artifacts file '%s' (id=%d).",
626 fileName, downloadsFile.getId()), ex);
627 this.addErrorMessage(
628 NbBundle.getMessage(
this.getClass(),
"Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
631 }
catch (IOException ex) {
632 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
633 temps, fileName, downloadsFile.getId()), ex);
634 this.addErrorMessage(
635 NbBundle.getMessage(
this.getClass(),
"Firefox.getDlV24.errMsg.errAnalyzeFile", this.getName(),
639 File dbFile =
new File(temps);
640 if (context.dataSourceIngestIsCancelled()) {
645 List<HashMap<String, Object>> tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V24);
647 logger.log(Level.INFO,
"{0} - Now getting downloads from {1} with {2} artifacts identified.",
new Object[]{moduleName, temps, tempList.size()});
648 for (HashMap<String, Object> result : tempList) {
650 if (context.dataSourceIngestIsCancelled()) {
654 String url = result.get(
"url").toString();
656 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
658 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
659 RecentActivityExtracterModuleFactory.getModuleName(),
665 String target = result.get(
"target").toString();
666 String downloadedFilePath =
"";
667 if (target != null) {
669 downloadedFilePath = URLDecoder.decode(target.replaceAll(
"file:///",
""),
"UTF-8");
670 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
671 RecentActivityExtracterModuleFactory.getModuleName(),
672 downloadedFilePath));
673 long pathID = Util.findID(dataSource, downloadedFilePath);
675 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
676 RecentActivityExtracterModuleFactory.getModuleName(),
679 }
catch (UnsupportedEncodingException ex) {
680 logger.log(Level.SEVERE,
"Error decoding Firefox download URL in " + temps, ex);
684 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
685 RecentActivityExtracterModuleFactory.getModuleName(),
686 Long.valueOf(result.get(
"lastModified").toString())));
687 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
688 RecentActivityExtracterModuleFactory.getModuleName(),
689 NbBundle.getMessage(this.getClass(),
"Firefox.moduleName")));
690 String domain = extractDomain(url);
691 if (domain != null && domain.isEmpty() ==
false) {
692 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
693 RecentActivityExtracterModuleFactory.getModuleName(), domain));
696 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
698 bbartifacts.add(bbart);
703 for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(downloadedFilePath), FilenameUtils.getPath(downloadedFilePath))) {
704 BlackboardArtifact downloadSourceArt = downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
705 downloadSourceArt.addAttributes(createDownloadSourceAttributes(url));
706 bbartifacts.add(downloadSourceArt);
709 }
catch (TskCoreException ex) {
710 logger.log(Level.SEVERE, String.format(
"Error creating download source artifact for file '%s'",
711 downloadedFilePath), ex);
715 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getDlV24.errMsg.errParsingArtifacts",
716 this.getName(), errors));
723 services.fireModuleDataEvent(
new ModuleDataEvent(
724 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
725 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
732 private void getFormsHistory() {
733 FileManager fileManager = currentCase.getServices().getFileManager();
734 List<AbstractFile> formHistoryFiles;
737 Set<String> excludedFieldNames =
new HashSet<>(Arrays.asList(
743 formHistoryFiles = fileManager.findFiles(dataSource,
"formhistory.sqlite",
"Firefox");
744 }
catch (TskCoreException ex) {
745 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getFormsAutofill.errMsg.errFetchingFiles");
746 logger.log(Level.WARNING, msg);
747 this.addErrorMessage(this.getName() +
": " + msg);
751 if (formHistoryFiles.isEmpty()) {
752 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getFormsAutofill.errMsg.noFilesFound");
753 logger.log(Level.INFO, msg);
758 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
760 for (AbstractFile formHistoryFile : formHistoryFiles) {
761 if (formHistoryFile.getSize() == 0) {
765 String fileName = formHistoryFile.getName();
766 String tempFilePath = RAImageIngestModule.getRATempPath(currentCase,
"firefox") + File.separator + fileName + j +
".db";
768 ContentUtils.writeToFile(formHistoryFile,
new File(tempFilePath), context::dataSourceIngestIsCancelled);
769 }
catch (ReadContentInputStreamException ex) {
770 logger.log(Level.WARNING, String.format(
"Error reading Firefox web history artifacts file '%s' (id=%d).",
771 fileName, formHistoryFile.getId()), ex);
772 this.addErrorMessage(
773 NbBundle.getMessage(
this.getClass(),
"Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getName(),
776 }
catch (IOException ex) {
777 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
778 tempFilePath, fileName, formHistoryFile.getId()), ex);
779 this.addErrorMessage(
780 NbBundle.getMessage(
this.getClass(),
"Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getName(),
784 File dbFile =
new File(tempFilePath);
785 if (context.dataSourceIngestIsCancelled()) {
791 boolean isFirefoxV64 = Util.checkColumn(
"timesUsed",
"moz_formhistory", tempFilePath);
792 String formHistoryQuery = (isFirefoxV64) ? FORMHISTORY_QUERY_V64 : FORMHISTORY_QUERY;
794 List<HashMap<String, Object>> tempList = this.dbConnect(tempFilePath, formHistoryQuery);
795 logger.log(Level.INFO,
"{0} - Now getting history from {1} with {2} artifacts identified.",
new Object[]{moduleName, tempFilePath, tempList.size()});
796 for (HashMap<String, Object> result : tempList) {
798 if (context.dataSourceIngestIsCancelled()) {
802 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
804 String fieldName = ((result.get(
"fieldname").toString() != null) ? result.get(
"fieldname").toString() :
"");
806 if (excludedFieldNames.contains(fieldName.toLowerCase())) {
810 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
811 RecentActivityExtracterModuleFactory.getModuleName(),
814 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
815 RecentActivityExtracterModuleFactory.getModuleName(),
816 ((result.get(
"value").toString() != null) ? result.get(
"value").toString() :
"")));
820 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
821 RecentActivityExtracterModuleFactory.getModuleName(),
822 (Long.valueOf(result.get(
"firstUsed").toString()) / 1000000)));
824 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
825 RecentActivityExtracterModuleFactory.getModuleName(),
826 (Long.valueOf(result.get(
"lastUsed").toString()) / 1000000)));
828 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
829 RecentActivityExtracterModuleFactory.getModuleName(),
830 (Integer.valueOf(result.get(
"timesUsed").toString()))));
834 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, formHistoryFile, bbattributes);
836 this.indexArtifact(bbart);
837 bbartifacts.add(bbart);
844 services.fireModuleDataEvent(
new ModuleDataEvent(
845 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
846 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, bbartifacts));
855 private void getAutofillProfiles() {
856 FileManager fileManager = currentCase.getServices().getFileManager();
857 List<AbstractFile> autofillProfilesFiles;
859 autofillProfilesFiles = fileManager.findFiles(dataSource,
"autofill-profiles.json",
"Firefox");
860 }
catch (TskCoreException ex) {
861 String msg = NbBundle.getMessage(this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errGettingFiles");
862 logger.log(Level.SEVERE, msg, ex);
863 this.addErrorMessage(this.getName() +
": " + msg);
867 if (autofillProfilesFiles.isEmpty()) {
868 logger.log(Level.INFO,
"Didn't find any Firefox Autofill Profiles files.");
873 Collection<BlackboardArtifact> bbartifacts =
new ArrayList<>();
876 while (j < autofillProfilesFiles.size()) {
877 AbstractFile profileFile = autofillProfilesFiles.get(j++);
878 if (profileFile.getSize() == 0) {
881 String temps = RAImageIngestModule.getRATempPath(currentCase,
"Firefox") + File.separator + profileFile.getName() + j +
".json";
883 ContentUtils.writeToFile(profileFile,
new File(temps), context::dataSourceIngestIsCancelled);
884 }
catch (ReadContentInputStreamException ex) {
885 logger.log(Level.WARNING, String.format(
"Error reading Firefox Autofill profiles artifacts file '%s' (id=%d).",
886 profileFile.getName(), profileFile.getId()), ex);
887 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
888 this.getName(), profileFile.getName()));
890 }
catch (IOException ex) {
891 logger.log(Level.SEVERE, String.format(
"Error writing temp file '%s' for Firefox Autofill profiles file '%s' (id=%d).",
892 temps, profileFile.getName(), profileFile.getId()), ex);
893 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
894 this.getName(), profileFile.getName()));
898 logger.log(Level.INFO,
"{0}- Now getting Bookmarks from {1}",
new Object[]{moduleName, temps});
899 File dbFile =
new File(temps);
900 if (context.dataSourceIngestIsCancelled()) {
905 FileReader tempReader;
907 tempReader =
new FileReader(temps);
908 }
catch (FileNotFoundException ex) {
909 logger.log(Level.SEVERE,
"Error while trying to read the Autofill profiles json file for Firefox.", ex);
910 this.addErrorMessage(
911 NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzeFile", this.getName(),
912 profileFile.getName()));
916 final JsonParser parser =
new JsonParser();
918 JsonObject jsonRootObject;
919 JsonArray jAddressesArray;
922 jsonRootObject = parser.parse(tempReader).getAsJsonObject();
923 jAddressesArray = jsonRootObject.getAsJsonArray(
"addresses");
924 }
catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
925 logger.log(Level.WARNING,
"Error parsing Json for Firefox Autofill profiles.", ex);
926 this.addErrorMessage(NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile3",
927 this.getName(), profileFile.getName()));
931 for (JsonElement result : jAddressesArray) {
932 JsonObject address = result.getAsJsonObject();
933 if (address == null) {
937 JsonElement nameEl = address.get(
"name");
938 String name = (nameEl != null) ? nameEl.getAsString() :
"";
940 JsonElement emailEl = address.get(
"email");
941 String email = (emailEl != null) ? emailEl.getAsString() :
"";
943 JsonElement telEl = address.get(
"tel");
944 String tel = (telEl != null) ? telEl.getAsString() :
"";
945 JsonElement telCountryCodeEl = address.get(
"tel-country-code");
946 String telCountryCode = (telCountryCodeEl != null) ? telCountryCodeEl.getAsString() :
"";
947 JsonElement telNationalEl = address.get(
"tel-national");
948 String telNational = (telNationalEl != null) ? telNationalEl.getAsString() :
"";
950 String phoneNumber = makeTelNumber(tel, telCountryCode, telNational);
952 JsonElement createdEl = address.get(
"timeCreated");
953 Long datetimeCreated = (createdEl != null) ? createdEl.getAsLong()/1000 : Long.valueOf(0);
954 JsonElement lastusedEl = address.get(
"timeLastUsed");
955 Long datetimeLastUsed = (lastusedEl != null) ? lastusedEl.getAsLong()/1000 : Long.valueOf(0);
956 JsonElement timesUsedEl = address.get(
"timesUsed");
957 Integer timesUsed = (timesUsedEl != null) ? timesUsedEl.getAsShort() : Integer.valueOf(0);
959 JsonElement addressLine1El = address.get(
"address-line1");
960 String addressLine1 = (addressLine1El != null) ? addressLine1El.getAsString() :
"";
961 JsonElement addressLine2El = address.get(
"address-line2");
962 String addressLine2 = (addressLine2El != null) ? addressLine2El.getAsString() :
"";
963 JsonElement addressLine3El = address.get(
"address-line3");
964 String addressLine3 = (addressLine3El != null) ? addressLine3El.getAsString() :
"";
966 JsonElement postalCodeEl = address.get(
"postal-code");
967 String postalCode = (postalCodeEl != null) ? postalCodeEl.getAsString() :
"";
968 JsonElement countryEl = address.get(
"country");
969 String country = (countryEl != null) ? countryEl.getAsString() :
"";
971 String mailingAddress = makeFullAddress(addressLine1, addressLine2, addressLine3, postalCode, country );
974 Collection<BlackboardAttribute> bbattributes =
new ArrayList<>();
975 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME_PERSON,
976 RecentActivityExtracterModuleFactory.getModuleName(),
979 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
980 RecentActivityExtracterModuleFactory.getModuleName(),
983 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
984 RecentActivityExtracterModuleFactory.getModuleName(),
987 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCATION,
988 RecentActivityExtracterModuleFactory.getModuleName(),
991 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
992 RecentActivityExtracterModuleFactory.getModuleName(),
995 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
996 RecentActivityExtracterModuleFactory.getModuleName(),
999 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
1000 RecentActivityExtracterModuleFactory.getModuleName(),
1003 BlackboardArtifact bbart = profileFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS);
1006 if (bbart != null) {
1007 bbart.addAttributes(bbattributes);
1008 this.indexArtifact(bbart);
1009 bbartifacts.add(bbart);
1013 if (email != null && !email.isEmpty()) {
1015 Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, email, NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"), profileFile);
1016 }
catch (NoCurrentCaseException | TskCoreException ex) {
1017 logger.log(Level.SEVERE, String.format(
"Error creating email account instance for '%s' from Firefox profiles file '%s' .",
1018 email, profileFile.getName()), ex);
1023 if (phoneNumber != null && !phoneNumber.isEmpty()) {
1025 Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, phoneNumber, NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"), profileFile);
1026 }
catch (NoCurrentCaseException | TskCoreException ex) {
1027 logger.log(Level.SEVERE, String.format(
"Error creating phone number account instance for '%s' from Chrome profiles file '%s' .",
1028 phoneNumber, profileFile.getName()), ex);
1032 }
catch (TskCoreException ex) {
1033 logger.log(Level.SEVERE,
"Error while trying to insert Firefox Autofill profile artifact{0}", ex);
1034 this.addErrorMessage(
1035 NbBundle.getMessage(
this.getClass(),
"Firefox.getAutofillProfiles.errMsg.errAnalyzingFile4",
1036 this.getName(), profileFile.getName()));
1042 IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
1043 NbBundle.getMessage(
this.getClass(),
"Firefox.parentModuleName"),
1044 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS, bbartifacts));
1055 private String extractDomain(String url) {
1056 if (url == null || url.isEmpty()) {
1060 if (url.toLowerCase().startsWith(PLACE_URL_PREFIX)) {
1067 return NetworkUtils.extractDomain(url);
1080 private String makeTelNumber(String tel, String telCountryCode, String telNational) {
1082 if (tel != null && !tel.isEmpty()) {
1086 if ((telCountryCode != null && !telCountryCode.isEmpty()) &&
1087 (telNational != null && !telNational.isEmpty())) {
1088 return telCountryCode + telNational;
1105 private String makeFullAddress(String addressLine1, String addressLine2, String addressLine3, String postalCode, String country ) {
1106 String fullAddress =
"";
1107 fullAddress = appendAddressField(fullAddress, addressLine1 );
1108 fullAddress = appendAddressField(fullAddress, addressLine2 );
1109 fullAddress = appendAddressField(fullAddress, addressLine3 );
1110 fullAddress = appendAddressField(fullAddress, postalCode );
1111 fullAddress = appendAddressField(fullAddress, country );
1124 private String appendAddressField(String address, String addressfield) {
1126 String updatedAddress = address;
1127 if (addressfield != null && !addressfield.isEmpty()) {
1128 if (!updatedAddress.isEmpty()) {
1129 updatedAddress +=
", ";
1131 updatedAddress += addressfield;
1134 return updatedAddress;