Autopsy  4.19.3
Graphical digital forensics platform for The Sleuth Kit and other tools.
Chromium.java
Go to the documentation of this file.
1 /*
2  *
3  * Autopsy Forensic Browser
4  *
5  * Copyright 2012-2021 Basis Technology Corp.
6  *
7  * Copyright 2012 42six Solutions.
8  *
9  * Project Contact/Architect: carrier <at> sleuthkit <dot> org
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 package org.sleuthkit.autopsy.recentactivity;
24 
25 import com.google.common.collect.ImmutableMap;
26 import com.google.gson.JsonArray;
27 import com.google.gson.JsonElement;
28 import com.google.gson.JsonIOException;
29 import com.google.gson.JsonObject;
30 import com.google.gson.JsonParser;
31 import com.google.gson.JsonSyntaxException;
32 import org.openide.util.NbBundle;
34 import java.util.logging.Level;
35 import java.io.File;
36 import java.io.FileNotFoundException;
37 import java.io.FileReader;
38 import java.io.IOException;
39 import java.util.Collection;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.HashMap;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Set;
46 import org.apache.commons.io.FilenameUtils;
47 import org.apache.commons.lang3.StringUtils;
48 import org.openide.util.NbBundle.Messages;
56 import org.sleuthkit.datamodel.AbstractFile;
57 import org.sleuthkit.datamodel.Blackboard;
58 import org.sleuthkit.datamodel.BlackboardArtifact;
59 import org.sleuthkit.datamodel.BlackboardAttribute;
60 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
61 import org.sleuthkit.datamodel.Content;
62 import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
63 import org.sleuthkit.datamodel.Score;
64 import org.sleuthkit.datamodel.TskCoreException;
65 import org.sleuthkit.datamodel.TskData;
66 import org.sleuthkit.datamodel.blackboardutils.WebBrowserArtifactsHelper;
67 
71 class Chromium extends Extract {
72 
73  private static final String HISTORY_QUERY = "SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, " //NON-NLS
74  + "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"; //NON-NLS
75  private static final String COOKIE_QUERY = "SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies"; //NON-NLS
76  private static final String DOWNLOAD_QUERY = "SELECT full_path, url, start_time, received_bytes FROM downloads"; //NON-NLS
77  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"; //NON-NLS
78  private static final String LOGIN_QUERY = "SELECT origin_url, username_value, date_created, signon_realm from logins"; //NON-NLS
79  private static final String AUTOFILL_QUERY = "SELECT name, value, count, date_created "
80  + " FROM autofill, autofill_dates "
81  + " WHERE autofill.pair_id = autofill_dates.pair_id"; //NON-NLS
82  private static final String AUTOFILL_QUERY_V8X = "SELECT name, value, count, date_created, date_last_used from autofill"; //NON-NLS
83  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 "
84  + " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones"
85  + " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
86 
87  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"
88  + " FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones"
89  + " WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
90  private static final String FAVICON_QUERY = "SELECT page_url, last_updated, last_requested FROM icon_mapping, favicon_bitmaps "
91  + " WHERE icon_mapping.icon_id = favicon_bitmaps.icon_id";
92  private static final String LOCALSTATE_FILE_NAME = "Local State";
93  private static final String EXTENSIONS_FILE_NAME = "Secure Preferences";
94  private static final String HISTORY_FILE_NAME = "History";
95  private static final String BOOKMARK_FILE_NAME = "Bookmarks";
96  private static final String COOKIE_FILE_NAME = "Cookies";
97  private static final String LOGIN_DATA_FILE_NAME = "Login Data";
98  private static final String WEB_DATA_FILE_NAME = "Web Data";
99  private static final String FAVICON_DATA_FILE_NAME = "Favicons";
100  private static final String UC_BROWSER_NAME = "UC Browser";
101  private static final String OPERA_BROWSER_NAME = "Opera";
102  private static final String ENCRYPTED_FIELD_MESSAGE = "The data was encrypted.";
103  private static final String GOOGLE_PROFILE_NAME = "Profile";
104  private static final String GOOGLE_PROFILE = "Google Chrome ";
105  private static final String FAVICON_ARTIFACT_NAME = "TSK_FAVICON"; //NON-NLS
106  private static final String LOCAL_STATE_ARTIFACT_NAME = "TSK_LOCAL_STATE"; //NON-NLS
107  private static final String EXTENSIONS_ARTIFACT_NAME = "TSK_CHROME_EXTENSIONS"; //NON-NLS
108 
109  private Boolean databaseEncrypted = false;
110  private Boolean fieldEncrypted = false;
111 
112  private final Logger logger = Logger.getLogger(this.getClass().getName());
113  private Content dataSource;
114  private final IngestJobContext context;
115 
116  private Map<String, String> userProfiles;
117  private Map<String, String> browserLocations;
118 
119  private static final Map<String, String> BROWSERS_MAP = ImmutableMap.<String, String>builder()
120  .put("Microsoft Edge", "Microsoft/Edge/User Data")
121  .put("Yandex", "YandexBrowser/User Data")
122  .put("Opera", "Opera Software/Opera Stable")
123  .put("SalamWeb", "SalamWeb/User Data")
124  .put("UC Browser", "UCBrowser/User Data%")
125  .put("Brave", "BraveSoftware/Brave-Browser/User Data")
126  .put("Google Chrome", "Chrome/User Data")
127  .build();
128 
129  @Messages({"# {0} - browserName",
130  "Progress_Message_Chrome_History=Chrome History Browser {0}",
131  "# {0} - browserName",
132  "Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}",
133  "# {0} - browserName",
134  "Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}",
135  "# {0} - browserName",
136  "Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}",
137  "Progress_Message_Chrome_Profiles=Chrome Profiles {0}",
138  "Progress_Message_Chrome_Extensions=Chrome Extensions {0}",
139  "Progress_Message_Chrome_Favicons=Chrome Downloads Favicons {0}",
140  "Progress_Message_Chrome_FormHistory=Chrome Form History",
141  "# {0} - browserName",
142  "Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}",
143  "# {0} - browserName",
144  "Progress_Message_Chrome_Logins=Chrome Logins Browser {0}",
145  "Progress_Message_Chrome_Cache=Chrome Cache",})
146 
147  Chromium(IngestJobContext context) {
148  super(NbBundle.getMessage(Chromium.class, "Chrome.moduleName"), context);
149  this.context = context;
150  }
151 
152  @Override
153  public void process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
154  this.dataSource = dataSource;
155  dataFound = false;
156  long ingestJobId = context.getJobId();
157 
158  userProfiles = new HashMap<>();
159  browserLocations = new HashMap<>();
160  for (Map.Entry<String, String> browser : BROWSERS_MAP.entrySet()) {
161  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Profiles", browser.getKey()));
162  getProfiles(browser.getKey(), browser.getValue(), ingestJobId);
163  if (context.dataSourceIngestIsCancelled()) {
164  return;
165  }
166  }
167  for (Map.Entry<String, String> profile : userProfiles.entrySet()) {
168  String browserLocation = profile.getKey();
169  String browserName = browserLocations.get(browserLocation);
170  String userName = profile.getValue();
171  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Extensions", browserName));
172  this.getExtensions(browserName, browserLocation, userName, ingestJobId);
173  if (context.dataSourceIngestIsCancelled()) {
174  return;
175  }
176  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_History", browserName));
177  this.getHistory(browserName, browserLocation, userName, ingestJobId);
178  if (context.dataSourceIngestIsCancelled()) {
179  return;
180  }
181 
182  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Bookmarks", browserName));
183  this.getBookmark(browserName, browserLocation, userName, ingestJobId);
184  if (context.dataSourceIngestIsCancelled()) {
185  return;
186  }
187 
188  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Cookies", browserName));
189  this.getCookie(browserName, browserLocation, userName, ingestJobId);
190  if (context.dataSourceIngestIsCancelled()) {
191  return;
192  }
193 
194  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Logins", browserName));
195  this.getLogins(browserName, browserLocation, userName, ingestJobId);
196  if (context.dataSourceIngestIsCancelled()) {
197  return;
198  }
199 
200  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_AutoFill", browserName));
201  this.getAutofill(browserName, browserLocation, userName, ingestJobId);
202  if (context.dataSourceIngestIsCancelled()) {
203  return;
204  }
205 
206  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Downloads", browserName));
207  this.getDownload(browserName, browserLocation, userName, ingestJobId);
208  if (context.dataSourceIngestIsCancelled()) {
209  return;
210  }
211 
212  progressBar.progress(NbBundle.getMessage(this.getClass(), "Progress_Message_Chrome_Favicons", browserName));
213  this.getFavicons(browserName, browserLocation, userName, ingestJobId);
214  if (context.dataSourceIngestIsCancelled()) {
215  return;
216  }
217  }
218 
219  progressBar.progress(Bundle.Progress_Message_Chrome_Cache());
220  ChromeCacheExtractor chromeCacheExtractor = new ChromeCacheExtractor(dataSource, context, progressBar);
221  chromeCacheExtractor.processCaches();
222  }
223 
231  private void getProfiles(String browser, String browserLocation, long ingestJobId) {
232  FileManager fileManager = currentCase.getServices().getFileManager();
233  String browserName = browser;
234  List<AbstractFile> localStateFiles;
235  String localStateName = LOCALSTATE_FILE_NAME;
236  if (browserName.equals(UC_BROWSER_NAME)) {
237  localStateName = LOCALSTATE_FILE_NAME + "%";
238  }
239  try {
240  localStateFiles = fileManager.findFiles(dataSource, localStateName, browserLocation); //NON-NLS
241  } catch (TskCoreException ex) {
242  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.errGettingFiles");
243  logger.log(Level.SEVERE, msg, ex);
244  this.addErrorMessage(this.getDisplayName() + ": " + msg);
245  return;
246  }
247 
248  // get only the allocated ones, for now
249  List<AbstractFile> allocatedLocalStateFiles = new ArrayList<>();
250  for (AbstractFile localStateFile : localStateFiles) {
251  if (localStateFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
252  allocatedLocalStateFiles.add(localStateFile);
253  }
254  }
255 
256  // log a message if we don't have any allocated Local State files
257  if (allocatedLocalStateFiles.isEmpty()) {
258  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.couldntFindAnyFiles");
259  logger.log(Level.INFO, msg);
260  return;
261  }
262 
263  dataFound = true;
264  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
265  int j = 0;
266  while (j < allocatedLocalStateFiles.size()) {
267  if (browser.contains(GOOGLE_PROFILE_NAME)) {
268  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedLocalStateFiles.get(j).getParentPath());
269  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
270  }
271  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedLocalStateFiles.get(j).getName() + j; //NON-NLS
272  final AbstractFile localStateFile = allocatedLocalStateFiles.get(j++);
273  if ((localStateFile.getSize() == 0) || (localStateFile.getName().toLowerCase().contains("-slack"))
274  || (localStateFile.getName().toLowerCase().contains("cache")) || (localStateFile.getName().toLowerCase().contains("media"))
275  || (localStateFile.getName().toLowerCase().contains("index"))) {
276  continue;
277  }
278  try {
279  ContentUtils.writeToFile(localStateFile, new File(temps), context::dataSourceIngestIsCancelled);
280  } catch (ReadContentInputStreamException ex) {
281  logger.log(Level.WARNING, String.format("Error reading Chrome web Local State artifacts file '%s' (id=%d).",
282  localStateFile.getName(), localStateFile.getId()), ex); //NON-NLS
283  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.errAnalyzingFile",
284  this.getDisplayName(), localStateFile.getName()));
285  continue;
286  } catch (IOException ex) {
287  logger.log(Level.SEVERE, String.format("Error writing temp file '%s' for Chrome Local State artifacts file '%s' (id=%d).",
288  temps, localStateFile.getName(), localStateFile.getId()), ex); //NON-NLS
289  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.errMsg.errAnalyzingFile",
290  this.getDisplayName(), localStateFile.getName()));
291  continue;
292  }
293 
294  if (context.dataSourceIngestIsCancelled()) {
295  break;
296  }
297 
298  FileReader tempReader;
299  try {
300  tempReader = new FileReader(temps);
301  } catch (FileNotFoundException ex) {
302  logger.log(Level.WARNING, "Error while trying to read into the LocalState file.", ex); //NON-NLS
303  continue;
304  }
305 
306  JsonElement jsonElement;
307  JsonObject jElement, jProfile, jInfoCache;
308 
309  try {
310  jsonElement = JsonParser.parseReader(tempReader);
311  jElement = jsonElement.getAsJsonObject();
312  if (jElement.has("profile")) {
313  jProfile = jElement.get("profile").getAsJsonObject(); //NON-NLS
314  jInfoCache = jProfile.get("info_cache").getAsJsonObject();
315  } else {
316  continue;
317  }
318  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
319  logger.log(Level.WARNING, "Error parsing Json from LocalState.", ex); //NON-NLS
320  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getlocalState.errMsg.errAnalyzingFile",
321  this.getDisplayName(), localStateFile.getName()));
322  continue;
323  }
324 
325  BlackboardArtifact.Type localStateArtifactType;
326 
327  try {
328  localStateArtifactType = createArtifactType(LOCAL_STATE_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getLocalState.displayName"));
329  } catch (TskCoreException ex) {
330  logger.log(Level.SEVERE, String.format("Error creating artifact type for LocalState."), ex); //NON-NLS
331  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errCreateArtifact"));
332  continue;
333 
334  }
335  Set<String> profileNames = jInfoCache.keySet();
336  for (String profileName : profileNames) {
337  JsonElement result = jInfoCache.get(profileName);
338  JsonObject profile = result.getAsJsonObject();
339  if (profile == null) {
340  continue;
341  }
342  JsonElement gaiaIdEl = profile.get("gaia_id"); //NON-NLS
343  String gaiaId;
344  if (gaiaIdEl != null) {
345  gaiaId = gaiaIdEl.getAsString();
346  } else {
347  gaiaId = "";
348  }
349  String hostedDomain;
350  JsonElement hostedDomainEl = profile.get("hosted_domain"); //NON-NLS
351  if (hostedDomainEl != null) {
352  hostedDomain = hostedDomainEl.getAsString();
353  } else {
354  hostedDomain= "";
355  }
356  String shortcutName;
357  JsonElement shortcutNameEl = profile.get("shortcut_name"); //NON-NLS
358  if (shortcutNameEl != null) {
359  shortcutName = shortcutNameEl.getAsString();
360  } else {
361  shortcutName = "";
362  }
363  String name;
364  JsonElement nameEl = profile.get("name"); //NON-NLS
365  if (nameEl != null) {
366  name = nameEl.getAsString();
367  } else {
368  name= "";
369  }
370  String userName;
371  JsonElement userNameEl = profile.get("user_name"); //NON-NLS
372  if (userNameEl != null) {
373  userName = userNameEl.getAsString();
374  } else {
375  userName = "";
376  }
377 
378  if (userName.contains("")) {
379  userProfiles.put(browserLocation + "/" + profileName, name);
380  browserLocations.put(browserLocation + "/" + profileName, browser);
381  } else {
382  userProfiles.put(browserLocation + "/" + profileName, userName);
383  browserLocations.put(browserLocation + "/" + profileName, browser);
384  }
385 
386  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
387  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
388  RecentActivityExtracterModuleFactory.getModuleName(), profileName));
389  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID,
390  RecentActivityExtracterModuleFactory.getModuleName(), gaiaId));
391  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
392  RecentActivityExtracterModuleFactory.getModuleName(), hostedDomain));
393  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SHORTCUT,
394  RecentActivityExtracterModuleFactory.getModuleName(), shortcutName));
395  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
396  RecentActivityExtracterModuleFactory.getModuleName(), name));
397  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
398  RecentActivityExtracterModuleFactory.getModuleName(), userName));
399  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
400  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
401 
402  try {
403  bbartifacts.add(createArtifactWithAttributes(localStateArtifactType, localStateFile, bbattributes));
404  } catch (TskCoreException ex) {
405  logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", localStateFile.getId()), ex);
406  }
407 
408  }
409 
410  if (!context.dataSourceIngestIsCancelled()) {
411  postArtifacts(bbartifacts);
412  }
413  bbartifacts.clear();
414 
415  }
416  // Check if Default, Guest Profile and System Profile are in the usersProfiles, if they are not then add them
417  if (!userProfiles.containsKey("Default")) {
418  userProfiles.put(browserLocation + "/" + "Default", "Default");
419  browserLocations.put(browserLocation + "/" + "Default", browser);
420  }
421  if (!userProfiles.containsKey("Guest Profile")) {
422  userProfiles.put(browserLocation + "/" + "Guest Profile", "Guest");
423  browserLocations.put(browserLocation + "/" + "Guest Profile", browser);
424  }
425  if (!userProfiles.containsKey("System Profile")) {
426  userProfiles.put(browserLocation + "/" + "System Profile", "System");
427  browserLocations.put(browserLocation + "/" + "System Profile", browser);
428  }
429  }
430 
438  private void getExtensions(String browser, String browserLocation, String userName, long ingestJobId) {
439  FileManager fileManager = currentCase.getServices().getFileManager();
440  String browserName = browser;
441  List<AbstractFile> extensionFiles;
442  String extensionsName = EXTENSIONS_FILE_NAME;
443  if (browserName.equals(UC_BROWSER_NAME)) {
444  extensionsName = EXTENSIONS_FILE_NAME + "%";
445  }
446  try {
447  // Local State file is found in the directory about the browserLocation, that is why it is being removed
448  extensionFiles = fileManager.findFiles(dataSource, extensionsName, browserLocation); //NON-NLS
449  } catch (TskCoreException ex) {
450  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errGettingFiles");
451  logger.log(Level.SEVERE, msg, ex);
452  this.addErrorMessage(this.getDisplayName() + ": " + msg);
453  return;
454  }
455 
456  // get only the allocated ones, for now
457  List<AbstractFile> allocatedExtensionsFiles = new ArrayList<>();
458  for (AbstractFile extensionFile : extensionFiles) {
459  if (extensionFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
460  allocatedExtensionsFiles.add(extensionFile);
461  }
462  }
463 
464  // log a message if we don't have any allocated Local State files
465  if (allocatedExtensionsFiles.isEmpty()) {
466  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.couldntFindAnyFiles");
467  logger.log(Level.INFO, msg);
468  return;
469  }
470 
471  dataFound = true;
472  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
473  int j = 0;
474  while (j < allocatedExtensionsFiles.size()) {
475  if (browser.contains(GOOGLE_PROFILE_NAME)) {
476  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedExtensionsFiles.get(j).getParentPath());
477  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
478  }
479  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedExtensionsFiles.get(j).getName() + j; //NON-NLS
480  final AbstractFile extensionFile = allocatedExtensionsFiles.get(j++);
481  if ((extensionFile.getSize() == 0) || (extensionFile.getName().toLowerCase().contains("-slack"))
482  || (extensionFile.getName().toLowerCase().contains("cache")) || (extensionFile.getName().toLowerCase().contains("media"))
483  || (extensionFile.getName().toLowerCase().contains("index"))) {
484  continue;
485  }
486  try {
487  ContentUtils.writeToFile(extensionFile, new File(temps), context::dataSourceIngestIsCancelled);
488  } catch (ReadContentInputStreamException ex) {
489  logger.log(Level.WARNING, String.format("Error reading Chrome web extension artifacts file '%s' (id=%d).",
490  extensionFile.getName(), extensionFile.getId()), ex); //NON-NLS
491  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errAnalyzingFile",
492  this.getDisplayName(), extensionFile.getName()));
493  continue;
494  } catch (IOException ex) {
495  logger.log(Level.SEVERE, String.format("Error writing temp file '%s' for Chrome Extensions artifacts file '%s' (id=%d).",
496  temps, extensionFile.getName(), extensionFile.getId()), ex); //NON-NLS
497  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errAnalyzingFile",
498  this.getDisplayName(), extensionFile.getName()));
499  continue;
500  }
501 
502  if (context.dataSourceIngestIsCancelled()) {
503  break;
504  }
505 
506  FileReader tempReader;
507  try {
508  tempReader = new FileReader(temps);
509  } catch (FileNotFoundException ex) {
510  logger.log(Level.WARNING, "Error while trying to read into the Secure Preferences file.", ex); //NON-NLS
511  continue;
512  }
513 
514  BlackboardArtifact.Type localStateArtifactType;
515 
516  try {
517  localStateArtifactType = createArtifactType(EXTENSIONS_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.displayName"));
518  } catch (TskCoreException ex) {
519  logger.log(Level.SEVERE, String.format("Error creating artifact type for Secure Preferences."), ex); //NON-NLS
520  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensions.errMsg.errCreateArtifact"));
521  continue;
522  }
523 
524  String profileName = FilenameUtils.getBaseName(StringUtils.chop(extensionFile.getParentPath()));
525 
526  JsonElement jsonElement;
527  JsonObject jElement, jExtensions, jSettings;
528 
529  try {
530  jsonElement = JsonParser.parseReader(tempReader);
531  jElement = jsonElement.getAsJsonObject();
532  if (jElement.has("extensions")) {
533  logger.log(Level.WARNING, String.format("Processing Secure Preferences from %s", extensionFile.getParentPath()));
534  jExtensions = jElement.get("extensions").getAsJsonObject(); //NON-NLS
535  if (!browserName.equals(OPERA_BROWSER_NAME)) {
536  jSettings = jExtensions.get("settings").getAsJsonObject();
537  } else {
538  jSettings = jExtensions.get("opsettings").getAsJsonObject();
539  }
540  } else {
541  continue;
542  }
543  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
544  logger.log(Level.WARNING, "Error parsing Json from Secure Preferences.", ex); //NON-NLS
545  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getExtensoins.errMsg.errAnalyzingFile",
546  this.getDisplayName(), extensionFile.getName()));
547  continue;
548  }
549 
550  Set<String> extensions = jSettings.keySet();
551  for (String extension : extensions) {
552  JsonElement result = jSettings.get(extension);
553  JsonObject ext = result.getAsJsonObject();
554  if (ext == null) {
555  continue;
556  }
557  JsonElement flagEl = ext.get("state"); //NON-NLS
558  String flag;
559  if (flagEl != null) {
560  if (flagEl.getAsInt() == 1) {
561  flag = "Enabled";
562  } else {
563  flag = "Disabled";
564  }
565  } else {
566  flag = "";
567  }
568  String apiGrantedPermissions = "";
569  if (ext.has("active_permissions")) {
570  JsonObject permissions = ext.get("active_permissions").getAsJsonObject();
571  JsonArray apiPermissions = permissions.get("api").getAsJsonArray();
572  for (JsonElement apiPermission : apiPermissions) {
573  String apigrantEl = apiPermission.getAsString();
574  if (apigrantEl != null) {
575  apiGrantedPermissions = apiGrantedPermissions + ", " + apigrantEl;
576  } else {
577  apiGrantedPermissions = apiGrantedPermissions + "";
578  }
579  }
580  }
581  String version;
582  String description;
583  String extName;
584  if (ext.has("manifest")) {
585  JsonObject manifest = ext.get("manifest").getAsJsonObject();
586  JsonElement descriptionEl = manifest.get("description");
587  if (descriptionEl != null) {
588  description = descriptionEl.getAsString();
589  } else {
590  description = "";
591  }
592  JsonElement versionEl = manifest.get("version");
593  if (versionEl != null) {
594  version = versionEl.getAsString();
595  } else {
596  version = "";
597  }
598  JsonElement extNameEl = manifest.get("name");
599  if (extNameEl != null) {
600  extName = extNameEl.getAsString();
601  } else {
602  extName = "";
603  }
604  } else {
605  version = "";
606  description = "";
607  extName = "";
608  }
609  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
610  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ID,
611  RecentActivityExtracterModuleFactory.getModuleName(), extension));
612  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
613  RecentActivityExtracterModuleFactory.getModuleName(), extName));
614  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
615  RecentActivityExtracterModuleFactory.getModuleName(), description));
616  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VERSION,
617  RecentActivityExtracterModuleFactory.getModuleName(), version));
618  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
619  RecentActivityExtracterModuleFactory.getModuleName(), flag));
620  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PERMISSIONS,
621  RecentActivityExtracterModuleFactory.getModuleName(), apiGrantedPermissions.replaceFirst(", ", "")));
622  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
623  RecentActivityExtracterModuleFactory.getModuleName(), userName));
624  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
625  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
626 
627  try {
628  bbartifacts.add(createArtifactWithAttributes(localStateArtifactType, extensionFile, bbattributes));
629  } catch (TskCoreException ex) {
630  logger.log(Level.SEVERE, String.format("Failed to create Extension artifact for file (%d)", extensionFile.getId()), ex);
631  }
632 
633  }
634 
635  if (!context.dataSourceIngestIsCancelled()) {
636  postArtifacts(bbartifacts);
637  }
638  bbartifacts.clear();
639 
640  }
641  }
642 
650  private void getHistory(String browser, String browserLocation, String userName, long ingestJobId) {
651  FileManager fileManager = currentCase.getServices().getFileManager();
652  String browserName = browser;
653  List<AbstractFile> historyFiles;
654  String historyFileName = HISTORY_FILE_NAME;
655  if (browserName.equals(UC_BROWSER_NAME)) {
656  historyFileName = HISTORY_FILE_NAME + "%";
657  }
658  try {
659  historyFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
660  } catch (TskCoreException ex) {
661  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errGettingFiles");
662  logger.log(Level.SEVERE, msg, ex);
663  this.addErrorMessage(this.getDisplayName() + ": " + msg);
664  return;
665  }
666 
667  // get only the allocated ones, for now
668  List<AbstractFile> allocatedHistoryFiles = new ArrayList<>();
669  for (AbstractFile historyFile : historyFiles) {
670  if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
671  allocatedHistoryFiles.add(historyFile);
672  }
673  }
674 
675  // log a message if we don't have any allocated history files
676  if (allocatedHistoryFiles.isEmpty()) {
677  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.couldntFindAnyFiles");
678  logger.log(Level.INFO, msg);
679  return;
680  }
681 
682  dataFound = true;
683  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
684  int j = 0;
685  while (j < allocatedHistoryFiles.size()) {
686  if (browser.contains(GOOGLE_PROFILE_NAME)) {
687  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedHistoryFiles.get(j).getParentPath());
688  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
689  }
690  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedHistoryFiles.get(j).getName() + j + ".db"; //NON-NLS
691  final AbstractFile historyFile = allocatedHistoryFiles.get(j++);
692  if ((historyFile.getSize() == 0) || (historyFile.getName().toLowerCase().contains("-slack"))
693  || (historyFile.getName().toLowerCase().contains("cache")) || (historyFile.getName().toLowerCase().contains("media"))
694  || (historyFile.getName().toLowerCase().contains("index"))) {
695  continue;
696  }
697  try {
698  ContentUtils.writeToFile(historyFile, new File(temps), context::dataSourceIngestIsCancelled);
699  } catch (ReadContentInputStreamException ex) {
700  logger.log(Level.WARNING, String.format("Error reading Chrome web history artifacts file '%s' (id=%d).",
701  historyFile.getName(), historyFile.getId()), ex); //NON-NLS
702  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
703  this.getDisplayName(), historyFile.getName()));
704  continue;
705  } catch (IOException ex) {
706  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
707  temps, historyFile.getName(), historyFile.getId()), ex); //NON-NLS
708  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
709  this.getDisplayName(), historyFile.getName()));
710  continue;
711  }
712  File dbFile = new File(temps);
713  if (context.dataSourceIngestIsCancelled()) {
714  dbFile.delete();
715  break;
716  }
717  List<HashMap<String, Object>> tempList;
718  tempList = this.querySQLiteDb(temps, HISTORY_QUERY);
719  logger.log(Level.INFO, "{0}- Now getting history from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
720  for (HashMap<String, Object> result : tempList) {
721  String url = result.get("url") == null ? "" : result.get("url").toString();
722  String extractedDomain = NetworkUtils.extractDomain(url);
723 
724  try {
725  Collection<BlackboardAttribute> bbattributes = createHistoryAttributes(
726  StringUtils.defaultString(url),
727  (Long.valueOf(result.get("last_visit_time").toString()) / 1000000) - Long.valueOf("11644473600"),
728  result.get("from_visit") == null ? "" : result.get("from_visit").toString(),
729  result.get("title") == null ? "" : result.get("title").toString(),
730  browserName,
731  extractedDomain,
732  userName);
733 
734  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_HISTORY, historyFile, bbattributes));
735  } catch (TskCoreException ex) {
736  logger.log(Level.SEVERE, String.format("Failed to create history artifact for file (%d)", historyFile.getId()), ex);
737  }
738  }
739  dbFile.delete();
740  }
741 
742  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
743  postArtifacts(bbartifacts);
744  }
745  }
746 
754  private void getBookmark(String browser, String browserLocation, String userName, long ingestJobId) {
755  FileManager fileManager = currentCase.getServices().getFileManager();
756  List<AbstractFile> bookmarkFiles;
757  String browserName = browser;
758  String bookmarkFileName = BOOKMARK_FILE_NAME;
759  if (browserName.equals(UC_BROWSER_NAME)) {
760  bookmarkFileName = BOOKMARK_FILE_NAME + "%";
761  }
762  try {
763  bookmarkFiles = fileManager.findFiles(dataSource, bookmarkFileName, browserLocation); //NON-NLS
764  } catch (TskCoreException ex) {
765  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errGettingFiles");
766  logger.log(Level.SEVERE, msg, ex);
767  this.addErrorMessage(this.getDisplayName() + ": " + msg);
768  return;
769  }
770 
771  if (bookmarkFiles.isEmpty()) {
772  logger.log(Level.INFO, "Didn't find any Chrome bookmark files."); //NON-NLS
773  return;
774  }
775 
776  dataFound = true;
777  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
778  int j = 0;
779  while (j < bookmarkFiles.size()) {
780  if (browser.contains(GOOGLE_PROFILE_NAME)) {
781  String parentPath = FilenameUtils.normalizeNoEndSeparator(bookmarkFiles.get(j).getParentPath());
782  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
783  }
784 
785  AbstractFile bookmarkFile = bookmarkFiles.get(j++);
786  if ((bookmarkFile.getSize() == 0) || (bookmarkFile.getName().toLowerCase().contains("-slack"))
787  || (bookmarkFile.getName().toLowerCase().contains("extras")) || (bookmarkFile.getName().toLowerCase().contains("log"))
788  || (bookmarkFile.getName().toLowerCase().contains("backup")) || (bookmarkFile.getName().toLowerCase().contains("visualized"))
789  || (bookmarkFile.getName().toLowerCase().contains("bak")) || (bookmarkFile.getParentPath().toLowerCase().contains("backup"))) {
790  continue;
791  }
792  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + bookmarkFile.getName() + j + ".db"; //NON-NLS
793  try {
794  ContentUtils.writeToFile(bookmarkFile, new File(temps), context::dataSourceIngestIsCancelled);
795  } catch (ReadContentInputStreamException ex) {
796  logger.log(Level.WARNING, String.format("Error reading Chrome bookmark artifacts file '%s' (id=%d).",
797  bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
798  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
799  this.getDisplayName(), bookmarkFile.getName()));
800  continue;
801  } catch (IOException ex) {
802  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
803  temps, bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
804  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
805  this.getDisplayName(), bookmarkFile.getName()));
806  continue;
807  }
808 
809  logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{getDisplayName(), temps}); //NON-NLS
810  File dbFile = new File(temps);
811  if (context.dataSourceIngestIsCancelled()) {
812  dbFile.delete();
813  break;
814  }
815 
816  FileReader tempReader;
817  try {
818  tempReader = new FileReader(temps);
819  } catch (FileNotFoundException ex) {
820  logger.log(Level.WARNING, "Error while trying to read into the Bookmarks for Chrome.", ex); //NON-NLS
821  continue;
822  }
823 
824  JsonElement jsonElement;
825  JsonObject jElement, jRoot;
826 
827  try {
828  jsonElement = JsonParser.parseReader(tempReader);
829  jElement = jsonElement.getAsJsonObject();
830  jRoot = jElement.get("roots").getAsJsonObject(); //NON-NLS
831  Set<String> bookmarkKeys = jRoot.keySet();
832  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
833  logger.log(Level.WARNING, "Error parsing Json from Chrome Bookmark.", ex); //NON-NLS
834  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile3",
835  this.getDisplayName(), bookmarkFile.getName()));
836  continue;
837  }
838 
839  Set<String> bookmarkKeys = jRoot.keySet();
840  for (String bookmarkKey : bookmarkKeys) {
841  JsonObject jBookmark = jRoot.get(bookmarkKey).getAsJsonObject(); //NON-NLS
842  JsonArray jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS
843  for (JsonElement result : jBookmarkArray) {
844  JsonObject address = result.getAsJsonObject();
845  if (address == null) {
846  continue;
847  }
848  JsonElement urlEl = address.get("url"); //NON-NLS
849  String url;
850  if (urlEl != null) {
851  url = urlEl.getAsString();
852  } else {
853  url = "";
854  }
855  String name;
856  JsonElement nameEl = address.get("name"); //NON-NLS
857  if (nameEl != null) {
858  name = nameEl.getAsString();
859  } else {
860  name = "";
861  }
862  Long date;
863  JsonElement dateEl = address.get("date_added"); //NON-NLS
864  if (dateEl != null) {
865  date = dateEl.getAsLong();
866  } else {
867  date = Long.valueOf(0);
868  }
869  String domain = NetworkUtils.extractDomain(url);
870  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
871  //TODO Revisit usage of deprecated constructor as per TSK-583
872  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
873  RecentActivityExtracterModuleFactory.getModuleName(), url));
874  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
875  RecentActivityExtracterModuleFactory.getModuleName(), name));
876  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
877  RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf("11644473600")));
878  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
879  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
880  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
881  RecentActivityExtracterModuleFactory.getModuleName(), domain));
882  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
883  RecentActivityExtracterModuleFactory.getModuleName(), userName));
884  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
885  RecentActivityExtracterModuleFactory.getModuleName(), bookmarkKey));
886 
887 
888  try {
889  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes));
890  } catch (TskCoreException ex) {
891  logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", bookmarkFile.getId()), ex);
892  }
893 
894  }
895  }
896 
897  if (!context.dataSourceIngestIsCancelled()) {
898  postArtifacts(bbartifacts);
899  }
900  bbartifacts.clear();
901  dbFile.delete();
902  }
903  }
904 
912  private void getCookie(String browser, String browserLocation, String userName, long ingestJobId) {
913 
914  FileManager fileManager = currentCase.getServices().getFileManager();
915  List<AbstractFile> cookiesFiles;
916  String browserName = browser;
917  String cookieFileName = COOKIE_FILE_NAME;
918  if (browserName.equals(UC_BROWSER_NAME)) {
919  // Wildcard on front and back of Cookies are there for Cookie files that start with something else
920  // ie: UC browser has "Extension Cookies.9" as well as Cookies.9
921  cookieFileName = "%" + COOKIE_FILE_NAME + "%";
922  }
923  try {
924  cookiesFiles = fileManager.findFiles(dataSource, cookieFileName, browserLocation); //NON-NLS
925  } catch (TskCoreException ex) {
926  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errGettingFiles");
927  logger.log(Level.SEVERE, msg, ex);
928  this.addErrorMessage(this.getDisplayName() + ": " + msg);
929  return;
930  }
931 
932  if (cookiesFiles.isEmpty()) {
933  logger.log(Level.INFO, "Didn't find any Chrome cookies files."); //NON-NLS
934  return;
935  }
936 
937  dataFound = true;
938  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
939  int j = 0;
940  while (j < cookiesFiles.size()) {
941  if (browser.contains(GOOGLE_PROFILE_NAME)) {
942  String parentPath = FilenameUtils.normalizeNoEndSeparator(cookiesFiles.get(j).getParentPath());
943  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
944  }
945 
946  AbstractFile cookiesFile = cookiesFiles.get(j++);
947  if ((cookiesFile.getSize() == 0) || (cookiesFile.getName().toLowerCase().contains("-slack"))) {
948  continue;
949  }
950  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + cookiesFile.getName() + j + ".db"; //NON-NLS
951  try {
952  ContentUtils.writeToFile(cookiesFile, new File(temps), context::dataSourceIngestIsCancelled);
953  } catch (ReadContentInputStreamException ex) {
954  logger.log(Level.WARNING, String.format("Error reading Chrome cookie artifacts file '%s' (id=%d).",
955  cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
956  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
957  this.getDisplayName(), cookiesFile.getName()));
958  continue;
959  } catch (IOException ex) {
960  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
961  temps, cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
962  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
963  this.getDisplayName(), cookiesFile.getName()));
964  continue;
965  }
966  File dbFile = new File(temps);
967  if (context.dataSourceIngestIsCancelled()) {
968  dbFile.delete();
969  break;
970  }
971 
972  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, COOKIE_QUERY);
973  logger.log(Level.INFO, "{0}- Now getting cookies from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
974  for (HashMap<String, Object> result : tempList) {
975  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
976  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
977  RecentActivityExtracterModuleFactory.getModuleName(),
978  ((result.get("host_key").toString() != null) ? result.get("host_key").toString() : ""))); //NON-NLS
979  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
980  RecentActivityExtracterModuleFactory.getModuleName(),
981  (Long.valueOf(result.get("last_access_utc").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
982 
983  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
984  RecentActivityExtracterModuleFactory.getModuleName(),
985  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
986  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
987  RecentActivityExtracterModuleFactory.getModuleName(),
988  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
989  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
990  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
991  String domain = result.get("host_key").toString(); //NON-NLS
992  domain = domain.replaceFirst("^\\.+(?!$)", "");
993  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
994  RecentActivityExtracterModuleFactory.getModuleName(), domain));
995  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
996  RecentActivityExtracterModuleFactory.getModuleName(), userName));
997 
998  try {
999  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_COOKIE, cookiesFile, bbattributes));
1000  } catch (TskCoreException ex) {
1001  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", cookiesFile.getId()), ex);
1002  }
1003  }
1004 
1005  dbFile.delete();
1006  }
1007 
1008  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1009  postArtifacts(bbartifacts);
1010  }
1011  }
1012 
1020  private void getDownload(String browser, String browserLocation, String userName, long ingestJobId) {
1021  FileManager fileManager = currentCase.getServices().getFileManager();
1022  List<AbstractFile> downloadFiles;
1023  String browserName = browser;
1024  String historyFileName = HISTORY_FILE_NAME;
1025  if (browserName.equals(UC_BROWSER_NAME)) {
1026  historyFileName = HISTORY_FILE_NAME + "%";
1027  }
1028  try {
1029  downloadFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
1030  } catch (TskCoreException ex) {
1031  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errGettingFiles");
1032  logger.log(Level.SEVERE, msg, ex);
1033  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1034  return;
1035  }
1036 
1037  if (downloadFiles.isEmpty()) {
1038  logger.log(Level.INFO, "Didn't find any Chrome download files."); //NON-NLS
1039  return;
1040  }
1041 
1042  dataFound = true;
1043  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1044  int j = 0;
1045  while (j < downloadFiles.size()) {
1046  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1047  String parentPath = FilenameUtils.normalizeNoEndSeparator(downloadFiles.get(j).getParentPath());
1048  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1049  }
1050 
1051  AbstractFile downloadFile = downloadFiles.get(j++);
1052  if ((downloadFile.getSize() == 0) || (downloadFile.getName().toLowerCase().contains("-slack"))
1053  || (downloadFile.getName().toLowerCase().contains("cache")) || (downloadFile.getName().toLowerCase().contains("index"))) {
1054  continue;
1055  }
1056 
1057  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + downloadFile.getName() + j + ".db"; //NON-NLS
1058  try {
1059  ContentUtils.writeToFile(downloadFile, new File(temps), context::dataSourceIngestIsCancelled);
1060  } catch (ReadContentInputStreamException ex) {
1061  logger.log(Level.WARNING, String.format("Error reading Chrome download artifacts file '%s' (id=%d).",
1062  downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1063  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1064  this.getDisplayName(), downloadFile.getName()));
1065  continue;
1066  } catch (IOException ex) {
1067  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
1068  temps, downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1069  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1070  this.getDisplayName(), downloadFile.getName()));
1071  continue;
1072  }
1073  File dbFile = new File(temps);
1074  if (context.dataSourceIngestIsCancelled()) {
1075  dbFile.delete();
1076  break;
1077  }
1078 
1079  List<HashMap<String, Object>> tempList;
1080 
1081  if (isChromePreVersion30(temps)) {
1082  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY);
1083  } else {
1084  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY_V30);
1085  }
1086 
1087  logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1088  for (HashMap<String, Object> result : tempList) {
1089  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1090  String fullPath = result.get("full_path").toString(); //NON-NLS
1091  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
1092  RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
1093  long pathID = Util.findID(dataSource, fullPath);
1094  if (pathID != -1) {
1095  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
1096  NbBundle.getMessage(this.getClass(),
1097  "Chrome.parentModuleName"), pathID));
1098  }
1099  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1100  RecentActivityExtracterModuleFactory.getModuleName(),
1101  ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
1102  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
1103  Long time = (Long.valueOf(result.get("start_time").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1104 
1105  //TODO Revisit usage of deprecated constructor as per TSK-583
1106  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
1107  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1108  RecentActivityExtracterModuleFactory.getModuleName(), time));
1109  String domain = NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
1110  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1111  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1112  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1113  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1114  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1115  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1116 
1117  // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact.
1118  try {
1119  BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
1120  bbartifacts.add(webDownloadArtifact);
1121  String normalizedFullPath = FilenameUtils.normalize(fullPath, true);
1122  for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
1123  bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact));
1124  break;
1125  }
1126  } catch (TskCoreException ex) {
1127  logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", fullPath), ex); //NON-NLS
1128  }
1129  }
1130 
1131  dbFile.delete();
1132  }
1133 
1134  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1135  postArtifacts(bbartifacts);
1136  }
1137  }
1138 
1146  private void getFavicons(String browser, String browserLocation, String userName, long ingestJobId) {
1147  FileManager fileManager = currentCase.getServices().getFileManager();
1148  List<AbstractFile> faviconFiles;
1149  String browserName = browser;
1150  try {
1151  faviconFiles = fileManager.findFiles(dataSource, FAVICON_DATA_FILE_NAME, browserLocation); //NON-NLS
1152  } catch (TskCoreException ex) {
1153  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errGettingFiles");
1154  logger.log(Level.SEVERE, msg, ex);
1155  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1156  return;
1157  }
1158 
1159  if (faviconFiles.isEmpty()) {
1160  logger.log(Level.INFO, "Didn't find any Chrome favicon files."); //NON-NLS
1161  return;
1162  }
1163 
1164  dataFound = true;
1165  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1166  int j = 0;
1167  while (j < faviconFiles.size()) {
1168  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1169  String parentPath = FilenameUtils.normalizeNoEndSeparator(faviconFiles.get(j).getParentPath());
1170  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1171  }
1172  AbstractFile faviconFile = faviconFiles.get(j++);
1173  if ((faviconFile.getSize() == 0) || (faviconFile.getName().toLowerCase().contains("-slack"))
1174  || (faviconFile.getName().toLowerCase().contains("cache")) || (faviconFile.getName().toLowerCase().contains("index"))) {
1175  continue;
1176  }
1177 
1178  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + faviconFile.getName() + j + ".db"; //NON-NLS
1179  try {
1180  ContentUtils.writeToFile(faviconFile, new File(temps), context::dataSourceIngestIsCancelled);
1181  } catch (ReadContentInputStreamException ex) {
1182  logger.log(Level.WARNING, String.format("Error reading Chrome favicons artifacts file '%s' (id=%d).",
1183  faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1184  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errAnalyzeFiles1",
1185  this.getDisplayName(), faviconFile.getName()));
1186  continue;
1187  } catch (IOException ex) {
1188  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome favicon artifacts file '%s' (id=%d).",
1189  temps, faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1190  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errAnalyzeFiles1",
1191  this.getDisplayName(), faviconFile.getName()));
1192  continue;
1193  }
1194  File dbFile = new File(temps);
1195  if (context.dataSourceIngestIsCancelled()) {
1196  dbFile.delete();
1197  break;
1198  }
1199 
1200  BlackboardArtifact.Type faviconArtifactType;
1201 
1202  try {
1203  faviconArtifactType = createArtifactType(FAVICON_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.displayName"));
1204  } catch (TskCoreException ex) {
1205  logger.log(Level.SEVERE, String.format("Error creating artifact type for Chrome favicon."), ex); //NON-NLS
1206  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errCreateArtifact"));
1207  continue;
1208 
1209  }
1210 
1211  List<HashMap<String, Object>> tempList;
1212 
1213  tempList = this.querySQLiteDb(temps, FAVICON_QUERY);
1214 
1215  logger.log(Level.INFO, "{0}- Now getting favicons from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1216  for (HashMap<String, Object> result : tempList) {
1217  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1218  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1219  RecentActivityExtracterModuleFactory.getModuleName(),
1220  ((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""))); //NON-NLS
1221  Long updatedTime = (Long.valueOf(result.get("last_updated").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1222  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1223  RecentActivityExtracterModuleFactory.getModuleName(), updatedTime));
1224  Long requestedTime = (Long.valueOf(result.get("last_requested").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1225  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1226  RecentActivityExtracterModuleFactory.getModuleName(), requestedTime));
1227  String domain = NetworkUtils.extractDomain((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""); //NON-NLS
1228  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1229  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1230  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1231  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1232  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1233  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1234 
1235  try {
1236  bbartifacts.add(createArtifactWithAttributes(faviconArtifactType, faviconFile, bbattributes));
1237  } catch (TskCoreException ex) {
1238  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", faviconFile.getId()), ex);
1239  }
1240 
1241  }
1242 
1243  dbFile.delete();
1244  }
1245 
1246  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1247  postArtifacts(bbartifacts);
1248  }
1249  }
1250 
1258  private void getLogins(String browser, String browserLocation, String userName, long ingestJobId) {
1259 
1260  FileManager fileManager = currentCase.getServices().getFileManager();
1261  List<AbstractFile> loginDataFiles;
1262  String browserName = browser;
1263  String loginDataFileName = LOGIN_DATA_FILE_NAME;
1264  if (browserName.equals(UC_BROWSER_NAME)) {
1265  loginDataFileName = LOGIN_DATA_FILE_NAME + "%";
1266  }
1267 
1268  try {
1269  loginDataFiles = fileManager.findFiles(dataSource, loginDataFileName, browserLocation); //NON-NLS
1270  } catch (TskCoreException ex) {
1271  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errGettingFiles");
1272  logger.log(Level.SEVERE, msg, ex);
1273  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1274  return;
1275  }
1276 
1277  if (loginDataFiles.isEmpty()) {
1278  logger.log(Level.INFO, "Didn't find any Chrome Login Data files."); //NON-NLS
1279  return;
1280  }
1281 
1282  dataFound = true;
1283  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1284  int j = 0;
1285  while (j < loginDataFiles.size()) {
1286  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1287  String parentPath = FilenameUtils.normalizeNoEndSeparator(loginDataFiles.get(j).getParentPath());
1288  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1289  }
1290  AbstractFile loginDataFile = loginDataFiles.get(j++);
1291  if ((loginDataFile.getSize() == 0) || (loginDataFile.getName().toLowerCase().contains("-slack"))) {
1292  continue;
1293  }
1294  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + loginDataFile.getName() + j + ".db"; //NON-NLS
1295  try {
1296  ContentUtils.writeToFile(loginDataFile, new File(temps), context::dataSourceIngestIsCancelled);
1297  } catch (ReadContentInputStreamException ex) {
1298  logger.log(Level.WARNING, String.format("Error reading Chrome login artifacts file '%s' (id=%d).",
1299  loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1300  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1301  this.getDisplayName(), loginDataFile.getName()));
1302  continue;
1303  } catch (IOException ex) {
1304  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
1305  temps, loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1306  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1307  this.getDisplayName(), loginDataFile.getName()));
1308  continue;
1309  }
1310  File dbFile = new File(temps);
1311  if (context.dataSourceIngestIsCancelled()) {
1312  dbFile.delete();
1313  break;
1314  }
1315  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, LOGIN_QUERY);
1316  logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1317  for (HashMap<String, Object> result : tempList) {
1318  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1319 
1320  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1321  RecentActivityExtracterModuleFactory.getModuleName(),
1322  ((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : ""))); //NON-NLS
1323 
1324  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1325  RecentActivityExtracterModuleFactory.getModuleName(),
1326  (Long.valueOf(result.get("date_created").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
1327 
1328  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
1329  RecentActivityExtracterModuleFactory.getModuleName(),
1330  (NetworkUtils.extractDomain((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : "")))); //NON-NLS
1331 
1332  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1333  RecentActivityExtracterModuleFactory.getModuleName(),
1334  ((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
1335 
1336  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REALM,
1337  RecentActivityExtracterModuleFactory.getModuleName(),
1338  ((result.get("signon_realm") != null && result.get("signon_realm").toString() != null) ? result.get("signon_realm").toString() : ""))); //NON-NLS
1339 
1340  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1341  RecentActivityExtracterModuleFactory.getModuleName(),
1342  result.containsKey("signon_realm") ? NetworkUtils.extractDomain(result.get("signon_realm").toString()) : "")); //NON-NLS
1343 
1344  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1345  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1346 
1347  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1348  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1349 
1350  try {
1351  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes));
1352  } catch (TskCoreException ex) {
1353  logger.log(Level.SEVERE, String.format("Failed to create service account artifact for file (%d)", loginDataFile.getId()), ex);
1354  }
1355  }
1356 
1357  dbFile.delete();
1358  }
1359 
1360  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1361  postArtifacts(bbartifacts);
1362  }
1363  }
1364 
1373  private void getAutofill(String browser, String browserLocation, String userName, long ingestJobId) {
1374 
1375  FileManager fileManager = currentCase.getServices().getFileManager();
1376  List<AbstractFile> webDataFiles;
1377  String browserName = browser;
1378  String webDataFileName = WEB_DATA_FILE_NAME;
1379  if (browserName.equals(UC_BROWSER_NAME)) {
1380  webDataFileName = WEB_DATA_FILE_NAME + "%";
1381  }
1382 
1383  try {
1384  webDataFiles = fileManager.findFiles(dataSource, webDataFileName, browserLocation); //NON-NLS
1385  } catch (TskCoreException ex) {
1386  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getAutofills.errMsg.errGettingFiles");
1387  logger.log(Level.SEVERE, msg, ex);
1388  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1389  return;
1390  }
1391 
1392  if (webDataFiles.isEmpty()) {
1393  logger.log(Level.INFO, "Didn't find any Chrome Web Data files."); //NON-NLS
1394  return;
1395  }
1396 
1397  dataFound = true;
1398  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1399  int j = 0;
1400  while (j < webDataFiles.size()) {
1401  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1402  String parentPath = FilenameUtils.normalizeNoEndSeparator(webDataFiles.get(j).getParentPath());
1403  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1404  }
1405  databaseEncrypted = false;
1406  AbstractFile webDataFile = webDataFiles.get(j++);
1407  if ((webDataFile.getSize() == 0) || (webDataFile.getName().toLowerCase().contains("-slack"))) {
1408  continue;
1409  }
1410  String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + webDataFile.getName() + j + ".db"; //NON-NLS
1411  try {
1412  ContentUtils.writeToFile(webDataFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
1413  } catch (ReadContentInputStreamException ex) {
1414  logger.log(Level.WARNING, String.format("Error reading Chrome Autofill artifacts file '%s' (id=%d).",
1415  webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1416  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getAutofill.errMsg.errAnalyzingFiles",
1417  this.getDisplayName(), webDataFile.getName()));
1418  continue;
1419  } catch (IOException ex) {
1420  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
1421  tempFilePath, webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1422  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1423  this.getDisplayName(), webDataFile.getName()));
1424  continue;
1425  }
1426  File dbFile = new File(tempFilePath);
1427  if (context.dataSourceIngestIsCancelled()) {
1428  dbFile.delete();
1429  break;
1430  }
1431 
1432  // The DB schema is little different in schema version 8x vs older versions
1433  boolean isSchemaV8X = Util.checkColumn("date_created", "autofill", tempFilePath);
1434 
1435  // get form autofill artifacts
1436  bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X, userName, browserName));
1437  try {
1438  // get form address atifacts
1439  getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
1440  if (databaseEncrypted) {
1441  String comment = String.format("%s Autofill Database Encryption Detected", browserName);
1442  Collection<BlackboardAttribute> bbattributes = Arrays.asList(
1443  new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1444  RecentActivityExtracterModuleFactory.getModuleName(), comment));
1445 
1446  bbartifacts.add(
1447  webDataFile.newAnalysisResult(
1448  BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE,
1449  null, null, comment, bbattributes).getAnalysisResult());
1450  }
1451  } catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
1452  logger.log(Level.SEVERE, String.format("Error adding artifacts to the case database "
1453  + "for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
1454  }
1455 
1456  dbFile.delete();
1457  }
1458 
1459  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1460  postArtifacts(bbartifacts);
1461  }
1462  }
1463 
1474  private Collection<BlackboardArtifact> getFormAutofillArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X, String userName, String browser) {
1475 
1476  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1477 
1478  // The DB Schema is little different in version 8x vs older versions
1479  String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
1480  : AUTOFILL_QUERY;
1481 
1482  List<HashMap<String, Object>> autofills = this.querySQLiteDb(dbFilePath, autoFillquery);
1483  logger.log(Level.INFO, "{0}- Now getting Autofill information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, autofills.size()}); //NON-NLS
1484  for (HashMap<String, Object> result : autofills) {
1485  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1486 
1487  // extract all common attributes
1488  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
1489  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1490  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
1491 
1492  fieldEncrypted = false;
1493  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
1494  RecentActivityExtracterModuleFactory.getModuleName(),
1495  processFields(result.get("value")))); //NON-NLS
1496 
1497  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
1498  RecentActivityExtracterModuleFactory.getModuleName(),
1499  (Integer.valueOf(result.get("count").toString())))); //NON-NLS
1500 
1501  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1502  RecentActivityExtracterModuleFactory.getModuleName(),
1503  Long.valueOf(result.get("date_created").toString()))); //NON-NLS
1504 
1505  // get schema version specific attributes
1506  if (isSchemaV8X) {
1507  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1508  RecentActivityExtracterModuleFactory.getModuleName(),
1509  Long.valueOf(result.get("date_last_used").toString()))); //NON-NLS
1510  }
1511 
1512  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1513  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1514  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1515  RecentActivityExtracterModuleFactory.getModuleName(), browser));
1516  if (fieldEncrypted) {
1517  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1518  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE));
1519  }
1520 
1521  // Add an artifact
1522  try {
1523  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes));
1524  } catch (TskCoreException ex) {
1525  logger.log(Level.SEVERE, String.format("Failed to create web form autopfill artifact for file (%d)", webDataFile.getId()), ex);
1526  }
1527  }
1528 
1529  // return all extracted artifacts
1530  return bbartifacts;
1531  }
1532 
1544  private void getFormAddressArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X) throws NoCurrentCaseException,
1545  TskCoreException, Blackboard.BlackboardException {
1546 
1547  String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
1548  : WEBFORM_ADDRESS_QUERY;
1549 
1550  // Helper to create web form address artifacts.
1551  WebBrowserArtifactsHelper helper = new WebBrowserArtifactsHelper(
1552  Case.getCurrentCaseThrows().getSleuthkitCase(),
1553  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1554  webDataFile, context.getJobId()
1555  );
1556 
1557  // Get Web form addresses
1558  List<HashMap<String, Object>> addresses = this.querySQLiteDb(dbFilePath, webformAddressQuery);
1559  logger.log(Level.INFO, "{0}- Now getting Web form addresses from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, addresses.size()}); //NON-NLS
1560  for (HashMap<String, Object> result : addresses) {
1561 
1562  fieldEncrypted = false;
1563 
1564  String first_name = processFields(result.get("first_name"));
1565  String middle_name = processFields(result.get("middle_name"));
1566  String last_name = processFields(result.get("last_name"));
1567 
1568  // get email and phone
1569  String email_Addr = processFields(result.get("email"));
1570  String phone_number = processFields(result.get("number"));
1571 
1572  // Get the address fields
1573  String city = processFields(result.get("city"));
1574  String state = processFields(result.get("state"));
1575  String zipcode = processFields(result.get("zipcode"));
1576  String country_code = processFields(result.get("country_code"));
1577 
1578  // schema version specific fields
1579  String full_name = "";
1580  String street_address = "";
1581  long date_modified = 0;
1582  int use_count = 0;
1583  long use_date = 0;
1584 
1585  if (isSchemaV8X) {
1586 
1587  full_name = processFields(result.get("full_name"));
1588  street_address = processFields(result.get("street_address"));
1589  date_modified = result.get("date_modified").toString() != null ? Long.valueOf(result.get("date_modified").toString()) : 0;
1590  use_count = result.get("use_count").toString() != null ? Integer.valueOf(result.get("use_count").toString()) : 0;
1591  use_date = result.get("use_date").toString() != null ? Long.valueOf(result.get("use_date").toString()) : 0;
1592  } else {
1593  String address_line_1 = processFields(result.get("address_line_1"));
1594  String address_line_2 = processFields(result.get("address_line_2"));
1595  street_address = String.join(" ", address_line_1, address_line_2);
1596  }
1597 
1598  // Create atrributes from extracted fields
1599  if (full_name == null || full_name.isEmpty()) {
1600  full_name = String.join(" ", first_name, middle_name, last_name);
1601  }
1602 
1603  String locationAddress = String.join(", ", street_address, city, state, zipcode, country_code);
1604 
1605  List<BlackboardAttribute> otherAttributes = new ArrayList<>();
1606  if (date_modified > 0) {
1607  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1608  RecentActivityExtracterModuleFactory.getModuleName(),
1609  date_modified)); //NON-NLS
1610  if (fieldEncrypted) {
1611  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1612  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE)); //NON-NLS
1613 
1614  }
1615  }
1616 
1617  helper.addWebFormAddress(
1618  full_name, email_Addr, phone_number,
1619  locationAddress, 0, use_date,
1620  use_count, otherAttributes);
1621  }
1622  }
1623 
1633  private String processFields(Object dataValue) {
1634 
1635  if (dataValue instanceof byte[]) {
1636  fieldEncrypted = true;
1637  databaseEncrypted = true;
1638  }
1639 
1640  return dataValue.toString() != null ? dataValue.toString() : "";
1641 
1642  }
1643 
1644  private boolean isChromePreVersion30(String temps) {
1645  String query = "PRAGMA table_info(downloads)"; //NON-NLS
1646  List<HashMap<String, Object>> columns = this.querySQLiteDb(temps, query);
1647  for (HashMap<String, Object> col : columns) {
1648  if (col.get("name").equals("url")) { //NON-NLS
1649  return true;
1650  }
1651  }
1652 
1653  return false;
1654  }
1655 
1656  @Messages({
1657  "ExtractFavicon_Display_Name=Favicon"
1658  })
1665  private BlackboardArtifact.Type createArtifactType(String artifactName, String displayName) throws TskCoreException {
1666  BlackboardArtifact.Type faviconArtifactType;
1667  try {
1668  faviconArtifactType = tskCase.getBlackboard().getOrAddArtifactType(artifactName, displayName); //NON-NLS
1669  } catch (Blackboard.BlackboardException ex) {
1670  throw new TskCoreException(String.format("An exception was thrown while defining artifact type %s", artifactName), ex);
1671  }
1672  return faviconArtifactType;
1673  }
1674 
1675 }

Copyright © 2012-2022 Basis Technology. Generated on: Tue Sep 27 2022
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.