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  if (apiPermission.isJsonPrimitive()) {
574  String apigrantEl = apiPermission.getAsString();
575  if (apigrantEl != null) {
576  apiGrantedPermissions = apiGrantedPermissions + ", " + apigrantEl;
577  } else {
578  apiGrantedPermissions = apiGrantedPermissions + "";
579  }
580  }
581  }
582  }
583  String version;
584  String description;
585  String extName;
586  if (ext.has("manifest")) {
587  JsonObject manifest = ext.get("manifest").getAsJsonObject();
588  JsonElement descriptionEl = manifest.get("description");
589  if (descriptionEl != null) {
590  description = descriptionEl.getAsString();
591  } else {
592  description = "";
593  }
594  JsonElement versionEl = manifest.get("version");
595  if (versionEl != null) {
596  version = versionEl.getAsString();
597  } else {
598  version = "";
599  }
600  JsonElement extNameEl = manifest.get("name");
601  if (extNameEl != null) {
602  extName = extNameEl.getAsString();
603  } else {
604  extName = "";
605  }
606  } else {
607  version = "";
608  description = "";
609  extName = "";
610  }
611  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
612  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_ID,
613  RecentActivityExtracterModuleFactory.getModuleName(), extension));
614  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
615  RecentActivityExtracterModuleFactory.getModuleName(), extName));
616  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DESCRIPTION,
617  RecentActivityExtracterModuleFactory.getModuleName(), description));
618  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VERSION,
619  RecentActivityExtracterModuleFactory.getModuleName(), version));
620  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_FLAG,
621  RecentActivityExtracterModuleFactory.getModuleName(), flag));
622  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PERMISSIONS,
623  RecentActivityExtracterModuleFactory.getModuleName(), apiGrantedPermissions.replaceFirst(", ", "")));
624  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
625  RecentActivityExtracterModuleFactory.getModuleName(), userName));
626  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
627  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
628 
629  try {
630  bbartifacts.add(createArtifactWithAttributes(localStateArtifactType, extensionFile, bbattributes));
631  } catch (TskCoreException ex) {
632  logger.log(Level.SEVERE, String.format("Failed to create Extension artifact for file (%d)", extensionFile.getId()), ex);
633  }
634 
635  }
636 
637  if (!context.dataSourceIngestIsCancelled()) {
638  postArtifacts(bbartifacts);
639  }
640  bbartifacts.clear();
641 
642  }
643  }
644 
652  private void getHistory(String browser, String browserLocation, String userName, long ingestJobId) {
653  FileManager fileManager = currentCase.getServices().getFileManager();
654  String browserName = browser;
655  List<AbstractFile> historyFiles;
656  String historyFileName = HISTORY_FILE_NAME;
657  if (browserName.equals(UC_BROWSER_NAME)) {
658  historyFileName = HISTORY_FILE_NAME + "%";
659  }
660  try {
661  historyFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
662  } catch (TskCoreException ex) {
663  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errGettingFiles");
664  logger.log(Level.SEVERE, msg, ex);
665  this.addErrorMessage(this.getDisplayName() + ": " + msg);
666  return;
667  }
668 
669  // get only the allocated ones, for now
670  List<AbstractFile> allocatedHistoryFiles = new ArrayList<>();
671  for (AbstractFile historyFile : historyFiles) {
672  if (historyFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
673  allocatedHistoryFiles.add(historyFile);
674  }
675  }
676 
677  // log a message if we don't have any allocated history files
678  if (allocatedHistoryFiles.isEmpty()) {
679  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.couldntFindAnyFiles");
680  logger.log(Level.INFO, msg);
681  return;
682  }
683 
684  dataFound = true;
685  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
686  int j = 0;
687  while (j < allocatedHistoryFiles.size()) {
688  if (browser.contains(GOOGLE_PROFILE_NAME)) {
689  String parentPath = FilenameUtils.normalizeNoEndSeparator(allocatedHistoryFiles.get(j).getParentPath());
690  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
691  }
692  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + allocatedHistoryFiles.get(j).getName() + j + ".db"; //NON-NLS
693  final AbstractFile historyFile = allocatedHistoryFiles.get(j++);
694  if ((historyFile.getSize() == 0) || (historyFile.getName().toLowerCase().contains("-slack"))
695  || (historyFile.getName().toLowerCase().contains("cache")) || (historyFile.getName().toLowerCase().contains("media"))
696  || (historyFile.getName().toLowerCase().contains("index"))) {
697  continue;
698  }
699  try {
700  ContentUtils.writeToFile(historyFile, new File(temps), context::dataSourceIngestIsCancelled);
701  } catch (ReadContentInputStreamException ex) {
702  logger.log(Level.WARNING, String.format("Error reading Chrome web history artifacts file '%s' (id=%d).",
703  historyFile.getName(), historyFile.getId()), ex); //NON-NLS
704  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
705  this.getDisplayName(), historyFile.getName()));
706  continue;
707  } catch (IOException ex) {
708  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome web history artifacts file '%s' (id=%d).",
709  temps, historyFile.getName(), historyFile.getId()), ex); //NON-NLS
710  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
711  this.getDisplayName(), historyFile.getName()));
712  continue;
713  }
714  File dbFile = new File(temps);
715  if (context.dataSourceIngestIsCancelled()) {
716  dbFile.delete();
717  break;
718  }
719  List<HashMap<String, Object>> tempList;
720  tempList = this.querySQLiteDb(temps, HISTORY_QUERY);
721  logger.log(Level.INFO, "{0}- Now getting history from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
722  for (HashMap<String, Object> result : tempList) {
723  String url = result.get("url") == null ? "" : result.get("url").toString();
724  String extractedDomain = NetworkUtils.extractDomain(url);
725 
726  try {
727  Collection<BlackboardAttribute> bbattributes = createHistoryAttributes(
728  StringUtils.defaultString(url),
729  (Long.valueOf(result.get("last_visit_time").toString()) / 1000000) - Long.valueOf("11644473600"),
730  result.get("from_visit") == null ? "" : result.get("from_visit").toString(),
731  result.get("title") == null ? "" : result.get("title").toString(),
732  browserName,
733  extractedDomain,
734  userName);
735 
736  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_HISTORY, historyFile, bbattributes));
737  } catch (TskCoreException ex) {
738  logger.log(Level.SEVERE, String.format("Failed to create history artifact for file (%d)", historyFile.getId()), ex);
739  }
740  }
741  dbFile.delete();
742  }
743 
744  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
745  postArtifacts(bbartifacts);
746  }
747  }
748 
756  private void getBookmark(String browser, String browserLocation, String userName, long ingestJobId) {
757  FileManager fileManager = currentCase.getServices().getFileManager();
758  List<AbstractFile> bookmarkFiles;
759  String browserName = browser;
760  String bookmarkFileName = BOOKMARK_FILE_NAME;
761  if (browserName.equals(UC_BROWSER_NAME)) {
762  bookmarkFileName = BOOKMARK_FILE_NAME + "%";
763  }
764  try {
765  bookmarkFiles = fileManager.findFiles(dataSource, bookmarkFileName, browserLocation); //NON-NLS
766  } catch (TskCoreException ex) {
767  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errGettingFiles");
768  logger.log(Level.SEVERE, msg, ex);
769  this.addErrorMessage(this.getDisplayName() + ": " + msg);
770  return;
771  }
772 
773  if (bookmarkFiles.isEmpty()) {
774  logger.log(Level.INFO, "Didn't find any Chrome bookmark files."); //NON-NLS
775  return;
776  }
777 
778  dataFound = true;
779  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
780  int j = 0;
781  while (j < bookmarkFiles.size()) {
782  if (browser.contains(GOOGLE_PROFILE_NAME)) {
783  String parentPath = FilenameUtils.normalizeNoEndSeparator(bookmarkFiles.get(j).getParentPath());
784  browserName = GOOGLE_PROFILE + " " + FilenameUtils.getBaseName(parentPath);
785  }
786 
787  AbstractFile bookmarkFile = bookmarkFiles.get(j++);
788  if ((bookmarkFile.getSize() == 0) || (bookmarkFile.getName().toLowerCase().contains("-slack"))
789  || (bookmarkFile.getName().toLowerCase().contains("extras")) || (bookmarkFile.getName().toLowerCase().contains("log"))
790  || (bookmarkFile.getName().toLowerCase().contains("backup")) || (bookmarkFile.getName().toLowerCase().contains("visualized"))
791  || (bookmarkFile.getName().toLowerCase().contains("bak")) || (bookmarkFile.getParentPath().toLowerCase().contains("backup"))) {
792  continue;
793  }
794  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + bookmarkFile.getName() + j + ".db"; //NON-NLS
795  try {
796  ContentUtils.writeToFile(bookmarkFile, new File(temps), context::dataSourceIngestIsCancelled);
797  } catch (ReadContentInputStreamException ex) {
798  logger.log(Level.WARNING, String.format("Error reading Chrome bookmark artifacts file '%s' (id=%d).",
799  bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
800  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
801  this.getDisplayName(), bookmarkFile.getName()));
802  continue;
803  } catch (IOException ex) {
804  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome bookmark artifacts file '%s' (id=%d).",
805  temps, bookmarkFile.getName(), bookmarkFile.getId()), ex); //NON-NLS
806  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
807  this.getDisplayName(), bookmarkFile.getName()));
808  continue;
809  }
810 
811  logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{getDisplayName(), temps}); //NON-NLS
812  File dbFile = new File(temps);
813  if (context.dataSourceIngestIsCancelled()) {
814  dbFile.delete();
815  break;
816  }
817 
818  FileReader tempReader;
819  try {
820  tempReader = new FileReader(temps);
821  } catch (FileNotFoundException ex) {
822  logger.log(Level.WARNING, "Error while trying to read into the Bookmarks for Chrome.", ex); //NON-NLS
823  continue;
824  }
825 
826  JsonElement jsonElement;
827  JsonObject jElement, jRoot;
828 
829  try {
830  jsonElement = JsonParser.parseReader(tempReader);
831  jElement = jsonElement.getAsJsonObject();
832  jRoot = jElement.get("roots").getAsJsonObject(); //NON-NLS
833  Set<String> bookmarkKeys = jRoot.keySet();
834  } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
835  logger.log(Level.WARNING, "Error parsing Json from Chrome Bookmark.", ex); //NON-NLS
836  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile3",
837  this.getDisplayName(), bookmarkFile.getName()));
838  continue;
839  }
840 
841  Set<String> bookmarkKeys = jRoot.keySet();
842  for (String bookmarkKey : bookmarkKeys) {
843  JsonObject jBookmark = jRoot.get(bookmarkKey).getAsJsonObject(); //NON-NLS
844  JsonArray jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS
845  for (JsonElement result : jBookmarkArray) {
846  JsonObject address = result.getAsJsonObject();
847  if (address == null) {
848  continue;
849  }
850  JsonElement urlEl = address.get("url"); //NON-NLS
851  String url;
852  if (urlEl != null) {
853  url = urlEl.getAsString();
854  } else {
855  url = "";
856  }
857  String name;
858  JsonElement nameEl = address.get("name"); //NON-NLS
859  if (nameEl != null) {
860  name = nameEl.getAsString();
861  } else {
862  name = "";
863  }
864  Long date;
865  JsonElement dateEl = address.get("date_added"); //NON-NLS
866  if (dateEl != null) {
867  date = dateEl.getAsLong();
868  } else {
869  date = Long.valueOf(0);
870  }
871  String domain = NetworkUtils.extractDomain(url);
872  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
873  //TODO Revisit usage of deprecated constructor as per TSK-583
874  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
875  RecentActivityExtracterModuleFactory.getModuleName(), url));
876  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
877  RecentActivityExtracterModuleFactory.getModuleName(), name));
878  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
879  RecentActivityExtracterModuleFactory.getModuleName(), (date / 1000000) - Long.valueOf("11644473600")));
880  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
881  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
882  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
883  RecentActivityExtracterModuleFactory.getModuleName(), domain));
884  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
885  RecentActivityExtracterModuleFactory.getModuleName(), userName));
886  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
887  RecentActivityExtracterModuleFactory.getModuleName(), bookmarkKey));
888 
889 
890  try {
891  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes));
892  } catch (TskCoreException ex) {
893  logger.log(Level.SEVERE, String.format("Failed to create bookmark artifact for file (%d)", bookmarkFile.getId()), ex);
894  }
895 
896  }
897  }
898 
899  if (!context.dataSourceIngestIsCancelled()) {
900  postArtifacts(bbartifacts);
901  }
902  bbartifacts.clear();
903  dbFile.delete();
904  }
905  }
906 
914  private void getCookie(String browser, String browserLocation, String userName, long ingestJobId) {
915 
916  FileManager fileManager = currentCase.getServices().getFileManager();
917  List<AbstractFile> cookiesFiles;
918  String browserName = browser;
919  String cookieFileName = COOKIE_FILE_NAME;
920  if (browserName.equals(UC_BROWSER_NAME)) {
921  // Wildcard on front and back of Cookies are there for Cookie files that start with something else
922  // ie: UC browser has "Extension Cookies.9" as well as Cookies.9
923  cookieFileName = "%" + COOKIE_FILE_NAME + "%";
924  }
925  try {
926  cookiesFiles = fileManager.findFiles(dataSource, cookieFileName, browserLocation); //NON-NLS
927  } catch (TskCoreException ex) {
928  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errGettingFiles");
929  logger.log(Level.SEVERE, msg, ex);
930  this.addErrorMessage(this.getDisplayName() + ": " + msg);
931  return;
932  }
933 
934  if (cookiesFiles.isEmpty()) {
935  logger.log(Level.INFO, "Didn't find any Chrome cookies files."); //NON-NLS
936  return;
937  }
938 
939  dataFound = true;
940  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
941  int j = 0;
942  while (j < cookiesFiles.size()) {
943  if (browser.contains(GOOGLE_PROFILE_NAME)) {
944  String parentPath = FilenameUtils.normalizeNoEndSeparator(cookiesFiles.get(j).getParentPath());
945  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
946  }
947 
948  AbstractFile cookiesFile = cookiesFiles.get(j++);
949  if ((cookiesFile.getSize() == 0) || (cookiesFile.getName().toLowerCase().contains("-slack"))) {
950  continue;
951  }
952  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + cookiesFile.getName() + j + ".db"; //NON-NLS
953  try {
954  ContentUtils.writeToFile(cookiesFile, new File(temps), context::dataSourceIngestIsCancelled);
955  } catch (ReadContentInputStreamException ex) {
956  logger.log(Level.WARNING, String.format("Error reading Chrome cookie artifacts file '%s' (id=%d).",
957  cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
958  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
959  this.getDisplayName(), cookiesFile.getName()));
960  continue;
961  } catch (IOException ex) {
962  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome cookie artifacts file '%s' (id=%d).",
963  temps, cookiesFile.getName(), cookiesFile.getId()), ex); //NON-NLS
964  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile",
965  this.getDisplayName(), cookiesFile.getName()));
966  continue;
967  }
968  File dbFile = new File(temps);
969  if (context.dataSourceIngestIsCancelled()) {
970  dbFile.delete();
971  break;
972  }
973 
974  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, COOKIE_QUERY);
975  logger.log(Level.INFO, "{0}- Now getting cookies from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
976  for (HashMap<String, Object> result : tempList) {
977  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
978  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
979  RecentActivityExtracterModuleFactory.getModuleName(),
980  ((result.get("host_key").toString() != null) ? result.get("host_key").toString() : ""))); //NON-NLS
981  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
982  RecentActivityExtracterModuleFactory.getModuleName(),
983  (Long.valueOf(result.get("last_access_utc").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
984 
985  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
986  RecentActivityExtracterModuleFactory.getModuleName(),
987  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
988  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
989  RecentActivityExtracterModuleFactory.getModuleName(),
990  ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
991  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
992  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
993  String domain = result.get("host_key").toString(); //NON-NLS
994  domain = domain.replaceFirst("^\\.+(?!$)", "");
995  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
996  RecentActivityExtracterModuleFactory.getModuleName(), domain));
997  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
998  RecentActivityExtracterModuleFactory.getModuleName(), userName));
999 
1000  try {
1001  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_COOKIE, cookiesFile, bbattributes));
1002  } catch (TskCoreException ex) {
1003  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", cookiesFile.getId()), ex);
1004  }
1005  }
1006 
1007  dbFile.delete();
1008  }
1009 
1010  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1011  postArtifacts(bbartifacts);
1012  }
1013  }
1014 
1022  private void getDownload(String browser, String browserLocation, String userName, long ingestJobId) {
1023  FileManager fileManager = currentCase.getServices().getFileManager();
1024  List<AbstractFile> downloadFiles;
1025  String browserName = browser;
1026  String historyFileName = HISTORY_FILE_NAME;
1027  if (browserName.equals(UC_BROWSER_NAME)) {
1028  historyFileName = HISTORY_FILE_NAME + "%";
1029  }
1030  try {
1031  downloadFiles = fileManager.findFiles(dataSource, historyFileName, browserLocation); //NON-NLS
1032  } catch (TskCoreException ex) {
1033  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errGettingFiles");
1034  logger.log(Level.SEVERE, msg, ex);
1035  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1036  return;
1037  }
1038 
1039  if (downloadFiles.isEmpty()) {
1040  logger.log(Level.INFO, "Didn't find any Chrome download files."); //NON-NLS
1041  return;
1042  }
1043 
1044  dataFound = true;
1045  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1046  int j = 0;
1047  while (j < downloadFiles.size()) {
1048  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1049  String parentPath = FilenameUtils.normalizeNoEndSeparator(downloadFiles.get(j).getParentPath());
1050  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1051  }
1052 
1053  AbstractFile downloadFile = downloadFiles.get(j++);
1054  if ((downloadFile.getSize() == 0) || (downloadFile.getName().toLowerCase().contains("-slack"))
1055  || (downloadFile.getName().toLowerCase().contains("cache")) || (downloadFile.getName().toLowerCase().contains("index"))) {
1056  continue;
1057  }
1058 
1059  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + downloadFile.getName() + j + ".db"; //NON-NLS
1060  try {
1061  ContentUtils.writeToFile(downloadFile, new File(temps), context::dataSourceIngestIsCancelled);
1062  } catch (ReadContentInputStreamException ex) {
1063  logger.log(Level.WARNING, String.format("Error reading Chrome download artifacts file '%s' (id=%d).",
1064  downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1065  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1066  this.getDisplayName(), downloadFile.getName()));
1067  continue;
1068  } catch (IOException ex) {
1069  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome download artifacts file '%s' (id=%d).",
1070  temps, downloadFile.getName(), downloadFile.getId()), ex); //NON-NLS
1071  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
1072  this.getDisplayName(), downloadFile.getName()));
1073  continue;
1074  }
1075  File dbFile = new File(temps);
1076  if (context.dataSourceIngestIsCancelled()) {
1077  dbFile.delete();
1078  break;
1079  }
1080 
1081  List<HashMap<String, Object>> tempList;
1082 
1083  if (isChromePreVersion30(temps)) {
1084  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY);
1085  } else {
1086  tempList = this.querySQLiteDb(temps, DOWNLOAD_QUERY_V30);
1087  }
1088 
1089  logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1090  for (HashMap<String, Object> result : tempList) {
1091  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1092  String fullPath = result.get("full_path").toString(); //NON-NLS
1093  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
1094  RecentActivityExtracterModuleFactory.getModuleName(), fullPath));
1095  long pathID = Util.findID(dataSource, fullPath);
1096  if (pathID != -1) {
1097  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
1098  NbBundle.getMessage(this.getClass(),
1099  "Chrome.parentModuleName"), pathID));
1100  }
1101  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1102  RecentActivityExtracterModuleFactory.getModuleName(),
1103  ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
1104  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
1105  Long time = (Long.valueOf(result.get("start_time").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1106 
1107  //TODO Revisit usage of deprecated constructor as per TSK-583
1108  //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
1109  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1110  RecentActivityExtracterModuleFactory.getModuleName(), time));
1111  String domain = NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
1112  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1113  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1114  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1115  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1116  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1117  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1118 
1119  // find the downloaded file and create a TSK_ASSOCIATED_OBJECT for it, associating it with the TSK_WEB_DOWNLOAD artifact.
1120  try {
1121  BlackboardArtifact webDownloadArtifact = createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_DOWNLOAD, downloadFile, bbattributes);
1122  bbartifacts.add(webDownloadArtifact);
1123  String normalizedFullPath = FilenameUtils.normalize(fullPath, true);
1124  for (AbstractFile downloadedFile : currentCase.getSleuthkitCase().getFileManager().findFilesExactNameExactPath(dataSource, FilenameUtils.getName(normalizedFullPath), FilenameUtils.getPath(normalizedFullPath))) {
1125  bbartifacts.add(createAssociatedArtifact(downloadedFile, webDownloadArtifact));
1126  break;
1127  }
1128  } catch (TskCoreException ex) {
1129  logger.log(Level.SEVERE, String.format("Error creating associated object artifact for file '%s'", fullPath), ex); //NON-NLS
1130  }
1131  }
1132 
1133  dbFile.delete();
1134  }
1135 
1136  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1137  postArtifacts(bbartifacts);
1138  }
1139  }
1140 
1148  private void getFavicons(String browser, String browserLocation, String userName, long ingestJobId) {
1149  FileManager fileManager = currentCase.getServices().getFileManager();
1150  List<AbstractFile> faviconFiles;
1151  String browserName = browser;
1152  try {
1153  faviconFiles = fileManager.findFiles(dataSource, FAVICON_DATA_FILE_NAME, browserLocation); //NON-NLS
1154  } catch (TskCoreException ex) {
1155  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errGettingFiles");
1156  logger.log(Level.SEVERE, msg, ex);
1157  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1158  return;
1159  }
1160 
1161  if (faviconFiles.isEmpty()) {
1162  logger.log(Level.INFO, "Didn't find any Chrome favicon files."); //NON-NLS
1163  return;
1164  }
1165 
1166  dataFound = true;
1167  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1168  int j = 0;
1169  while (j < faviconFiles.size()) {
1170  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1171  String parentPath = FilenameUtils.normalizeNoEndSeparator(faviconFiles.get(j).getParentPath());
1172  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1173  }
1174  AbstractFile faviconFile = faviconFiles.get(j++);
1175  if ((faviconFile.getSize() == 0) || (faviconFile.getName().toLowerCase().contains("-slack"))
1176  || (faviconFile.getName().toLowerCase().contains("cache")) || (faviconFile.getName().toLowerCase().contains("index"))) {
1177  continue;
1178  }
1179 
1180  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + faviconFile.getName() + j + ".db"; //NON-NLS
1181  try {
1182  ContentUtils.writeToFile(faviconFile, new File(temps), context::dataSourceIngestIsCancelled);
1183  } catch (ReadContentInputStreamException ex) {
1184  logger.log(Level.WARNING, String.format("Error reading Chrome favicons artifacts file '%s' (id=%d).",
1185  faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1186  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.errMsg.errAnalyzeFiles1",
1187  this.getDisplayName(), faviconFile.getName()));
1188  continue;
1189  } catch (IOException ex) {
1190  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome favicon artifacts file '%s' (id=%d).",
1191  temps, faviconFile.getName(), faviconFile.getId()), ex); //NON-NLS
1192  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errAnalyzeFiles1",
1193  this.getDisplayName(), faviconFile.getName()));
1194  continue;
1195  }
1196  File dbFile = new File(temps);
1197  if (context.dataSourceIngestIsCancelled()) {
1198  dbFile.delete();
1199  break;
1200  }
1201 
1202  BlackboardArtifact.Type faviconArtifactType;
1203 
1204  try {
1205  faviconArtifactType = createArtifactType(FAVICON_ARTIFACT_NAME, NbBundle.getMessage(this.getClass(), "Chrome.getFavicon.displayName"));
1206  } catch (TskCoreException ex) {
1207  logger.log(Level.SEVERE, String.format("Error creating artifact type for Chrome favicon."), ex); //NON-NLS
1208  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getfavicon.errMsg.errCreateArtifact"));
1209  continue;
1210 
1211  }
1212 
1213  List<HashMap<String, Object>> tempList;
1214 
1215  tempList = this.querySQLiteDb(temps, FAVICON_QUERY);
1216 
1217  logger.log(Level.INFO, "{0}- Now getting favicons from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1218  for (HashMap<String, Object> result : tempList) {
1219  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1220  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1221  RecentActivityExtracterModuleFactory.getModuleName(),
1222  ((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""))); //NON-NLS
1223  Long updatedTime = (Long.valueOf(result.get("last_updated").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1224  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1225  RecentActivityExtracterModuleFactory.getModuleName(), updatedTime));
1226  Long requestedTime = (Long.valueOf(result.get("last_requested").toString()) / 1000000) - Long.valueOf("11644473600"); //NON-NLS
1227  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1228  RecentActivityExtracterModuleFactory.getModuleName(), requestedTime));
1229  String domain = NetworkUtils.extractDomain((result.get("page_url").toString() != null) ? result.get("page_url").toString() : ""); //NON-NLS
1230  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1231  RecentActivityExtracterModuleFactory.getModuleName(), domain));
1232  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1233  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1234  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1235  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1236 
1237  try {
1238  bbartifacts.add(createArtifactWithAttributes(faviconArtifactType, faviconFile, bbattributes));
1239  } catch (TskCoreException ex) {
1240  logger.log(Level.SEVERE, String.format("Failed to create cookie artifact for file (%d)", faviconFile.getId()), ex);
1241  }
1242 
1243  }
1244 
1245  dbFile.delete();
1246  }
1247 
1248  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1249  postArtifacts(bbartifacts);
1250  }
1251  }
1252 
1260  private void getLogins(String browser, String browserLocation, String userName, long ingestJobId) {
1261 
1262  FileManager fileManager = currentCase.getServices().getFileManager();
1263  List<AbstractFile> loginDataFiles;
1264  String browserName = browser;
1265  String loginDataFileName = LOGIN_DATA_FILE_NAME;
1266  if (browserName.equals(UC_BROWSER_NAME)) {
1267  loginDataFileName = LOGIN_DATA_FILE_NAME + "%";
1268  }
1269 
1270  try {
1271  loginDataFiles = fileManager.findFiles(dataSource, loginDataFileName, browserLocation); //NON-NLS
1272  } catch (TskCoreException ex) {
1273  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errGettingFiles");
1274  logger.log(Level.SEVERE, msg, ex);
1275  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1276  return;
1277  }
1278 
1279  if (loginDataFiles.isEmpty()) {
1280  logger.log(Level.INFO, "Didn't find any Chrome Login Data files."); //NON-NLS
1281  return;
1282  }
1283 
1284  dataFound = true;
1285  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1286  int j = 0;
1287  while (j < loginDataFiles.size()) {
1288  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1289  String parentPath = FilenameUtils.normalizeNoEndSeparator(loginDataFiles.get(j).getParentPath());
1290  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1291  }
1292  AbstractFile loginDataFile = loginDataFiles.get(j++);
1293  if ((loginDataFile.getSize() == 0) || (loginDataFile.getName().toLowerCase().contains("-slack"))) {
1294  continue;
1295  }
1296  String temps = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + loginDataFile.getName() + j + ".db"; //NON-NLS
1297  try {
1298  ContentUtils.writeToFile(loginDataFile, new File(temps), context::dataSourceIngestIsCancelled);
1299  } catch (ReadContentInputStreamException ex) {
1300  logger.log(Level.WARNING, String.format("Error reading Chrome login artifacts file '%s' (id=%d).",
1301  loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1302  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1303  this.getDisplayName(), loginDataFile.getName()));
1304  continue;
1305  } catch (IOException ex) {
1306  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
1307  temps, loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
1308  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1309  this.getDisplayName(), loginDataFile.getName()));
1310  continue;
1311  }
1312  File dbFile = new File(temps);
1313  if (context.dataSourceIngestIsCancelled()) {
1314  dbFile.delete();
1315  break;
1316  }
1317  List<HashMap<String, Object>> tempList = this.querySQLiteDb(temps, LOGIN_QUERY);
1318  logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), temps, tempList.size()}); //NON-NLS
1319  for (HashMap<String, Object> result : tempList) {
1320  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1321 
1322  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
1323  RecentActivityExtracterModuleFactory.getModuleName(),
1324  ((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : ""))); //NON-NLS
1325 
1326  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1327  RecentActivityExtracterModuleFactory.getModuleName(),
1328  (Long.valueOf(result.get("date_created").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
1329 
1330  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
1331  RecentActivityExtracterModuleFactory.getModuleName(),
1332  (NetworkUtils.extractDomain((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : "")))); //NON-NLS
1333 
1334  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1335  RecentActivityExtracterModuleFactory.getModuleName(),
1336  ((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
1337 
1338  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REALM,
1339  RecentActivityExtracterModuleFactory.getModuleName(),
1340  ((result.get("signon_realm") != null && result.get("signon_realm").toString() != null) ? result.get("signon_realm").toString() : ""))); //NON-NLS
1341 
1342  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
1343  RecentActivityExtracterModuleFactory.getModuleName(),
1344  result.containsKey("signon_realm") ? NetworkUtils.extractDomain(result.get("signon_realm").toString()) : "")); //NON-NLS
1345 
1346  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1347  RecentActivityExtracterModuleFactory.getModuleName(), browserName));
1348 
1349  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1350  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1351 
1352  try {
1353  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes));
1354  } catch (TskCoreException ex) {
1355  logger.log(Level.SEVERE, String.format("Failed to create service account artifact for file (%d)", loginDataFile.getId()), ex);
1356  }
1357  }
1358 
1359  dbFile.delete();
1360  }
1361 
1362  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1363  postArtifacts(bbartifacts);
1364  }
1365  }
1366 
1375  private void getAutofill(String browser, String browserLocation, String userName, long ingestJobId) {
1376 
1377  FileManager fileManager = currentCase.getServices().getFileManager();
1378  List<AbstractFile> webDataFiles;
1379  String browserName = browser;
1380  String webDataFileName = WEB_DATA_FILE_NAME;
1381  if (browserName.equals(UC_BROWSER_NAME)) {
1382  webDataFileName = WEB_DATA_FILE_NAME + "%";
1383  }
1384 
1385  try {
1386  webDataFiles = fileManager.findFiles(dataSource, webDataFileName, browserLocation); //NON-NLS
1387  } catch (TskCoreException ex) {
1388  String msg = NbBundle.getMessage(this.getClass(), "Chrome.getAutofills.errMsg.errGettingFiles");
1389  logger.log(Level.SEVERE, msg, ex);
1390  this.addErrorMessage(this.getDisplayName() + ": " + msg);
1391  return;
1392  }
1393 
1394  if (webDataFiles.isEmpty()) {
1395  logger.log(Level.INFO, "Didn't find any Chrome Web Data files."); //NON-NLS
1396  return;
1397  }
1398 
1399  dataFound = true;
1400  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1401  int j = 0;
1402  while (j < webDataFiles.size()) {
1403  if (browser.contains(GOOGLE_PROFILE_NAME)) {
1404  String parentPath = FilenameUtils.normalizeNoEndSeparator(webDataFiles.get(j).getParentPath());
1405  browserName = GOOGLE_PROFILE + FilenameUtils.getBaseName(parentPath);
1406  }
1407  databaseEncrypted = false;
1408  AbstractFile webDataFile = webDataFiles.get(j++);
1409  if ((webDataFile.getSize() == 0) || (webDataFile.getName().toLowerCase().contains("-slack"))) {
1410  continue;
1411  }
1412  String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, browserName, ingestJobId) + File.separator + webDataFile.getName() + j + ".db"; //NON-NLS
1413  try {
1414  ContentUtils.writeToFile(webDataFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
1415  } catch (ReadContentInputStreamException ex) {
1416  logger.log(Level.WARNING, String.format("Error reading Chrome Autofill artifacts file '%s' (id=%d).",
1417  webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1418  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getAutofill.errMsg.errAnalyzingFiles",
1419  this.getDisplayName(), webDataFile.getName()));
1420  continue;
1421  } catch (IOException ex) {
1422  logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
1423  tempFilePath, webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
1424  this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
1425  this.getDisplayName(), webDataFile.getName()));
1426  continue;
1427  }
1428  File dbFile = new File(tempFilePath);
1429  if (context.dataSourceIngestIsCancelled()) {
1430  dbFile.delete();
1431  break;
1432  }
1433 
1434  // The DB schema is little different in schema version 8x vs older versions
1435  boolean isSchemaV8X = Util.checkColumn("date_created", "autofill", tempFilePath);
1436 
1437  // get form autofill artifacts
1438  bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X, userName, browserName));
1439  try {
1440  // get form address atifacts
1441  getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X);
1442  if (databaseEncrypted) {
1443  String comment = String.format("%s Autofill Database Encryption Detected", browserName);
1444  Collection<BlackboardAttribute> bbattributes = Arrays.asList(
1445  new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1446  RecentActivityExtracterModuleFactory.getModuleName(), comment));
1447 
1448  bbartifacts.add(
1449  webDataFile.newAnalysisResult(
1450  BlackboardArtifact.Type.TSK_ENCRYPTION_DETECTED, Score.SCORE_NOTABLE,
1451  null, null, comment, bbattributes).getAnalysisResult());
1452  }
1453  } catch (NoCurrentCaseException | TskCoreException | Blackboard.BlackboardException ex) {
1454  logger.log(Level.SEVERE, String.format("Error adding artifacts to the case database "
1455  + "for chrome file %s [objId=%d]", webDataFile.getName(), webDataFile.getId()), ex);
1456  }
1457 
1458  dbFile.delete();
1459  }
1460 
1461  if (!bbartifacts.isEmpty() && !context.dataSourceIngestIsCancelled()) {
1462  postArtifacts(bbartifacts);
1463  }
1464  }
1465 
1476  private Collection<BlackboardArtifact> getFormAutofillArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X, String userName, String browser) {
1477 
1478  Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
1479 
1480  // The DB Schema is little different in version 8x vs older versions
1481  String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
1482  : AUTOFILL_QUERY;
1483 
1484  List<HashMap<String, Object>> autofills = this.querySQLiteDb(dbFilePath, autoFillquery);
1485  logger.log(Level.INFO, "{0}- Now getting Autofill information from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, autofills.size()}); //NON-NLS
1486  for (HashMap<String, Object> result : autofills) {
1487  Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
1488 
1489  // extract all common attributes
1490  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
1491  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1492  ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
1493 
1494  fieldEncrypted = false;
1495  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
1496  RecentActivityExtracterModuleFactory.getModuleName(),
1497  processFields(result.get("value")))); //NON-NLS
1498 
1499  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
1500  RecentActivityExtracterModuleFactory.getModuleName(),
1501  (Integer.valueOf(result.get("count").toString())))); //NON-NLS
1502 
1503  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
1504  RecentActivityExtracterModuleFactory.getModuleName(),
1505  Long.valueOf(result.get("date_created").toString()))); //NON-NLS
1506 
1507  // get schema version specific attributes
1508  if (isSchemaV8X) {
1509  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
1510  RecentActivityExtracterModuleFactory.getModuleName(),
1511  Long.valueOf(result.get("date_last_used").toString()))); //NON-NLS
1512  }
1513 
1514  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
1515  RecentActivityExtracterModuleFactory.getModuleName(), userName));
1516  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
1517  RecentActivityExtracterModuleFactory.getModuleName(), browser));
1518  if (fieldEncrypted) {
1519  bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1520  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE));
1521  }
1522 
1523  // Add an artifact
1524  try {
1525  bbartifacts.add(createArtifactWithAttributes(BlackboardArtifact.Type.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes));
1526  } catch (TskCoreException ex) {
1527  logger.log(Level.SEVERE, String.format("Failed to create web form autopfill artifact for file (%d)", webDataFile.getId()), ex);
1528  }
1529  }
1530 
1531  // return all extracted artifacts
1532  return bbartifacts;
1533  }
1534 
1546  private void getFormAddressArtifacts(AbstractFile webDataFile, String dbFilePath, boolean isSchemaV8X) throws NoCurrentCaseException,
1547  TskCoreException, Blackboard.BlackboardException {
1548 
1549  String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
1550  : WEBFORM_ADDRESS_QUERY;
1551 
1552  // Helper to create web form address artifacts.
1553  WebBrowserArtifactsHelper helper = new WebBrowserArtifactsHelper(
1554  Case.getCurrentCaseThrows().getSleuthkitCase(),
1555  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
1556  webDataFile, context.getJobId()
1557  );
1558 
1559  // Get Web form addresses
1560  List<HashMap<String, Object>> addresses = this.querySQLiteDb(dbFilePath, webformAddressQuery);
1561  logger.log(Level.INFO, "{0}- Now getting Web form addresses from {1} with {2} artifacts identified.", new Object[]{getDisplayName(), dbFilePath, addresses.size()}); //NON-NLS
1562  for (HashMap<String, Object> result : addresses) {
1563 
1564  fieldEncrypted = false;
1565 
1566  String first_name = processFields(result.get("first_name"));
1567  String middle_name = processFields(result.get("middle_name"));
1568  String last_name = processFields(result.get("last_name"));
1569 
1570  // get email and phone
1571  String email_Addr = processFields(result.get("email"));
1572  String phone_number = processFields(result.get("number"));
1573 
1574  // Get the address fields
1575  String city = processFields(result.get("city"));
1576  String state = processFields(result.get("state"));
1577  String zipcode = processFields(result.get("zipcode"));
1578  String country_code = processFields(result.get("country_code"));
1579 
1580  // schema version specific fields
1581  String full_name = "";
1582  String street_address = "";
1583  long date_modified = 0;
1584  int use_count = 0;
1585  long use_date = 0;
1586 
1587  if (isSchemaV8X) {
1588 
1589  full_name = processFields(result.get("full_name"));
1590  street_address = processFields(result.get("street_address"));
1591  date_modified = result.get("date_modified").toString() != null ? Long.valueOf(result.get("date_modified").toString()) : 0;
1592  use_count = result.get("use_count").toString() != null ? Integer.valueOf(result.get("use_count").toString()) : 0;
1593  use_date = result.get("use_date").toString() != null ? Long.valueOf(result.get("use_date").toString()) : 0;
1594  } else {
1595  String address_line_1 = processFields(result.get("address_line_1"));
1596  String address_line_2 = processFields(result.get("address_line_2"));
1597  street_address = String.join(" ", address_line_1, address_line_2);
1598  }
1599 
1600  // Create atrributes from extracted fields
1601  if (full_name == null || full_name.isEmpty()) {
1602  full_name = String.join(" ", first_name, middle_name, last_name);
1603  }
1604 
1605  String locationAddress = String.join(", ", street_address, city, state, zipcode, country_code);
1606 
1607  List<BlackboardAttribute> otherAttributes = new ArrayList<>();
1608  if (date_modified > 0) {
1609  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
1610  RecentActivityExtracterModuleFactory.getModuleName(),
1611  date_modified)); //NON-NLS
1612  if (fieldEncrypted) {
1613  otherAttributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT,
1614  RecentActivityExtracterModuleFactory.getModuleName(), ENCRYPTED_FIELD_MESSAGE)); //NON-NLS
1615 
1616  }
1617  }
1618 
1619  helper.addWebFormAddress(
1620  full_name, email_Addr, phone_number,
1621  locationAddress, 0, use_date,
1622  use_count, otherAttributes);
1623  }
1624  }
1625 
1635  private String processFields(Object dataValue) {
1636 
1637  if (dataValue instanceof byte[]) {
1638  fieldEncrypted = true;
1639  databaseEncrypted = true;
1640  }
1641 
1642  return dataValue.toString() != null ? dataValue.toString() : "";
1643 
1644  }
1645 
1646  private boolean isChromePreVersion30(String temps) {
1647  String query = "PRAGMA table_info(downloads)"; //NON-NLS
1648  List<HashMap<String, Object>> columns = this.querySQLiteDb(temps, query);
1649  for (HashMap<String, Object> col : columns) {
1650  if (col.get("name").equals("url")) { //NON-NLS
1651  return true;
1652  }
1653  }
1654 
1655  return false;
1656  }
1657 
1658  @Messages({
1659  "ExtractFavicon_Display_Name=Favicon"
1660  })
1667  private BlackboardArtifact.Type createArtifactType(String artifactName, String displayName) throws TskCoreException {
1668  BlackboardArtifact.Type faviconArtifactType;
1669  try {
1670  faviconArtifactType = tskCase.getBlackboard().getOrAddArtifactType(artifactName, displayName); //NON-NLS
1671  } catch (Blackboard.BlackboardException ex) {
1672  throw new TskCoreException(String.format("An exception was thrown while defining artifact type %s", artifactName), ex);
1673  }
1674  return faviconArtifactType;
1675  }
1676 
1677 }

Copyright © 2012-2022 Basis Technology. Generated on: Mon Apr 17 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.