1 /*
2 *
3 * Autopsy Forensic Browser
4 *
5 * Copyright 2012-2018 Basis Technology Corp.
6 *
7 * Copyright 2012 42six Solutions.
8 * Contact: aebadirad <at> 42six <dot> com
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 java.io.File;
26 import java.io.IOException;
27 import java.io.UnsupportedEncodingException;
28 import java.net.URLDecoder;
29 import java.util.ArrayList;
30 import java.util.Collection;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.logging.Level;
34
35 import org.openide.util.NbBundle;
45 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
47 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
49 import org.
sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
51
55 class Firefox extends Extract {
56
57 private static final Logger logger = Logger.getLogger(Firefox.class.getName());
58 private static final String PLACE_URL_PREFIX = "place:";
59 private static final String HISTORY_QUERY = "SELECT moz_historyvisits.id,url,title,visit_count,(visit_date/1000000) AS visit_date,from_visit,(SELECT url FROM moz_places WHERE id=moz_historyvisits.from_visit) as ref FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id AND hidden = 0"; //NON-NLS
60 private static final String COOKIE_QUERY = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed,(creationTime/1000000) AS creationTime FROM moz_cookies"; //NON-NLS
61 private static final String COOKIE_QUERY_V3 = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed FROM moz_cookies"; //NON-NLS
62 private static final String BOOKMARK_QUERY = "SELECT fk, moz_bookmarks.title, url, (moz_bookmarks.dateAdded/1000000) AS dateAdded FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id"; //NON-NLS
63 private static final String DOWNLOAD_QUERY = "SELECT target, source,(startTime/1000000) AS startTime, maxBytes FROM moz_downloads"; //NON-NLS
64 private static final String DOWNLOAD_QUERY_V24 = "SELECT url, content AS target, (lastModified/1000000) AS lastModified FROM moz_places, moz_annos WHERE moz_places.id = moz_annos.place_id AND moz_annos.anno_attribute_id = 3"; //NON-NLS
65 private final IngestServices services = IngestServices.getInstance();
66 private Content dataSource;
67 private IngestJobContext context;
68
69 Firefox() {
70 moduleName = NbBundle.getMessage(Firefox.class, "Firefox.moduleName");
71 }
72
73 @Override
74 public void process(Content dataSource, IngestJobContext context) {
75 this.dataSource = dataSource;
76 this.context = context;
77 dataFound = false;
78 this.getHistory();
79 this.getBookmark();
80 this.getDownload();
81 this.getCookie();
82 }
83
84 private void getHistory() {
85 FileManager fileManager = currentCase.getServices().getFileManager();
86 List<AbstractFile> historyFiles;
87 try {
88 historyFiles = fileManager.findFiles(dataSource, "places.sqlite", "Firefox"); //NON-NLS
89 } catch (TskCoreException ex) {
90 String msg = NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errFetchingFiles");
91 logger.log(Level.WARNING, msg);
92 this.addErrorMessage(this.getName() + ": " + msg);
93 return;
94 }
95
96 if (historyFiles.isEmpty()) {
97 String msg = NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.noFilesFound");
98 logger.log(Level.INFO, msg);
99 return;
100 }
101
102 dataFound = true;
103 Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
104 int j = 0;
105 for (AbstractFile historyFile : historyFiles) {
106 if (historyFile.getSize() == 0) {
107 continue;
108 }
109
110 String fileName = historyFile.getName();
111 String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox") + File.separator + fileName + j + ".db"; //NON-NLS
112 try {
113 ContentUtils.writeToFile(historyFile, new File(temps), context::dataSourceIngestIsCancelled);
114 } catch (ReadContentInputStreamException ex) {
115 logger.log(Level.WARNING, String.format("Error reading Firefox web history artifacts file '%s' (id=%d).",
116 fileName, historyFile.getId()), ex); //NON-NLS
117 this.addErrorMessage(
118 NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
119 fileName));
120 continue;
121 } catch (IOException ex) {
122 logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
123 temps, fileName, historyFile.getId()), ex); //NON-NLS
124 this.addErrorMessage(
125 NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
126 fileName));
127 continue;
128 }
129 File dbFile = new File(temps);
130 if (context.dataSourceIngestIsCancelled()) {
131 dbFile.delete();
132 break;
133 }
134 List<HashMap<String, Object>> tempList = this.dbConnect(temps, HISTORY_QUERY);
135 logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
136 for (HashMap<String, Object> result : tempList) {
137 String url = result.get("url").toString();
138
139 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
140 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
141 NbBundle.getMessage(this.getClass(),
142 "Firefox.parentModuleName.noSpace"),
143 ((url != null) ? url : ""))); //NON-NLS
144 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
145 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
146 NbBundle.getMessage(this.getClass(),
147 "Firefox.parentModuleName.noSpace"),
148 (Long.valueOf(result.get("visit_date").toString())))); //NON-NLS
149 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REFERRER,
150 NbBundle.getMessage(this.getClass(),
151 "Firefox.parentModuleName.noSpace"),
152 ((result.get("ref").toString() != null) ? result.get("ref").toString() : ""))); //NON-NLS
153 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
154 NbBundle.getMessage(this.getClass(),
155 "Firefox.parentModuleName.noSpace"),
156 ((result.get("title").toString() != null) ? result.get("title").toString() : ""))); //NON-NLS
157 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
158 NbBundle.getMessage(this.getClass(),
159 "Firefox.parentModuleName.noSpace"),
160 NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
161 String domain = extractDomain(url);
162 if (domain != null && domain.isEmpty() == false) {
163 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
164 NbBundle.getMessage(this.getClass(),
165 "Firefox.parentModuleName.noSpace"), domain)); //NON-NLS
166
167 }
168 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
169 if (bbart != null) {
170 bbartifacts.add(bbart);
171 }
172 }
173 ++j;
174 dbFile.delete();
175 }
176
177 services.fireModuleDataEvent(new ModuleDataEvent(
178 NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
179 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY, bbartifacts));
180 }
181
185 private void getBookmark() {
186
187 FileManager fileManager = currentCase.getServices().getFileManager();
188 List<AbstractFile> bookmarkFiles;
189 try {
190 bookmarkFiles = fileManager.findFiles(dataSource, "places.sqlite", "Firefox"); //NON-NLS
191 } catch (TskCoreException ex) {
192 String msg = NbBundle.getMessage(this.getClass(), "Firefox.getBookmark.errMsg.errFetchFiles");
193 logger.log(Level.WARNING, msg);
194 this.addErrorMessage(this.getName() + ": " + msg);
195 return;
196 }
197
198 if (bookmarkFiles.isEmpty()) {
199 logger.log(Level.INFO, "Didn't find any firefox bookmark files."); //NON-NLS
200 return;
201 }
202
203 dataFound = true;
204 Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
205 int j = 0;
206 for (AbstractFile bookmarkFile : bookmarkFiles) {
207 if (bookmarkFile.getSize() == 0) {
208 continue;
209 }
210 String fileName = bookmarkFile.getName();
211 String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox") + File.separator + fileName + j + ".db"; //NON-NLS
212 try {
213 ContentUtils.writeToFile(bookmarkFile, new File(temps), context::dataSourceIngestIsCancelled);
214 } catch (ReadContentInputStreamException ex) {
215 logger.log(Level.WARNING, String.format("Error reading Firefox bookmark artifacts file '%s' (id=%d).",
216 fileName, bookmarkFile.getId()), ex); //NON-NLS
217 this.addErrorMessage(
218 NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
219 fileName));
220 continue;
221 } catch (IOException ex) {
222 logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox bookmark artifacts file '%s' (id=%d).",
223 temps, fileName, bookmarkFile.getId()), ex); //NON-NLS
224 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getBookmark.errMsg.errAnalyzeFile",
225 this.getName(), fileName));
226 continue;
227 }
228 File dbFile = new File(temps);
229 if (context.dataSourceIngestIsCancelled()) {
230 dbFile.delete();
231 break;
232 }
233 List<HashMap<String, Object>> tempList = this.dbConnect(temps, BOOKMARK_QUERY);
234 logger.log(Level.INFO, "{0} - Now getting bookmarks from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
235 for (HashMap<String, Object> result : tempList) {
236 String url = result.get("url").toString();
237
238 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
239 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
240 NbBundle.getMessage(this.getClass(),
241 "Firefox.parentModuleName.noSpace"),
242 ((url != null) ? url : ""))); //NON-NLS
243 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
244 NbBundle.getMessage(this.getClass(),
245 "Firefox.parentModuleName.noSpace"),
246 ((result.get("title").toString() != null) ? result.get("title").toString() : ""))); //NON-NLS
247 if (Long.valueOf(result.get("dateAdded").toString()) > 0) { //NON-NLS
248 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
249 NbBundle.getMessage(this.getClass(),
250 "Firefox.parentModuleName.noSpace"),
251 (Long.valueOf(result.get("dateAdded").toString())))); //NON-NLS
252 }
253 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
254 NbBundle.getMessage(this.getClass(),
255 "Firefox.parentModuleName.noSpace"),
256 NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
257 String domain = extractDomain(url);
258 if (domain != null && domain.isEmpty() == false) {
259 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
260 NbBundle.getMessage(this.getClass(),
261 "Firefox.parentModuleName.noSpace"),
262 domain)); //NON-NLS
263 }
264
265 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes);
266 if (bbart != null) {
267 bbartifacts.add(bbart);
268 }
269 }
270 ++j;
271 dbFile.delete();
272 }
273
274 services.fireModuleDataEvent(new ModuleDataEvent(
275 NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
276 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bbartifacts));
277 }
278
282 private void getCookie() {
283 FileManager fileManager = currentCase.getServices().getFileManager();
284 List<AbstractFile> cookiesFiles;
285 try {
286 cookiesFiles = fileManager.findFiles(dataSource, "cookies.sqlite", "Firefox"); //NON-NLS
287 } catch (TskCoreException ex) {
288 String msg = NbBundle.getMessage(this.getClass(), "Firefox.getCookie.errMsg.errFetchFile");
289 logger.log(Level.WARNING, msg);
290 this.addErrorMessage(this.getName() + ": " + msg);
291 return;
292 }
293
294 if (cookiesFiles.isEmpty()) {
295 logger.log(Level.INFO, "Didn't find any Firefox cookie files."); //NON-NLS
296 return;
297 }
298
299 dataFound = true;
300 Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
301 int j = 0;
302 for (AbstractFile cookiesFile : cookiesFiles) {
303 if (cookiesFile.getSize() == 0) {
304 continue;
305 }
306 String fileName = cookiesFile.getName();
307 String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox") + File.separator + fileName + j + ".db"; //NON-NLS
308 try {
309 ContentUtils.writeToFile(cookiesFile, new File(temps), context::dataSourceIngestIsCancelled);
310 } catch (ReadContentInputStreamException ex) {
311 logger.log(Level.WARNING, String.format("Error reading Firefox cookie artifacts file '%s' (id=%d).",
312 fileName, cookiesFile.getId()), ex); //NON-NLS
313 this.addErrorMessage(
314 NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
315 fileName));
316 continue;
317 } catch (IOException ex) {
318 logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox cookie artifacts file '%s' (id=%d).",
319 temps, fileName, cookiesFile.getId()), ex); //NON-NLS
320 this.addErrorMessage(
321 NbBundle.getMessage(this.getClass(), "Firefox.getCookie.errMsg.errAnalyzeFile", this.getName(),
322 fileName));
323 continue;
324 }
325 File dbFile = new File(temps);
326 if (context.dataSourceIngestIsCancelled()) {
327 dbFile.delete();
328 break;
329 }
330 boolean checkColumn = Util.checkColumn("creationTime", "moz_cookies", temps); //NON-NLS
331 String query;
332 if (checkColumn) {
333 query = COOKIE_QUERY;
334 } else {
335 query = COOKIE_QUERY_V3;
336 }
337
338 List<HashMap<String, Object>> tempList = this.dbConnect(temps, query);
339 logger.log(Level.INFO, "{0} - Now getting cookies from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
340 for (HashMap<String, Object> result : tempList) {
341 String host = result.get("host").toString();
342
343 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
344 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
345 NbBundle.getMessage(this.getClass(),
346 "Firefox.parentModuleName.noSpace"),
347 ((host != null) ? host : ""))); //NON-NLS
348 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
349 NbBundle.getMessage(this.getClass(),
350 "Firefox.parentModuleName.noSpace"),
351 (Long.valueOf(result.get("lastAccessed").toString())))); //NON-NLS
352 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
353 NbBundle.getMessage(this.getClass(),
354 "Firefox.parentModuleName.noSpace"),
355 ((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
356 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
357 NbBundle.getMessage(this.getClass(),
358 "Firefox.parentModuleName.noSpace"),
359 ((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
360 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
361 NbBundle.getMessage(this.getClass(),
362 "Firefox.parentModuleName.noSpace"),
363 NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
364
365 if (checkColumn == true) {
366 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
367 NbBundle.getMessage(this.getClass(),
368 "Firefox.parentModuleName.noSpace"),
369 (Long.valueOf(result.get("creationTime").toString())))); //NON-NLS
370 }
371 String domain = extractDomain(host);
372 if (domain != null && domain.isEmpty() == false) {
373 domain = domain.replaceFirst("^\\.+(?!$)", "");
374 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
375 NbBundle.getMessage(this.getClass(),
376 "Firefox.parentModuleName.noSpace"), domain));
377 }
378
379 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
380 if (bbart != null) {
381 bbartifacts.add(bbart);
382 }
383 }
384 ++j;
385 dbFile.delete();
386 }
387
388 services.fireModuleDataEvent(new ModuleDataEvent(
389 NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
390 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_COOKIE, bbartifacts));
391 }
392
396 private void getDownload() {
397 getDownloadPreVersion24();
398 getDownloadVersion24();
399 }
400
406 private void getDownloadPreVersion24() {
407
408 FileManager fileManager = currentCase.getServices().getFileManager();
409 List<AbstractFile> downloadsFiles;
410 try {
411 downloadsFiles = fileManager.findFiles(dataSource, "downloads.sqlite", "Firefox"); //NON-NLS
412 } catch (TskCoreException ex) {
413 String msg = NbBundle.getMessage(this.getClass(), "Firefox.getDlPre24.errMsg.errFetchFiles");
414 logger.log(Level.WARNING, msg);
415 this.addErrorMessage(this.getName() + ": " + msg);
416 return;
417 }
418
419 if (downloadsFiles.isEmpty()) {
420 logger.log(Level.INFO, "Didn't find any pre-version-24.0 Firefox download files."); //NON-NLS
421 return;
422 }
423
424 dataFound = true;
425 Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
426 int j = 0;
427 for (AbstractFile downloadsFile : downloadsFiles) {
428 if (downloadsFile.getSize() == 0) {
429 continue;
430 }
431 String fileName = downloadsFile.getName();
432 String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox") + File.separator + fileName + j + ".db"; //NON-NLS
433 int errors = 0;
434 try {
435 ContentUtils.writeToFile(downloadsFile, new File(temps), context::dataSourceIngestIsCancelled);
436 } catch (ReadContentInputStreamException ex) {
437 logger.log(Level.WARNING, String.format("Error reading Firefox download artifacts file '%s' (id=%d).",
438 fileName, downloadsFile.getId()), ex); //NON-NLS
439 this.addErrorMessage(
440 NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
441 fileName));
442 continue;
443 } catch (IOException ex) {
444 logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
445 temps, fileName, downloadsFile.getId()), ex); //NON-NLS
446 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getDlPre24.errMsg.errAnalyzeFiles",
447 this.getName(), fileName));
448 continue;
449 }
450 File dbFile = new File(temps);
451 if (context.dataSourceIngestIsCancelled()) {
452 dbFile.delete();
453 break;
454 }
455
456 List<HashMap<String, Object>> tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
457 logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
458 for (HashMap<String, Object> result : tempList) {
459 String source = result.get("source").toString();
460
461 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
462
463 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
464 NbBundle.getMessage(this.getClass(),
465 "Firefox.parentModuleName.noSpace"),
466 source)); //NON-NLS
467 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
468 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
469 NbBundle.getMessage(this.getClass(),
470 "Firefox.parentModuleName.noSpace"),
471 (Long.valueOf(result.get("startTime").toString())))); //NON-NLS
472
473 String target = result.get("target").toString(); //NON-NLS
474
475 if (target != null) {
476 try {
477 String decodedTarget = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
478 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
479 NbBundle.getMessage(this.getClass(),
480 "Firefox.parentModuleName.noSpace"),
481 decodedTarget));
482 long pathID = Util.findID(dataSource, decodedTarget);
483 if (pathID != -1) {
484 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
485 NbBundle.getMessage(this.getClass(),
486 "Firefox.parentModuleName.noSpace"),
487 pathID));
488 }
489 } catch (UnsupportedEncodingException ex) {
490 logger.log(Level.SEVERE, "Error decoding Firefox download URL in " + temps, ex); //NON-NLS
491 errors++;
492 }
493 }
494
495 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
496 NbBundle.getMessage(this.getClass(),
497 "Firefox.parentModuleName.noSpace"),
498 NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
499 String domain = extractDomain(source);
500 if (domain != null && domain.isEmpty() == false) {
501 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
502 NbBundle.getMessage(this.getClass(),
503 "Firefox.parentModuleName.noSpace"),
504 domain)); //NON-NLS
505 }
506
507 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
508 if (bbart != null) {
509 bbartifacts.add(bbart);
510 }
511 }
512 if (errors > 0) {
513 this.addErrorMessage(
514 NbBundle.getMessage(this.getClass(), "Firefox.getDlPre24.errMsg.errParsingArtifacts",
515 this.getName(), errors));
516 }
517 j++;
518 dbFile.delete();
519 break;
520 }
521
522 services.fireModuleDataEvent(new ModuleDataEvent(
523 NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
524 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
525 }
526
532 private void getDownloadVersion24() {
533 FileManager fileManager = currentCase.getServices().getFileManager();
534 List<AbstractFile> downloadsFiles;
535 try {
536 downloadsFiles = fileManager.findFiles(dataSource, "places.sqlite", "Firefox"); //NON-NLS
537 } catch (TskCoreException ex) {
538 String msg = NbBundle.getMessage(this.getClass(), "Firefox.getDlV24.errMsg.errFetchFiles");
539 logger.log(Level.WARNING, msg);
540 this.addErrorMessage(this.getName() + ": " + msg);
541 return;
542 }
543
544 if (downloadsFiles.isEmpty()) {
545 logger.log(Level.INFO, "Didn't find any version-24.0 Firefox download files."); //NON-NLS
546 return;
547 }
548
549 dataFound = true;
550 Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
551 int j = 0;
552 for (AbstractFile downloadsFile : downloadsFiles) {
553 if (downloadsFile.getSize() == 0) {
554 continue;
555 }
556 String fileName = downloadsFile.getName();
557 String temps = RAImageIngestModule.getRATempPath(currentCase, "firefox") + File.separator + fileName + "-downloads" + j + ".db"; //NON-NLS
558 int errors = 0;
559 try {
560 ContentUtils.writeToFile(downloadsFile, new File(temps), context::dataSourceIngestIsCancelled);
561 } catch (ReadContentInputStreamException ex) {
562 logger.log(Level.WARNING, String.format("Error reading Firefox download artifacts file '%s' (id=%d).",
563 fileName, downloadsFile.getId()), ex); //NON-NLS
564 this.addErrorMessage(
565 NbBundle.getMessage(this.getClass(), "Firefox.getHistory.errMsg.errAnalyzeFile", this.getName(),
566 fileName));
567 continue;
568 } catch (IOException ex) {
569 logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox download artifacts file '%s' (id=%d).",
570 temps, fileName, downloadsFile.getId()), ex); //NON-NLS
571 this.addErrorMessage(
572 NbBundle.getMessage(this.getClass(), "Firefox.getDlV24.errMsg.errAnalyzeFile", this.getName(),
573 fileName));
574 continue;
575 }
576 File dbFile = new File(temps);
577 if (context.dataSourceIngestIsCancelled()) {
578 dbFile.delete();
579 break;
580 }
581
582 List<HashMap<String, Object>> tempList = this.dbConnect(temps, DOWNLOAD_QUERY_V24);
583
584 logger.log(Level.INFO, "{0} - Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
585 for (HashMap<String, Object> result : tempList) {
586 String url = result.get("url").toString();
587
588 Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
589
590 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
591 NbBundle.getMessage(this.getClass(),
592 "Firefox.parentModuleName.noSpace"),
593 url)); //NON-NLS
594 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
595 //TODO Revisit usage of deprecated constructor as per TSK-583
596 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString()))));
597
598 String target = result.get("target").toString(); //NON-NLS
599 if (target != null) {
600 try {
601 String decodedTarget = URLDecoder.decode(target.replaceAll("file:///", ""), "UTF-8"); //NON-NLS
602 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH,
603 NbBundle.getMessage(this.getClass(),
604 "Firefox.parentModuleName.noSpace"),
605 decodedTarget));
606 long pathID = Util.findID(dataSource, decodedTarget);
607 if (pathID != -1) {
608 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID,
609 NbBundle.getMessage(this.getClass(),
610 "Firefox.parentModuleName.noSpace"),
611 pathID));
612 }
613 } catch (UnsupportedEncodingException ex) {
614 logger.log(Level.SEVERE, "Error decoding Firefox download URL in " + temps, ex); //NON-NLS
615 errors++;
616 }
617 }
618 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
619 NbBundle.getMessage(this.getClass(),
620 "Firefox.parentModuleName.noSpace"),
621 Long.valueOf(result.get("lastModified").toString()))); //NON-NLS
622 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
623 NbBundle.getMessage(this.getClass(),
624 "Firefox.parentModuleName.noSpace"),
625 NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
626 String domain = extractDomain(url);
627 if (domain != null && domain.isEmpty() == false) {
628 bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
629 NbBundle.getMessage(this.getClass(),
630 "Firefox.parentModuleName.noSpace"),
631 domain)); //NON-NLS
632 }
633
634 BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
635 if (bbart != null) {
636 bbartifacts.add(bbart);
637 }
638 }
639 if (errors > 0) {
640 this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getDlV24.errMsg.errParsingArtifacts",
641 this.getName(), errors));
642 }
643 j++;
644 dbFile.delete();
645 break;
646 }
647
648 services.fireModuleDataEvent(new ModuleDataEvent(
649 NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
650 BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
651 }
652
661 private String extractDomain(String url) {
662 if (url == null || url.isEmpty()) {
663 return url;
664 }
665
666 if (url.toLowerCase().startsWith(PLACE_URL_PREFIX)) {
667 /*
668 * Ignore URLs that begin with the matched text.
669 */
670 return null;
671 }
672
673 return NetworkUtils.extractDomain(url);
674 }
675 }