1 /*
2 *
3 * Autopsy Forensic Browser
4 *
5 * Copyright 2012-2014 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.gson.JsonArray;
26 import com.google.gson.JsonElement;
27 import com.google.gson.JsonIOException;
28 import com.google.gson.JsonObject;
29 import com.google.gson.JsonParser;
30 import com.google.gson.JsonSyntaxException;
31 import org.openide.util.NbBundle;
34 import java.util.logging.Level;
35 import java.util.*;
36 import java.io.File;
37 import java.io.FileNotFoundException;
38 import java.io.FileReader;
39 import java.io.IOException;
52
56 class Chrome extends Extract {
57
58 private static final String historyQuery = "SELECT urls.url, urls.title, urls.visit_count, urls.typed_count, " //NON-NLS
59 + "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
60 private static final String cookieQuery = "select name, value, host_key, expires_utc,last_access_utc, creation_utc from cookies"; //NON-NLS
61 private static final String downloadQuery = "select full_path, url, start_time, received_bytes from downloads"; //NON-NLS
62 private static final String downloadQueryVersion30 = "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
63 private static final String loginQuery = "select origin_url, username_value, signon_realm from logins"; //NON-NLS
67
68 Chrome() {
69 moduleName = NbBundle.getMessage(Chrome.class, "Chrome.moduleName");
70 }
71
72 @Override
74 this.dataSource = dataSource;
75 this.context = context;
76 dataFound = false;
77 this.getHistory();
78 this.getBookmark();
79 this.getCookie();
80 this.getLogin();
81 this.getDownload();
82 }
83
87 private void getHistory() {
88 FileManager fileManager = currentCase.getServices().getFileManager();
89 List<AbstractFile> historyFiles;
90 try {
91 historyFiles = fileManager.
findFiles(dataSource,
"History",
"Chrome");
//NON-NLS
93 String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errGettingFiles");
94 logger.log(Level.SEVERE, msg, ex);
95 this.addErrorMessage(this.getName() + ": " + msg);
96 return;
97 }
98
99 // get only the allocated ones, for now
100 List<AbstractFile> allocatedHistoryFiles = new ArrayList<>();
103 allocatedHistoryFiles.add(historyFile);
104 }
105 }
106
107 // log a message if we don't have any allocated history files
108 if (allocatedHistoryFiles.isEmpty()) {
109 String msg = NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.couldntFindAnyFiles");
110 logger.log(Level.INFO, msg);
111 return;
112 }
113
114 dataFound = true;
115 int j = 0;
116 while (j < historyFiles.size()) {
119 if (historyFile.
getSize() == 0) {
120 continue;
121 }
122 try {
124 } catch (IOException ex) {
125 logger.log(Level.SEVERE, "Error writing temp sqlite db for Chrome web history artifacts.{0}", ex); //NON-NLS
126 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getHistory.errMsg.errAnalyzingFile",
127 this.getName(), historyFile.
getName()));
128 continue;
129 }
130 File dbFile = new File(temps);
132 dbFile.delete();
133 break;
134 }
135 List<HashMap<String, Object>> tempList;
136 tempList = this.dbConnect(temps, historyQuery);
137 logger.log(Level.INFO, "{0}- Now getting history from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
138 for (HashMap<String, Object> result : tempList) {
139 Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
141 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
142 ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
144 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
145 (Long.valueOf(result.get("last_visit_time").toString()) / 1000000)- Long.valueOf("11644473600"))); //NON-NLS
147 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
148 ((result.get("from_visit").toString() != null) ? result.get("from_visit").toString() : ""))); //NON-NLS
150 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
151 ((result.get("title").toString() != null) ? result.get("title").toString() : ""))); //NON-NLS
153 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
154 NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
156 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
157 (Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
159 }
160 dbFile.delete();
161 }
162
165 }
166
170 private void getBookmark() {
171 FileManager fileManager = currentCase.getServices().getFileManager();
172 List<AbstractFile> bookmarkFiles = null;
173 try {
174 bookmarkFiles = fileManager.
findFiles(dataSource,
"Bookmarks",
"Chrome");
//NON-NLS
176 String msg = NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errGettingFiles");
177 logger.log(Level.SEVERE, msg, ex);
178 this.addErrorMessage(this.getName() + ": " + msg);
179 return;
180 }
181
182 if (bookmarkFiles.isEmpty()) {
183 logger.log(Level.INFO, "Didn't find any Chrome bookmark files."); //NON-NLS
184 return;
185 }
186
187 dataFound = true;
188 int j = 0;
189
190 while (j < bookmarkFiles.size()) {
192 if (bookmarkFile.
getSize() == 0) {
193 continue;
194 }
196 try {
198 } catch (IOException ex) {
199 logger.log(Level.SEVERE, "Error writing temp sqlite db for Chrome bookmark artifacts.{0}", ex); //NON-NLS
200 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile",
201 this.getName(), bookmarkFile.
getName()));
202 continue;
203 }
204
205 logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{moduleName, temps}); //NON-NLS
206 File dbFile = new File(temps);
208 dbFile.delete();
209 break;
210 }
211
212 FileReader tempReader;
213 try {
214 tempReader = new FileReader(temps);
215 } catch (FileNotFoundException ex) {
216 logger.log(Level.SEVERE, "Error while trying to read into the Bookmarks for Chrome.", ex); //NON-NLS
217 this.addErrorMessage(
218 NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzeFile", this.getName(),
220 continue;
221 }
222
223 final JsonParser parser = new JsonParser();
224 JsonElement jsonElement;
225 JsonObject jElement, jRoot, jBookmark;
226 JsonArray jBookmarkArray;
227
228 try {
229 jsonElement = parser.parse(tempReader);
230 jElement = jsonElement.getAsJsonObject();
231 jRoot = jElement.get("roots").getAsJsonObject(); //NON-NLS
232 jBookmark = jRoot.get("bookmark_bar").getAsJsonObject(); //NON-NLS
233 jBookmarkArray = jBookmark.getAsJsonArray("children"); //NON-NLS
234 } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
235 logger.log(Level.WARNING, "Error parsing Json from Chrome Bookmark.", ex); //NON-NLS
236 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile3",
237 this.getName(), bookmarkFile.
getName()));
238 continue;
239 }
240
241 for (JsonElement result : jBookmarkArray) {
242 JsonObject address = result.getAsJsonObject();
243 if (address == null) {
244 continue;
245 }
246 JsonElement urlEl = address.get("url"); //NON-NLS
247 String url;
248 if (urlEl != null) {
249 url = urlEl.getAsString();
250 }
251 else {
252 url = "";
253 }
254 String name;
255 JsonElement nameEl = address.get("name"); //NON-NLS
256 if (nameEl != null) {
257 name = nameEl.getAsString();
258 }
259 else {
260 name = "";
261 }
262 Long date;
263 JsonElement dateEl = address.get("date_added"); //NON-NLS
264 if (dateEl != null) {
265 date = dateEl.getAsLong();
266 }
267 else {
268 date = Long.valueOf(0);
269 }
270 String domain = Util.extractDomain(url);
271 try {
273 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
274 //TODO Revisit usage of deprecated constructor as per TSK-583
276 NbBundle.getMessage(this.getClass(),
277 "Chrome.parentModuleName"), url));
279 NbBundle.getMessage(this.getClass(),
280 "Chrome.parentModuleName"), name));
282 NbBundle.getMessage(this.getClass(),
283 "Chrome.parentModuleName"), (date/1000000) - Long.valueOf("11644473600")));
285 NbBundle.getMessage(this.getClass(),
286 "Chrome.parentModuleName"),
287 NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
289 NbBundle.getMessage(this.getClass(),
290 "Chrome.parentModuleName"), domain));
293 logger.log(Level.SEVERE, "Error while trying to insert Chrome bookmark artifact{0}", ex); //NON-NLS
294 this.addErrorMessage(
295 NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errAnalyzingFile4",
296 this.getName(), bookmarkFile.
getName()));
297 }
298 }
299 dbFile.delete();
300 }
301
303 }
304
308 private void getCookie() {
309
310 FileManager fileManager = currentCase.getServices().getFileManager();
311 List<AbstractFile> cookiesFiles;
312 try {
313 cookiesFiles = fileManager.
findFiles(dataSource,
"Cookies",
"Chrome");
//NON-NLS
315 String msg = NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errGettingFiles");
316 logger.log(Level.SEVERE, msg, ex);
317 this.addErrorMessage(this.getName() + ": " + msg);
318 return;
319 }
320
321 if (cookiesFiles.isEmpty()) {
322 logger.log(Level.INFO, "Didn't find any Chrome cookies files."); //NON-NLS
323 return;
324 }
325
326 dataFound = true;
327 int j = 0;
328 while (j < cookiesFiles.size()) {
330 if (cookiesFile.
getSize() == 0) {
331 continue;
332 }
334 try {
336 } catch (IOException ex) {
337 logger.log(Level.SEVERE, "Error writing temp sqlite db for Chrome cookie artifacts.{0}", ex); //NON-NLS
338 this.addErrorMessage(
339 NbBundle.getMessage(this.getClass(), "Chrome.getCookie.errMsg.errAnalyzeFile", this.getName(),
341 continue;
342 }
343 File dbFile = new File(temps);
345 dbFile.delete();
346 break;
347 }
348
349 List<HashMap<String, Object>> tempList = this.dbConnect(temps, cookieQuery);
350 logger.log(Level.INFO, "{0}- Now getting cookies from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
351 for (HashMap<String, Object> result : tempList) {
352 Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
354 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
355 ((result.get("host_key").toString() != null) ? result.get("host_key").toString() : ""))); //NON-NLS
357 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
358 (Long.valueOf(result.get("last_access_utc").toString()) / 1000000)- Long.valueOf("11644473600"))); //NON-NLS
359
361 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
362 ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
364 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
365 ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
367 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
368 NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
369 String domain = result.get("host_key").toString(); //NON-NLS
370 domain = domain.replaceFirst("^\\.+(?!$)", "");
372 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), domain));
374 }
375
376 dbFile.delete();
377 }
378
380 }
381
385 private void getDownload() {
386 FileManager fileManager = currentCase.getServices().getFileManager();
387 List<AbstractFile> downloadFiles = null;
388 try {
389 downloadFiles = fileManager.
findFiles(dataSource,
"History",
"Chrome");
//NON-NLS
391 String msg = NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errGettingFiles");
392 logger.log(Level.SEVERE, msg, ex);
393 this.addErrorMessage(this.getName() + ": " + msg);
394 return;
395 }
396
397 if (downloadFiles.isEmpty()) {
398 logger.log(Level.INFO, "Didn't find any Chrome download files."); //NON-NLS
399 return;
400 }
401
402 dataFound = true;
403 int j = 0;
404 while (j < downloadFiles.size()) {
406 if (downloadFile.
getSize() == 0) {
407 continue;
408 }
410 try {
412 } catch (IOException ex) {
413 logger.log(Level.SEVERE, "Error writing temp sqlite db for Chrome download artifacts.{0}", ex); //NON-NLS
414 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getDownload.errMsg.errAnalyzeFiles1",
415 this.getName(), downloadFile.
getName()));
416 continue;
417 }
418 File dbFile = new File(temps);
420 dbFile.delete();
421 break;
422 }
423
424 List<HashMap<String, Object>> tempList;
425
426 if (isChromePreVersion30(temps)) {
427 tempList = this.dbConnect(temps, downloadQuery);
428 } else {
429 tempList = this.dbConnect(temps, downloadQueryVersion30);
430 }
431
432 logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
433 for (HashMap<String, Object> result : tempList) {
434 Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
436 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), (result.get("full_path").toString()))); //NON-NLS
437 long pathID = Util.findID(dataSource, (result.get("full_path").toString())); //NON-NLS
438 if (pathID != -1) {
440 NbBundle.getMessage(this.getClass(),
441 "Chrome.parentModuleName"), pathID));
442 }
444 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
445 ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
446 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
447 Long time = (Long.valueOf(result.get("start_time").toString()) / 1000000)- Long.valueOf("11644473600"); //NON-NLS
448
449 //TODO Revisit usage of deprecated constructor as per TSK-583
450 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
452 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), time));
453 String domain = Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
455 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), domain));
457 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
458 NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
460 }
461
462 dbFile.delete();
463 }
464
467 }
468
472 private void getLogin() {
473 FileManager fileManager = currentCase.getServices().getFileManager();
474 List<AbstractFile> signonFiles;
475 try {
476 signonFiles = fileManager.
findFiles(dataSource,
"signons.sqlite",
"Chrome");
//NON-NLS
478 String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errGettingFiles");
479 logger.log(Level.SEVERE, msg, ex);
480 this.addErrorMessage(this.getName() + ": " + msg);
481 return;
482 }
483
484 if (signonFiles.isEmpty()) {
485 logger.log(Level.INFO, "Didn't find any Chrome signon files."); //NON-NLS
486 return;
487 }
488
489 dataFound = true;
490 int j = 0;
491 while (j < signonFiles.size()) {
493 if (signonFile.
getSize() == 0) {
494 continue;
495 }
497 try {
499 } catch (IOException ex) {
500 logger.log(Level.SEVERE, "Error writing temp sqlite db for Chrome login artifacts.{0}", ex); //NON-NLS
501 this.addErrorMessage(
502 NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles", this.getName(),
504 continue;
505 }
506 File dbFile = new File(temps);
508 dbFile.delete();
509 break;
510 }
511 List<HashMap<String, Object>> tempList = this.dbConnect(temps, loginQuery);
512 logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
513 for (HashMap<String, Object> result : tempList) {
514 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
516 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
517 ((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : ""))); //NON-NLS
518 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("origin_url").toString() != null) ? EscapeUtil.decodeURL(result.get("origin_url").toString()) : "")));
519 //TODO Revisit usage of deprecated constructor as per TSK-583
520 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", ((Long.valueOf(result.get("last_visit_time").toString())) / 1000000)));
522 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
523 (Long.valueOf(result.get("last_visit_time").toString()) / 1000000)- Long.valueOf("11644473600"))); //NON-NLS
525 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
526 ((result.get("from_visit").toString() != null) ? result.get("from_visit").toString() : ""))); //NON-NLS
528 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
529 ((result.get("title").toString() != null) ? result.get("title").toString() : ""))); //NON-NLS
531 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
532 NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
534 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
535 (Util.extractDomain((result.get("origin_url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
537 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
538 ((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
540 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
541 result.get("signon_realm").toString())); //NON-NLS
543
544 Collection<BlackboardAttribute> osAcctAttributes = new ArrayList<>();
546 NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
547 ((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
549 }
550
551 dbFile.delete();
552 }
553
555 }
556
557 private boolean isChromePreVersion30(String temps) {
558 String query = "PRAGMA table_info(downloads)"; //NON-NLS
559 List<HashMap<String, Object>> columns = this.dbConnect(temps, query);
560 for (HashMap<String, Object> col : columns) {
561 if (col.get("name").equals("url")) { //NON-NLS
562 return true;
563 }
564 }
565
566 return false;
567 }
568 }
static< T, V > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, SwingWorker< T, V > worker, boolean source)
void addAttributes(Collection< BlackboardAttribute > attributes)
static String getRATempPath(Case a_case, String mod)
synchronized List< AbstractFile > findFiles(Content dataSource, String fileName)
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
boolean dataSourceIngestIsCancelled()
BlackboardArtifact newArtifact(int artifactTypeID)
static Logger getLogger(String name)
static synchronized IngestServices getInstance()