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;
 
   31 import org.openide.util.NbBundle;
 
   34 import java.util.logging.Level;
 
   37 import java.io.FileNotFoundException;
 
   38 import java.io.FileReader;
 
   39 import java.io.IOException;
 
   40 import org.apache.commons.io.FilenameUtils;
 
   41 import org.openide.util.NbBundle.Messages;
 
   53 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
 
   55 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
 
   57 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
 
   64 class Chrome 
extends Extract {
 
   66     private static final String HISTORY_QUERY = 
"SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, "  
   67             + 
"last_visit_time, urls.hidden, visits.visit_time, (SELECT urls.url FROM urls WHERE urls.id=visits.url) AS from_visit, visits.transition FROM urls, visits WHERE urls.id = visits.url"; 
 
   68     private static final String COOKIE_QUERY = 
"SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies"; 
 
   69     private static final String DOWNLOAD_QUERY = 
"SELECT full_path, url, start_time, received_bytes FROM downloads"; 
 
   70     private static final String DOWNLOAD_QUERY_V30 = 
"SELECT current_path AS full_path, url, start_time, received_bytes FROM downloads, downloads_url_chains WHERE downloads.id=downloads_url_chains.id"; 
 
   71     private static final String LOGIN_QUERY = 
"SELECT origin_url, username_value, date_created, signon_realm from logins"; 
 
   72     private static final String AUTOFILL_QUERY = 
"SELECT name, value, count, date_created " + 
 
   73                                                     " FROM autofill, autofill_dates " +
 
   74                                                     " WHERE autofill.pair_id = autofill_dates.pair_id" 
   76     private static final String AUTOFILL_QUERY_V8X = 
"SELECT name, value, count, date_created, date_last_used from autofill"; 
 
   77     private static final String WEBFORM_ADDRESS_QUERY = 
"SELECT first_name, middle_name, last_name, address_line_1, address_line_2, city, state, zipcode, country_code, number, email, date_modified " +
 
   78                                                         " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
 
   79                                                         " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
 
   81     private static final String WEBFORM_ADDRESS_QUERY_V8X = 
"SELECT first_name, middle_name, last_name, full_name, street_address, city, state, zipcode, country_code, number, email, date_modified, use_date, use_count" +
 
   82                                                             " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
 
   83                                                             " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
 
   84     private final Logger logger = Logger.getLogger(this.getClass().getName());
 
   85     private Content dataSource;
 
   86     private IngestJobContext context;
 
   89         "Progress_Message_Chrome_History=Chrome History",
 
   90         "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks",
 
   91         "Progress_Message_Chrome_Cookies=Chrome Cookies",
 
   92         "Progress_Message_Chrome_Downloads=Chrome Downloads",
 
   93         "Progress_Message_Chrome_FormHistory=Chrome Form History",
 
   94         "Progress_Message_Chrome_AutoFill=Chrome Auto Fill",
 
   95         "Progress_Message_Chrome_Logins=Chrome Logins",
 
   96         "Progress_Message_Chrome_Cache=Chrome Cache",
 
  100         moduleName = NbBundle.getMessage(Chrome.class, 
"Chrome.moduleName");
 
  104     public void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
 
  105         this.dataSource = dataSource;
 
  106         this.context = context;
 
  109         progressBar.progress(Bundle.Progress_Message_Chrome_History());
 
  112         progressBar.progress(Bundle.Progress_Message_Chrome_Bookmarks());
 
  115         progressBar.progress(Bundle.Progress_Message_Chrome_Cookies());
 
  118         progressBar.progress(Bundle.Progress_Message_Chrome_Logins());
 
  121         progressBar.progress(Bundle.Progress_Message_Chrome_AutoFill());
 
  124         progressBar.progress(Bundle.Progress_Message_Chrome_Downloads());
 
  127         progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
 
  128         ChromeCacheExtractor chromeCacheExtractor = 
new ChromeCacheExtractor(dataSource, context, progressBar);
 
  129         chromeCacheExtractor.getCaches();
 
  135     private void getHistory() {
 
  136         FileManager fileManager = currentCase.getServices().getFileManager();
 
  137         List<AbstractFile> historyFiles;
 
  139             historyFiles = fileManager.findFiles(dataSource, 
"History", 
"Chrome"); 
 
  140         } 
catch (TskCoreException ex) {
 
  141             String msg = NbBundle.getMessage(this.getClass(), 
"Chrome.getHistory.errMsg.errGettingFiles");
 
  142             logger.log(Level.SEVERE, msg, ex);
 
  143             this.addErrorMessage(this.getName() + 
": " + msg);
 
  148         List<AbstractFile> allocatedHistoryFiles = 
new ArrayList<>();
 
  149         for (AbstractFile historyFile : historyFiles) {
 
  150             if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
 
  151                 allocatedHistoryFiles.add(historyFile);
 
  156         if (allocatedHistoryFiles.isEmpty()) {
 
  157             String msg = NbBundle.getMessage(this.getClass(), 
"Chrome.getHistory.errMsg.couldntFindAnyFiles");
 
  158             logger.log(Level.INFO, msg);
 
  163         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  165         while (j < historyFiles.size()) {
 
  166             String temps = RAImageIngestModule.getRATempPath(currentCase, 
"chrome") + File.separator + historyFiles.get(j).getName() + j + 
".db"; 
 
  167             final AbstractFile historyFile = historyFiles.get(j++);
 
  168             if (historyFile.getSize() == 0) {
 
  172                 ContentUtils.writeToFile(historyFile, 
new File(temps), context::dataSourceIngestIsCancelled);
 
  173             } 
catch (ReadContentInputStreamException ex) {
 
  174                 logger.log(Level.WARNING, String.format(
"Error reading Chrome web history artifacts file '%s' (id=%d).",
 
  175                         historyFile.getName(), historyFile.getId()), ex); 
 
  176                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getHistory.errMsg.errAnalyzingFile",
 
  177                         this.getName(), historyFile.getName()));
 
  179             } 
catch (IOException ex) {
 
  180                 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
 
  181                         temps, historyFile.getName(), historyFile.getId()), ex); 
 
  182                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getHistory.errMsg.errAnalyzingFile",
 
  183                         this.getName(), historyFile.getName()));
 
  186             File dbFile = 
new File(temps);
 
  187             if (context.dataSourceIngestIsCancelled()) {
 
  191             List<HashMap<String, Object>> tempList;
 
  192             tempList = this.dbConnect(temps, HISTORY_QUERY);
 
  193             logger.log(Level.INFO, 
"{0}- Now getting history from {1} with {2}artifacts identified.", 
new Object[]{moduleName, temps, tempList.size()}); 
 
  194             for (HashMap<String, Object> result : tempList) {
 
  195                 Collection<BlackboardAttribute> bbattributes = 
new ArrayList<BlackboardAttribute>();
 
  196                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
 
  197                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  198                         ((result.get(
"url").toString() != null) ? result.get(
"url").toString() : 
""))); 
 
  199                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
 
  200                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  201                         (Long.valueOf(result.get(
"last_visit_time").toString()) / 1000000) - Long.valueOf(
"11644473600"))); 
 
  202                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
 
  203                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  204                         ((result.get(
"from_visit").toString() != null) ? result.get(
"from_visit").toString() : 
""))); 
 
  205                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
 
  206                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  207                         ((result.get(
"title").toString() != null) ? result.get(
"title").toString() : 
""))); 
 
  208                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
 
  209                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  210                         NbBundle.getMessage(this.getClass(), 
"Chrome.moduleName")));
 
  211                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
 
  212                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  213                         (NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() : 
"")))); 
 
  215                 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
 
  217                     bbartifacts.add(bbart);
 
  223         IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
 
  224                 NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"),
 
  225                 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, bbartifacts));
 
  231     private void getBookmark() {
 
  232         FileManager fileManager = currentCase.getServices().getFileManager();
 
  233         List<AbstractFile> bookmarkFiles;
 
  235             bookmarkFiles = fileManager.findFiles(dataSource, 
"Bookmarks", 
"Chrome"); 
 
  236         } 
catch (TskCoreException ex) {
 
  237             String msg = NbBundle.getMessage(this.getClass(), 
"Chrome.getBookmark.errMsg.errGettingFiles");
 
  238             logger.log(Level.SEVERE, msg, ex);
 
  239             this.addErrorMessage(this.getName() + 
": " + msg);
 
  243         if (bookmarkFiles.isEmpty()) {
 
  244             logger.log(Level.INFO, 
"Didn't find any Chrome bookmark files."); 
 
  249         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  252         while (j < bookmarkFiles.size()) {
 
  253             AbstractFile bookmarkFile = bookmarkFiles.get(j++);
 
  254             if (bookmarkFile.getSize() == 0) {
 
  257             String temps = RAImageIngestModule.getRATempPath(currentCase, 
"chrome") + File.separator + bookmarkFile.getName() + j + 
".db"; 
 
  259                 ContentUtils.writeToFile(bookmarkFile, 
new File(temps), context::dataSourceIngestIsCancelled);
 
  260             } 
catch (ReadContentInputStreamException ex) {
 
  261                 logger.log(Level.WARNING, String.format(
"Error reading Chrome bookmark artifacts file '%s' (id=%d).",
 
  262                         bookmarkFile.getName(), bookmarkFile.getId()), ex); 
 
  263                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getBookmark.errMsg.errAnalyzingFile",
 
  264                         this.getName(), bookmarkFile.getName()));
 
  266             } 
catch (IOException ex) {
 
  267                 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
 
  268                         temps, bookmarkFile.getName(), bookmarkFile.getId()), ex); 
 
  269                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getBookmark.errMsg.errAnalyzingFile",
 
  270                         this.getName(), bookmarkFile.getName()));
 
  274             logger.log(Level.INFO, 
"{0}- Now getting Bookmarks from {1}", 
new Object[]{moduleName, temps}); 
 
  275             File dbFile = 
new File(temps);
 
  276             if (context.dataSourceIngestIsCancelled()) {
 
  281             FileReader tempReader;
 
  283                 tempReader = 
new FileReader(temps);
 
  284             } 
catch (FileNotFoundException ex) {
 
  285                 logger.log(Level.SEVERE, 
"Error while trying to read into the Bookmarks for Chrome.", ex); 
 
  286                 this.addErrorMessage(
 
  287                         NbBundle.getMessage(
this.getClass(), 
"Chrome.getBookmark.errMsg.errAnalyzeFile", this.getName(),
 
  288                                 bookmarkFile.getName()));
 
  292             final JsonParser parser = 
new JsonParser();
 
  293             JsonElement jsonElement;
 
  294             JsonObject jElement, jRoot, jBookmark;
 
  295             JsonArray jBookmarkArray;
 
  298                 jsonElement = parser.parse(tempReader);
 
  299                 jElement = jsonElement.getAsJsonObject();
 
  300                 jRoot = jElement.get(
"roots").getAsJsonObject(); 
 
  301                 jBookmark = jRoot.get(
"bookmark_bar").getAsJsonObject(); 
 
  302                 jBookmarkArray = jBookmark.getAsJsonArray(
"children"); 
 
  303             } 
catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
 
  304                 logger.log(Level.WARNING, 
"Error parsing Json from Chrome Bookmark.", ex); 
 
  305                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getBookmark.errMsg.errAnalyzingFile3",
 
  306                         this.getName(), bookmarkFile.getName()));
 
  310             for (JsonElement result : jBookmarkArray) {
 
  311                 JsonObject address = result.getAsJsonObject();
 
  312                 if (address == null) {
 
  315                 JsonElement urlEl = address.get(
"url"); 
 
  318                     url = urlEl.getAsString();
 
  323                 JsonElement nameEl = address.get(
"name"); 
 
  324                 if (nameEl != null) {
 
  325                     name = nameEl.getAsString();
 
  330                 JsonElement dateEl = address.get(
"date_added"); 
 
  331                 if (dateEl != null) {
 
  332                     date = dateEl.getAsLong();
 
  334                     date = Long.valueOf(0);
 
  336                 String domain = NetworkUtils.extractDomain(url);
 
  338                     BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
 
  339                     Collection<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  341                     bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
 
  342                             RecentActivityExtracterModuleFactory.getModuleName(), url));
 
  343                     bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
 
  344                             RecentActivityExtracterModuleFactory.getModuleName(), name));
 
  345                     bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
 
  346                             RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf(
"11644473600")));
 
  347                     bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
 
  348                             RecentActivityExtracterModuleFactory.getModuleName(),
 
  349                             NbBundle.getMessage(this.getClass(), 
"Chrome.moduleName")));
 
  350                     bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
 
  351                             RecentActivityExtracterModuleFactory.getModuleName(), domain));
 
  352                     bbart.addAttributes(bbattributes);
 
  355                     this.indexArtifact(bbart);
 
  356                     bbartifacts.add(bbart);
 
  357                 } 
catch (TskCoreException ex) {
 
  358                     logger.log(Level.SEVERE, 
"Error while trying to insert Chrome bookmark artifact{0}", ex); 
 
  359                     this.addErrorMessage(
 
  360                             NbBundle.getMessage(
this.getClass(), 
"Chrome.getBookmark.errMsg.errAnalyzingFile4",
 
  361                                     this.getName(), bookmarkFile.getName()));
 
  367         IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
 
  368                 NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"),
 
  369                 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bbartifacts));
 
  375     private void getCookie() {
 
  377         FileManager fileManager = currentCase.getServices().getFileManager();
 
  378         List<AbstractFile> cookiesFiles;
 
  380             cookiesFiles = fileManager.findFiles(dataSource, 
"Cookies", 
"Chrome"); 
 
  381         } 
catch (TskCoreException ex) {
 
  382             String msg = NbBundle.getMessage(this.getClass(), 
"Chrome.getCookie.errMsg.errGettingFiles");
 
  383             logger.log(Level.SEVERE, msg, ex);
 
  384             this.addErrorMessage(this.getName() + 
": " + msg);
 
  388         if (cookiesFiles.isEmpty()) {
 
  389             logger.log(Level.INFO, 
"Didn't find any Chrome cookies files."); 
 
  394         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  396         while (j < cookiesFiles.size()) {
 
  397             AbstractFile cookiesFile = cookiesFiles.get(j++);
 
  398             if (cookiesFile.getSize() == 0) {
 
  401             String temps = RAImageIngestModule.getRATempPath(currentCase, 
"chrome") + File.separator + cookiesFile.getName() + j + 
".db"; 
 
  403                 ContentUtils.writeToFile(cookiesFile, 
new File(temps), context::dataSourceIngestIsCancelled);
 
  404             } 
catch (ReadContentInputStreamException ex) {
 
  405                 logger.log(Level.WARNING, String.format(
"Error reading Chrome cookie artifacts file '%s' (id=%d).",
 
  406                         cookiesFile.getName(), cookiesFile.getId()), ex); 
 
  407                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getCookie.errMsg.errAnalyzeFile",
 
  408                         this.getName(), cookiesFile.getName()));
 
  410             } 
catch (IOException ex) {
 
  411                 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
 
  412                         temps, cookiesFile.getName(), cookiesFile.getId()), ex); 
 
  413                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getCookie.errMsg.errAnalyzeFile",
 
  414                         this.getName(), cookiesFile.getName()));
 
  417             File dbFile = 
new File(temps);
 
  418             if (context.dataSourceIngestIsCancelled()) {
 
  423             List<HashMap<String, Object>> tempList = this.dbConnect(temps, COOKIE_QUERY);
 
  424             logger.log(Level.INFO, 
"{0}- Now getting cookies from {1} with {2}artifacts identified.", 
new Object[]{moduleName, temps, tempList.size()}); 
 
  425             for (HashMap<String, Object> result : tempList) {
 
  426                 Collection<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  427                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
 
  428                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  429                         ((result.get(
"host_key").toString() != null) ? result.get(
"host_key").toString() : 
""))); 
 
  430                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
 
  431                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  432                         (Long.valueOf(result.get(
"last_access_utc").toString()) / 1000000) - Long.valueOf(
"11644473600"))); 
 
  434                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
 
  435                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  436                         ((result.get(
"name").toString() != null) ? result.get(
"name").toString() : 
""))); 
 
  437                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
 
  438                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  439                         ((result.get(
"value").toString() != null) ? result.get(
"value").toString() : 
""))); 
 
  440                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
 
  441                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  442                         NbBundle.getMessage(this.getClass(), 
"Chrome.moduleName")));
 
  443                 String domain = result.get(
"host_key").toString(); 
 
  444                 domain = domain.replaceFirst(
"^\\.+(?!$)", 
"");
 
  445                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
 
  446                         RecentActivityExtracterModuleFactory.getModuleName(), domain));
 
  448                 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
 
  450                     bbartifacts.add(bbart);
 
  457         IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
 
  458                 NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"),
 
  459                 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, bbartifacts));
 
  465     private void getDownload() {
 
  466         FileManager fileManager = currentCase.getServices().getFileManager();
 
  467         List<AbstractFile> downloadFiles;
 
  469             downloadFiles = fileManager.findFiles(dataSource, 
"History", 
"Chrome"); 
 
  470         } 
catch (TskCoreException ex) {
 
  471             String msg = NbBundle.getMessage(this.getClass(), 
"Chrome.getDownload.errMsg.errGettingFiles");
 
  472             logger.log(Level.SEVERE, msg, ex);
 
  473             this.addErrorMessage(this.getName() + 
": " + msg);
 
  477         if (downloadFiles.isEmpty()) {
 
  478             logger.log(Level.INFO, 
"Didn't find any Chrome download files."); 
 
  483         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  485         while (j < downloadFiles.size()) {
 
  486             AbstractFile downloadFile = downloadFiles.get(j++);
 
  487             if (downloadFile.getSize() == 0) {
 
  490             String temps = RAImageIngestModule.getRATempPath(currentCase, 
"chrome") + File.separator + downloadFile.getName() + j + 
".db"; 
 
  492                 ContentUtils.writeToFile(downloadFile, 
new File(temps), context::dataSourceIngestIsCancelled);
 
  493             } 
catch (ReadContentInputStreamException ex) {
 
  494                 logger.log(Level.WARNING, String.format(
"Error reading Chrome download artifacts file '%s' (id=%d).",
 
  495                         downloadFile.getName(), downloadFile.getId()), ex); 
 
  496                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
 
  497                         this.getName(), downloadFile.getName()));
 
  499             } 
catch (IOException ex) {
 
  500                 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
 
  501                         temps, downloadFile.getName(), downloadFile.getId()), ex); 
 
  502                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getDownload.errMsg.errAnalyzeFiles1",
 
  503                         this.getName(), downloadFile.getName()));
 
  506             File dbFile = 
new File(temps);
 
  507             if (context.dataSourceIngestIsCancelled()) {
 
  512             List<HashMap<String, Object>> tempList;
 
  514             if (isChromePreVersion30(temps)) {
 
  515                 tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
 
  517                 tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V30);
 
  520             logger.log(Level.INFO, 
"{0}- Now getting downloads from {1} with {2} artifacts identified.", 
new Object[]{moduleName, temps, tempList.size()}); 
 
  521             for (HashMap<String, Object> result : tempList) {
 
  522                 Collection<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  523                 String fullPath = result.get(
"full_path").toString(); 
 
  524                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
 
  525                         RecentActivityExtracterModuleFactory.getModuleName(), fullPath)); 
 
  526                 long pathID = Util.findID(dataSource, fullPath); 
 
  528                     bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
 
  529                             NbBundle.getMessage(
this.getClass(),
 
  530                                     "Chrome.parentModuleName"), pathID));
 
  532                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
 
  533                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  534                         ((result.get(
"url").toString() != null) ? result.get(
"url").toString() : 
""))); 
 
  536                 Long time = (Long.valueOf(result.get(
"start_time").toString()) / 1000000) - Long.valueOf(
"11644473600"); 
 
  540                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
 
  541                         RecentActivityExtracterModuleFactory.getModuleName(), time));
 
  542                 String domain = NetworkUtils.extractDomain((result.get(
"url").toString() != null) ? result.get(
"url").toString() : 
""); 
 
  543                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
 
  544                         RecentActivityExtracterModuleFactory.getModuleName(), domain));
 
  545                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
 
  546                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  547                         NbBundle.getMessage(this.getClass(), 
"Chrome.moduleName")));
 
  549                 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
 
  551                     bbartifacts.add(bbart);
 
  556                     for (AbstractFile downloadedFile : fileManager.findFiles(dataSource, FilenameUtils.getName(fullPath), FilenameUtils.getPath(fullPath))) {
 
  557                         BlackboardArtifact downloadSourceArt =  downloadedFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
 
  558                         downloadSourceArt.addAttributes(createDownloadSourceAttributes(result.get(
"url").toString()));
 
  560                         bbartifacts.add(downloadSourceArt);
 
  563                 } 
catch (TskCoreException ex) {
 
  564                      logger.log(Level.SEVERE, String.format(
"Error creating download source artifact for file  '%s'", fullPath), ex); 
 
  571         IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
 
  572                 NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"),
 
  573                 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
 
  579     private void getLogins() {
 
  581         FileManager fileManager = currentCase.getServices().getFileManager();
 
  582         List<AbstractFile> loginDataFiles;
 
  584             loginDataFiles = fileManager.findFiles(dataSource, 
"Login Data", 
"Chrome"); 
 
  585         } 
catch (TskCoreException ex) {
 
  586             String msg = NbBundle.getMessage(this.getClass(), 
"Chrome.getLogin.errMsg.errGettingFiles");
 
  587             logger.log(Level.SEVERE, msg, ex);
 
  588             this.addErrorMessage(this.getName() + 
": " + msg);
 
  592         if (loginDataFiles.isEmpty()) {
 
  593             logger.log(Level.INFO, 
"Didn't find any Chrome Login Data files."); 
 
  598         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  600         while (j < loginDataFiles.size()) {
 
  601             AbstractFile loginDataFile = loginDataFiles.get(j++);
 
  602             if (loginDataFile.getSize() == 0) {
 
  605             String temps = RAImageIngestModule.getRATempPath(currentCase, 
"chrome") + File.separator + loginDataFile.getName() + j + 
".db"; 
 
  607                 ContentUtils.writeToFile(loginDataFile, 
new File(temps), context::dataSourceIngestIsCancelled);
 
  608             } 
catch (ReadContentInputStreamException ex) {
 
  609                 logger.log(Level.WARNING, String.format(
"Error reading Chrome login artifacts file '%s' (id=%d).",
 
  610                         loginDataFile.getName(), loginDataFile.getId()), ex); 
 
  611                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getLogin.errMsg.errAnalyzingFiles",
 
  612                         this.getName(), loginDataFile.getName()));
 
  614             } 
catch (IOException ex) {
 
  615                 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
 
  616                         temps, loginDataFile.getName(), loginDataFile.getId()), ex); 
 
  617                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getLogin.errMsg.errAnalyzingFiles",
 
  618                         this.getName(), loginDataFile.getName()));
 
  621             File dbFile = 
new File(temps);
 
  622             if (context.dataSourceIngestIsCancelled()) {
 
  626             List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
 
  627             logger.log(Level.INFO, 
"{0}- Now getting login information from {1} with {2}artifacts identified.", 
new Object[]{moduleName, temps, tempList.size()}); 
 
  628             for (HashMap<String, Object> result : tempList) {
 
  629                 Collection<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  631                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
 
  632                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  633                         ((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() : 
""))); 
 
  636                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
 
  637                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  638                         (Long.valueOf(result.get(
"date_created").toString()) / 1000000) - Long.valueOf(
"11644473600"))); 
 
  640                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
 
  641                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  642                         (NetworkUtils.extractDomain((result.get(
"origin_url").toString() != null) ? result.get(
"origin_url").toString() : 
"")))); 
 
  644                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
 
  645                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  646                         ((result.get(
"username_value").toString() != null) ? result.get(
"username_value").toString().replaceAll(
"'", 
"''") : 
""))); 
 
  648                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
 
  649                         RecentActivityExtracterModuleFactory.getModuleName(),
 
  650                         ((result.get(
"signon_realm").toString() != null) ? result.get(
"signon_realm").toString() : 
""))); 
 
  652                 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes);
 
  654                     this.indexArtifact(bbart);
 
  655                     bbartifacts.add(bbart);
 
  661         IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
 
  662                 NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"),
 
  663                 BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, bbartifacts));
 
  671     private void getAutofill() {
 
  673         FileManager fileManager = currentCase.getServices().getFileManager();
 
  674         List<AbstractFile> webDataFiles;
 
  676             webDataFiles = fileManager.findFiles(dataSource, 
"Web Data", 
"Chrome"); 
 
  677         } 
catch (TskCoreException ex) {
 
  678             String msg = NbBundle.getMessage(this.getClass(), 
"Chrome.getAutofills.errMsg.errGettingFiles");
 
  679             logger.log(Level.SEVERE, msg, ex);
 
  680             this.addErrorMessage(this.getName() + 
": " + msg);
 
  684         if (webDataFiles.isEmpty()) {
 
  685             logger.log(Level.INFO, 
"Didn't find any Chrome Web Data files."); 
 
  690         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  692         while (j < webDataFiles.size()) {
 
  693             AbstractFile webDataFile = webDataFiles.get(j++);
 
  694             if (webDataFile.getSize() == 0) {
 
  697             String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, 
"chrome") + File.separator + webDataFile.getName() + j + 
".db"; 
 
  699                 ContentUtils.writeToFile(webDataFile, 
new File(tempFilePath), context::dataSourceIngestIsCancelled);
 
  700             } 
catch (ReadContentInputStreamException ex) {
 
  701                 logger.log(Level.WARNING, String.format(
"Error reading Chrome Autofill artifacts file '%s' (id=%d).",
 
  702                         webDataFile.getName(), webDataFile.getId()), ex); 
 
  703                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getAutofill.errMsg.errAnalyzingFiles",
 
  704                         this.getName(), webDataFile.getName()));
 
  706             } 
catch (IOException ex) {
 
  707                 logger.log(Level.SEVERE, String.format(
"Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
 
  708                         tempFilePath, webDataFile.getName(), webDataFile.getId()), ex); 
 
  709                 this.addErrorMessage(NbBundle.getMessage(
this.getClass(), 
"Chrome.getLogin.errMsg.errAnalyzingFiles",
 
  710                         this.getName(), webDataFile.getName()));
 
  713             File dbFile = 
new File(tempFilePath);
 
  714             if (context.dataSourceIngestIsCancelled()) {
 
  720             boolean isSchemaV8X = Util.checkColumn(
"date_created", 
"autofill", tempFilePath);
 
  723             bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X));
 
  725             bbartifacts.addAll(getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X));
 
  729         IngestServices.getInstance().fireModuleDataEvent(
new ModuleDataEvent(
 
  730                 NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"),
 
  731                 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, bbartifacts));
 
  744     private Collection<BlackboardArtifact> getFormAutofillArtifacts (AbstractFile webDataFile, String dbFilePath , 
boolean isSchemaV8X ) {
 
  746         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  749         String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X  
 
  752         List<HashMap<String, Object>> autofills = this.dbConnect(dbFilePath, autoFillquery);
 
  753         logger.log(Level.INFO, 
"{0}- Now getting Autofill information from {1} with {2}artifacts identified.", 
new Object[]{moduleName, dbFilePath, autofills.size()}); 
 
  754         for (HashMap<String, Object> result : autofills) {
 
  755             Collection<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  758             bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
 
  759                     NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"),
 
  760                     ((result.get(
"name").toString() != null) ? result.get(
"name").toString() : 
""))); 
 
  762             bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
 
  763                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  764                     ((result.get(
"value").toString() != null) ? result.get(
"value").toString() : 
""))); 
 
  766             bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
 
  767                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  768                     (Integer.valueOf(result.get(
"count").toString())))); 
 
  770              bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
 
  771                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  772                     Long.valueOf(result.get(
"date_created").toString()))); 
 
  776                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
 
  777                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  778                     Long.valueOf(result.get(
"date_last_used").toString()))); 
 
  782             BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes);
 
  784                 this.indexArtifact(bbart);
 
  785                 bbartifacts.add(bbart);
 
  802     private Collection<BlackboardArtifact> getFormAddressArtifacts (AbstractFile webDataFile, String dbFilePath , 
boolean isSchemaV8X ) {
 
  803         Collection<BlackboardArtifact> bbartifacts = 
new ArrayList<>();
 
  805         String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X 
 
  806                                                     : WEBFORM_ADDRESS_QUERY;
 
  809         List<HashMap<String, Object>> addresses = this.dbConnect(dbFilePath, webformAddressQuery);
 
  810         logger.log(Level.INFO, 
"{0}- Now getting Web form addresses from {1} with {2}artifacts identified.", 
new Object[]{moduleName, dbFilePath, addresses.size()}); 
 
  811         for (HashMap<String, Object> result : addresses) {
 
  812             Collection<BlackboardAttribute> bbattributes = 
new ArrayList<>();
 
  815             String first_name = result.get(
"first_name").toString() != null ? result.get(
"first_name").toString() : 
"";
 
  816             String middle_name = result.get(
"middle_name").toString() != null ? result.get(
"middle_name").toString() : 
"";
 
  817             String last_name = result.get(
"last_name").toString() != null ? result.get(
"last_name").toString() : 
"";
 
  820             String email_Addr = result.get(
"email").toString() != null ? result.get(
"email").toString() : 
"";
 
  821             String phone_number = result.get(
"number").toString() != null ? result.get(
"number").toString() : 
"";
 
  824             String city = result.get(
"city").toString() != null ? result.get(
"city").toString() : 
"";
 
  825             String state = result.get(
"state").toString() != null ? result.get(
"state").toString() : 
"";
 
  826             String zipcode = result.get(
"zipcode").toString() != null ? result.get(
"zipcode").toString() : 
"";
 
  827             String country_code = result.get(
"country_code").toString() != null ? result.get(
"country_code").toString() : 
"";
 
  830             String full_name = 
"";
 
  831             String street_address = 
"";
 
  832             long date_modified = 0;
 
  837                 full_name = result.get(
"full_name").toString() != null ? result.get(
"full_name").toString() : 
"";
 
  838                 street_address = result.get(
"street_address").toString() != null ? result.get(
"street_address").toString() : 
"";
 
  839                 date_modified = result.get(
"date_modified").toString() != null ? Long.valueOf(result.get(
"date_modified").toString()) : 0;
 
  840                 use_count = result.get(
"use_count").toString() != null ? Integer.valueOf(result.get(
"use_count").toString()) : 0;
 
  841                 use_date = result.get(
"use_date").toString() != null ? Long.valueOf(result.get(
"use_date").toString()) : 0;   
 
  843                 String address_line_1 = result.get(
"address_line_1").toString() != null ? result.get(
"street_address").toString() : 
""; 
 
  844                 String address_line_2 = result.get(
"address_line_2").toString() != null ? result.get(
"address_line_2").toString() : 
"";
 
  845                 street_address = String.join(
" ", address_line_1, address_line_2);
 
  849             if (email_Addr != null && !email_Addr.isEmpty()) {
 
  851                     Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, email_Addr,  NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"), webDataFile);
 
  852                 } 
catch (NoCurrentCaseException | TskCoreException ex) {
 
  853                     logger.log(Level.SEVERE, String.format(
"Error creating email account instance for '%s' from Chrome WebData file '%s' .",
 
  854                         email_Addr, webDataFile.getName()), ex); 
 
  858             if (phone_number != null && !phone_number.isEmpty()) {
 
  860                     Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, phone_number,  NbBundle.getMessage(
this.getClass(), 
"Chrome.parentModuleName"), webDataFile);
 
  861                 } 
catch (NoCurrentCaseException | TskCoreException ex) {
 
  862                     logger.log(Level.SEVERE, String.format(
"Error creating phone account instance for '%s' from Chrome WebData file '%s' .",
 
  863                         phone_number, webDataFile.getName()), ex); 
 
  868             if (full_name == null || full_name.isEmpty()) {
 
  869                 full_name = String.join(
" ", first_name, middle_name, last_name);
 
  871             bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME_PERSON,
 
  872                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  875             bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
 
  876                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  879             bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
 
  880                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  883             String locationAddress = String.join(
", ", street_address, city, state, zipcode, country_code);
 
  884             bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCATION,
 
  885                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  888             if (date_modified > 0) {
 
  889                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
 
  890                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  895                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
 
  896                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  901                 bbattributes.add(
new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
 
  902                     RecentActivityExtracterModuleFactory.getModuleName(),
 
  907             BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS, webDataFile, bbattributes);
 
  909                 this.indexArtifact(bbart);
 
  910                 bbartifacts.add(bbart);
 
  918     private boolean isChromePreVersion30(String temps) {
 
  919         String query = 
"PRAGMA table_info(downloads)"; 
 
  920         List<HashMap<String, Object>> columns = this.dbConnect(temps, query);
 
  921         for (HashMap<String, Object> col : columns) {
 
  922             if (col.get(
"name").equals(
"url")) {