From 8f1c233343f5137167a3f08b3d71eea5c6e892c5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 5 Oct 2018 16:23:24 -0400 Subject: [PATCH 01/25] Correct copyright notice in new AutopsyOptionProcessor class --- Core/src/org/sleuthkit/autopsy/core/AutopsyOptionProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/core/AutopsyOptionProcessor.java b/Core/src/org/sleuthkit/autopsy/core/AutopsyOptionProcessor.java index 41961bf4f3..dd4ba98ae6 100644 --- a/Core/src/org/sleuthkit/autopsy/core/AutopsyOptionProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/core/AutopsyOptionProcessor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-2017 Basis Technology Corp. + * Copyright 2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From e2cc7d009aa182b94263199e2447b63f9b369457 Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 9 Oct 2018 17:00:41 -0400 Subject: [PATCH 02/25] In HitsFactory.createKeys() add artifact hits in bulk to speed up display of large numbers of interesting hits. --- .../src/org/sleuthkit/autopsy/datamodel/InterestingHits.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java index 6e3c138fcd..8782b0fb89 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/InterestingHits.java @@ -44,7 +44,6 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; -import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -476,11 +475,13 @@ public class InterestingHits implements AutopsyVisitableItem { BlackboardArtifact art = skCase.getBlackboardArtifact(id); artifactHits.put(id, art); } - list.add(id); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS } }); + + list.addAll(artifactHits.keySet()); + return true; } From a82c68d1555a42ef6610a1a800afbb5a6b5e972a Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Wed, 10 Oct 2018 14:27:04 -0400 Subject: [PATCH 03/25] advance groups when none shown, update group when unseen is updated, ensure button stays disabled during rebuild , added comments. --- .../sleuthkit/autopsy/coreutils/History.java | 5 + .../imagegallery/ImageGalleryController.java | 50 ++++++++-- .../imagegallery/actions/NextUnseenGroup.java | 91 ++++++++++++++----- .../datamodel/grouping/GroupManager.java | 6 +- .../datamodel/grouping/GroupViewState.java | 30 +++--- .../imagegallery/gui/navpanel/NavPanel.java | 2 +- 6 files changed, 138 insertions(+), 46 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/History.java b/Core/src/org/sleuthkit/autopsy/coreutils/History.java index 746ac9f710..7a75529c2b 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/History.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/History.java @@ -43,18 +43,23 @@ import javax.annotation.concurrent.ThreadSafe; @ThreadSafe public class History { + // Stack of things that were previously shown before an 'advance' was done @GuardedBy("this") private final ObservableStack historyStack = new ObservableStack<>(); + // stack of things that were previously shown before a 'retreat' (i.e. a back) was done @GuardedBy("this") private final ObservableStack forwardStack = new ObservableStack<>(); + // what is currently being shown @GuardedBy("this") private final ReadOnlyObjectWrapper currentState = new ReadOnlyObjectWrapper<>(); + // Is the forward stack empty? @GuardedBy("this") private final ReadOnlyBooleanWrapper canAdvance = new ReadOnlyBooleanWrapper(); + // is the historyStack empty? @GuardedBy("this") private final ReadOnlyBooleanWrapper canRetreat = new ReadOnlyBooleanWrapper(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index ee46376aed..356ac5bdd1 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -136,18 +136,10 @@ public final class ImageGalleryController { return thumbnailSizeProp; } - public GroupViewState getViewState() { - return historyManager.getCurrentState(); - } - public ReadOnlyBooleanProperty regroupDisabledProperty() { return regroupDisabled.getReadOnlyProperty(); } - public ReadOnlyObjectProperty viewStateProperty() { - return historyManager.currentState(); - } - public FileIDSelectionModel getSelectionModel() { return selectionModel; } @@ -240,24 +232,66 @@ public final class ImageGalleryController { dbTaskQueueSize.addListener(obs -> this.updateRegroupDisabled()); } + + /** + * @return Currently displayed group or null if nothing is being displayed + */ + public GroupViewState getViewState() { + return historyManager.getCurrentState(); + } + + /** + * Get observable property of the current group. The UI currently changes + * based on this property changing, which happens when other actions and + * threads call advance(). + * + * @return Currently displayed group (as a property that can be observed) + */ + public ReadOnlyObjectProperty viewStateProperty() { + return historyManager.currentState(); + } + /** + * Should the "forward" button on the history be enabled? + * @return + */ public ReadOnlyBooleanProperty getCanAdvance() { return historyManager.getCanAdvance(); } + /** + * Should the "Back" button on the history be enabled? + * @return + */ public ReadOnlyBooleanProperty getCanRetreat() { return historyManager.getCanRetreat(); } + /** + * Display the passed in group. Causes this group to + * get recorded in the history queue and observers of the + * current state will be notified and update their panels/widgets + * appropriately. + * + * @param newState + */ @ThreadConfined(type = ThreadConfined.ThreadType.ANY) public void advance(GroupViewState newState) { historyManager.advance(newState); } + /** + * Display the next group in the "forward" history stack + * @return + */ public GroupViewState advance() { return historyManager.advance(); } + /** + * Display the previous group in the "back" history stack + * @return + */ public GroupViewState retreat() { return historyManager.retreat(); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java index 74168e9e13..994ec7b3cd 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/NextUnseenGroup.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.actions; +import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import java.util.Optional; import javafx.application.Platform; @@ -32,6 +33,7 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; +import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils; /** * Marks the currently displayed group as "seen" and advances to the next unseen @@ -56,6 +58,11 @@ public class NextUnseenGroup extends Action { private final ImageGalleryController controller; private final ObservableList unSeenGroups; private final GroupManager groupManager; + + private boolean isLoading = false; // set to true when we are marking current group as seen and loading new + + private final ListeningExecutorService exec = TaskUtils.getExecutorForClass(NextUnseenGroup.class); + public NextUnseenGroup(ImageGalleryController controller) { super(NEXT_UNSEEN_GROUP); @@ -63,56 +70,98 @@ public class NextUnseenGroup extends Action { this.controller = controller; groupManager = controller.getGroupManager(); + + // Get reference to the list of unseen groups, that GroupManager will continue to manage unSeenGroups = groupManager.getUnSeenGroups(); - unSeenGroups.addListener((Observable observable) -> updateButton()); + unSeenGroups.addListener((Observable observable) -> unSeenGroupListener()); controller.viewStateProperty().addListener((Observable observable) -> updateButton()); setEventHandler(event -> { //on fx-thread - //if there is a group assigned to the view, mark it as seen - Optional.ofNullable(controller.getViewState()) - .flatMap(GroupViewState::getGroup) - .ifPresent(group -> { - setDisabled(true); - groupManager.markGroupSeen(group, true) - .addListener(this::advanceToNextUnseenGroup, MoreExecutors.newDirectExecutorService()); - }); + isLoading = true; // make sure button stays disabled until we are done loading + setDisabled(true); + + //if there is a group assigned to the view, mark it as seen and move on to the next one + GroupViewState viewState = controller.getViewState(); + if (viewState != null) { + Optional group = viewState.getGroup(); + + if (group.isPresent()) { + // NOTE: We need to wait for current group to be marked as seen because the 'advance' + // method grabs the top of the unseen list + groupManager.markGroupSeen(group.get(), true) + .addListener(this::advanceToNextUnseenGroup, MoreExecutors.newDirectExecutorService()); + return; + } + } + + // otherwise, just move on to the next one + exec.submit(this::advanceToNextUnseenGroup); }); + + // initial button state updateButton(); } + /** + * Listener that updates UI based on changes to the unseen group list + */ + private void unSeenGroupListener() { + // set the group if there is no visible group. + // NOTE: it could be argued that this should be done in another listner + if (controller.getViewState() == null) { + advanceToNextUnseenGroup(); + // do not update the button if it is supposed to be disabled during loading of the next group + } else if (isLoading == false) { + // NOTE: should we get a lock on groupManager here like advanceToNextUnseenGroup does? + updateButton(); + } + } + + // update UI based on button being pressed private void advanceToNextUnseenGroup() { synchronized (groupManager) { if (CollectionUtils.isNotEmpty(unSeenGroups)) { - controller.advance(GroupViewState.tile(unSeenGroups.get(0))); + // NOTE: We keep the group in the unSeenGroup list until the user presses the + // button again mark it as seen + controller.advance(GroupViewState.createTile(unSeenGroups.get(0))); } - + updateButton(); } } + /** + * Update button based on currently displayed group and queues. + */ private void updateButton() { - int size = unSeenGroups.size(); - if (size < 1) { - //there are no unseen groups. + isLoading = false; + + int unSeenSize = unSeenGroups.size(); + + // NOTE: The currently displayed group is still in the unSeenGroups list until the user presses + // the button again and then we'll mark it as seen. + + // disable button if no unseen groups + if (unSeenSize < 1) { Platform.runLater(() -> { setDisabled(true); setText(ALL_GROUPS_SEEN); setGraphic(null); }); } else { - DrawableGroup get = unSeenGroups.get(0); - DrawableGroup orElse = Optional.ofNullable(controller.getViewState()).flatMap(GroupViewState::getGroup).orElse(null); - boolean equals = get.equals(orElse); - if (size == 1 & equals) { - //The only unseen group is the one that is being viewed. + DrawableGroup groupOnList = unSeenGroups.get(0); + DrawableGroup groupInView = Optional.ofNullable(controller.getViewState()).flatMap(GroupViewState::getGroup).orElse(null); + + //The only unseen group is the one that is being viewed. + if (unSeenSize == 1 & groupOnList.equals(groupInView)) { Platform.runLater(() -> { - setDisabled(false); + setDisabled(true); setText(MARK_GROUP_SEEN); setGraphic(new ImageView(END_IMAGE)); }); } else { - //there are more unseen groups. + //there are more unseen groups after this one Platform.runLater(() -> { setDisabled(false); setText(NEXT_UNSEEN_GROUP); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index c60da0357b..04f5906120 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -785,12 +785,12 @@ public class GroupManager { //the current group should not be visible so ... if (isNotEmpty(unSeenGroups)) { // show then next unseen group - controller.advance(GroupViewState.tile(unSeenGroups.get(0))); + controller.advance(GroupViewState.createTile(unSeenGroups.get(0))); } else if (isNotEmpty(analyzedGroups)) { //show the first analyzed group. - controller.advance(GroupViewState.tile(analyzedGroups.get(0))); + controller.advance(GroupViewState.createTile(analyzedGroups.get(0))); } else { //there are no groups, clear the group area. - controller.advance(GroupViewState.tile(null)); + controller.advance(GroupViewState.createTile(null)); } } } finally { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java index fa578021ef..87f1971d84 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupViewState.java @@ -26,12 +26,28 @@ import java.util.Optional; */ public final class GroupViewState { + // what group is being represented private final DrawableGroup group; + // Tile, Slide show, etc. private final GroupViewMode mode; private final Optional slideShowfileID; + private GroupViewState(DrawableGroup group, GroupViewMode mode, Long slideShowfileID) { + this.group = group; + this.mode = mode; + this.slideShowfileID = Optional.ofNullable(slideShowfileID); + } + + public static GroupViewState createTile(DrawableGroup group) { + return new GroupViewState(group, GroupViewMode.TILE, null); + } + + public static GroupViewState createSlideShow(DrawableGroup group, Long fileID) { + return new GroupViewState(group, GroupViewMode.SLIDE_SHOW, fileID); + } + public Optional getGroup() { return Optional.ofNullable(group); } @@ -44,19 +60,7 @@ public final class GroupViewState { return slideShowfileID; } - private GroupViewState(DrawableGroup group, GroupViewMode mode, Long slideShowfileID) { - this.group = group; - this.mode = mode; - this.slideShowfileID = Optional.ofNullable(slideShowfileID); - } - - public static GroupViewState tile(DrawableGroup group) { - return new GroupViewState(group, GroupViewMode.TILE, null); - } - - public static GroupViewState slideShow(DrawableGroup group, Long fileID) { - return new GroupViewState(group, GroupViewMode.SLIDE_SHOW, fileID); - } + @Override public int hashCode() { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java index 0aa0c287eb..1ce67cd030 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/navpanel/NavPanel.java @@ -107,7 +107,7 @@ abstract class NavPanel extends Tab { .addListener((observable, oldItem, newSelectedItem) -> { Optional.ofNullable(newSelectedItem) .map(getDataItemMapper()) - .ifPresent(group -> controller.advance(GroupViewState.tile(group))); + .ifPresent(group -> controller.advance(GroupViewState.createTile(group))); }); } From d097ef52c5992bb565c0390c14ef4efabd2c38e1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 10 Oct 2018 14:39:46 -0400 Subject: [PATCH 04/25] Ignore problematic URLs to prevent artifact creation. --- .../autopsy/recentactivity/ExtractIE.java | 77 ++++++++++++++++--- .../autopsy/recentactivity/Firefox.java | 46 ++++++++++- 2 files changed, 108 insertions(+), 15 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java index 1af8761144..bae13f9a34 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java @@ -31,9 +31,12 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; +import java.net.MalformedURLException; +import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.HashSet; @@ -69,6 +72,7 @@ class ExtractIE extends Extract { private final String moduleTempResultsDir; private String PASCO_LIB_PATH; private final String JAVA_PATH; + private static final List IGNORE_URL_PREFIXES = Arrays.asList("res://", "?CodeDownloadErrorLog!"); private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); private Content dataSource; private IngestJobContext context; @@ -473,9 +477,13 @@ class ExtractIE extends Extract { String actime = lineBuff[3]; Long ftime = (long) 0; - String user; - String realurl; + String user = null; + String realurl = null; String domain; + + if (isIgnoredUrl(lineBuff[1])) { + continue; + } /* * We've seen two types of lines: URL http://XYZ.com .... URL @@ -483,17 +491,42 @@ class ExtractIE extends Extract { */ if (lineBuff[1].contains("@")) { String url[] = lineBuff[1].split("@", 2); - user = url[0]; - user = user.replace("Visited:", ""); //NON-NLS - user = user.replace(":Host:", ""); //NON-NLS - user = user.replaceAll("(:)(.*?)(:)", ""); - user = user.trim(); - realurl = url[1]; - realurl = realurl.replace("Visited:", ""); //NON-NLS - realurl = realurl.replaceAll(":(.*?):", ""); - realurl = realurl.replace(":Host:", ""); //NON-NLS - realurl = realurl.trim(); + URL urlObject = null; + + try { + /* + * Attempt to use the left portion of the input for the URL. + */ + urlObject = new URL(url[0]); + user = ""; + realurl = lineBuff[1].trim(); + } catch (MalformedURLException ex) { + /* + * Could not create a new URL object from the left portion + * of the input. The right portion will be used instead. + */ + } + + if (urlObject == null) { + /* + * The left portion of the input could not be used for the + * URL, so use the right portion instead. + */ + user = url[0]; + user = user.replace("Visited:", ""); //NON-NLS + user = user.replace(":Host:", ""); //NON-NLS + user = user.replaceAll("(:)(.*?)(:)", ""); + user = user.trim(); + realurl = url[1]; + realurl = realurl.replace("Visited:", ""); //NON-NLS + realurl = realurl.replaceAll(":(.*?):", ""); + realurl = realurl.replace(":Host:", ""); //NON-NLS + realurl = realurl.trim(); + } } else { + /* + * Use the entire input for the URL. + */ user = ""; realurl = lineBuff[1].trim(); } @@ -562,4 +595,24 @@ class ExtractIE extends Extract { fileScanner.close(); return bbartifacts; } + + /** + * Determine if the URL should be ignored. + * + * @param url The URL to test. + * + * @return True if the URL should be ignored; otherwise false. + */ + private boolean isIgnoredUrl(String url) { + for (String ignore : IGNORE_URL_PREFIXES) { + if (url.startsWith(ignore)) { + /* + * Ignore URLs that begin with the matched text. + */ + return true; + } + } + + return false; + } } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java index 22459f4cf6..837af069f5 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java @@ -54,6 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException; class Firefox extends Extract { private static final Logger logger = Logger.getLogger(Firefox.class.getName()); + private static final String PLACE_URL_PREFIX = "place:"; 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 private static final String COOKIE_QUERY = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed,(creationTime/1000000) AS creationTime FROM moz_cookies"; //NON-NLS private static final String COOKIE_QUERY_V3 = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed FROM moz_cookies"; //NON-NLS @@ -132,6 +133,10 @@ class Firefox extends Extract { List> tempList = this.dbConnect(temps, HISTORY_QUERY); logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { + if (isIgnoredUrl(result.get("url").toString())) { + continue; + } + Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, NbBundle.getMessage(this.getClass(), @@ -226,12 +231,16 @@ class Firefox extends Extract { List> tempList = this.dbConnect(temps, BOOKMARK_QUERY); logger.log(Level.INFO, "{0} - Now getting bookmarks from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { + String url = result.get("url").toString(); + if (isIgnoredUrl(url)) { + continue; + } Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), - ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS + ((url != null) ? url : ""))); //NON-NLS bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), @@ -249,7 +258,7 @@ class Firefox extends Extract { bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), - (Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS + (Util.extractDomain((url != null) ? url : "")))); //NON-NLS BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes); if (bbart != null) { @@ -327,6 +336,9 @@ class Firefox extends Extract { List> tempList = this.dbConnect(temps, query); logger.log(Level.INFO, "{0} - Now getting cookies from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { + if (isIgnoredUrl(result.get("host").toString())) { + continue; + } Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, @@ -442,6 +454,9 @@ class Firefox extends Extract { List> tempList = this.dbConnect(temps, DOWNLOAD_QUERY); logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { + if (isIgnoredUrl(result.get("source").toString())) { + continue; + } Collection bbattributes = new ArrayList<>(); @@ -565,7 +580,10 @@ class Firefox extends Extract { logger.log(Level.INFO, "{0} - Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { - + if (isIgnoredUrl(result.get("url").toString())) { + continue; + } + Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, @@ -627,4 +645,26 @@ class Firefox extends Extract { NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"), BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts)); } + + /** + * Determine if the URL should be ignored. + * + * @param url The URL to test. + * + * @return True if the URL should be ignored; otherwise false. + */ + private boolean isIgnoredUrl(String url) { + if (url == null || url.isEmpty()) { + return true; + } + + if (url.toLowerCase().startsWith(PLACE_URL_PREFIX)) { + /* + * Ignore URLs that begin with the matched text. + */ + return true; + } + + return false; + } } From e66b57e2859e595c4294455bfef897cd82214659 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 11 Oct 2018 10:50:11 -0400 Subject: [PATCH 05/25] 1082: SQLException from ImageGallery while ingesting a data source in a multi-user case --- .../autopsy/imagegallery/datamodel/DrawableDB.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 7e2588bc65..9b8fb017a9 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -110,6 +110,8 @@ public final class DrawableDB { private final PreparedStatement insertHashHitStmt; + private final PreparedStatement removeHashHitStmt; + private final PreparedStatement updateDataSourceStmt; private final PreparedStatement updateFileStmt; @@ -263,6 +265,7 @@ public final class DrawableDB { selectHashSetStmt = prepareStatement("SELECT hash_set_id FROM hash_sets WHERE hash_set_name = ?"); //NON-NLS insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, obj_id) VALUES (?,?)"); //NON-NLS + removeHashHitStmt = prepareStatement("DELETE FROM hash_set_hits WHERE obj_id = ?"); //NON-NLS CaseDbTransaction caseDbTransaction = null; try { @@ -1517,12 +1520,15 @@ public final class DrawableDB { // Update the list of file IDs in memory removeImageFileFromList(id); + //"delete from hash_set_hits where (obj_id = " + id + ")" + removeHashHitStmt.setLong(1, id); + removeHashHitStmt.executeUpdate(); + //"delete from drawable_files where (obj_id = " + id + ")" removeFileStmt.setLong(1, id); removeFileStmt.executeUpdate(); tr.addRemovedFile(id); - //TODO: delete from hash_set_hits table also... } catch (SQLException ex) { logger.log(Level.WARNING, "failed to delete row for obj_id = " + id, ex); //NON-NLS } finally { From 154eec8cd7228f0c4ff50d07f328c02827a33dde Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 11 Oct 2018 11:26:07 -0400 Subject: [PATCH 06/25] Run all ingest modules on logical file sets --- .../sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java index e57febe1bf..7dc18a7394 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/SpecialDirectoryNode.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.swing.Action; import org.openide.util.NbBundle; @@ -27,6 +28,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.FileSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SpecialDirectory; /** @@ -60,7 +62,11 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNodesingletonList(content))); + } else { + actions.add(new RunIngestModulesAction(content)); + } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions.toArray(new Action[0]); } From 1b60038931a4f9b12c1c9ebc63467c069931c359 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 11 Oct 2018 11:35:16 -0400 Subject: [PATCH 07/25] 1081: NPE in ImageGallery while switching groups --- .../imagegallery/datamodel/grouping/GroupKey.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java index 8b1f6eb31a..2a6102ff27 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupKey.java @@ -99,7 +99,17 @@ public class GroupKey> implements Comparable if (!Objects.equals(this.attr, other.attr)) { return false; } - return this.dataSource.getId() == other.dataSource.getId(); + // Check datasource, if available + if (this.dataSource != null && other.dataSource != null) { + return this.dataSource.getId() == other.dataSource.getId(); + } else if (this.dataSource == null && other.dataSource == null) { + // neither group has a datasource + return true; + } else { + // one group has a datasource, other doesn't + return false; + } + } @Override From 8d7213f095b227195a1e5bc82181f3211606528a Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Oct 2018 12:58:36 -0400 Subject: [PATCH 08/25] Added space to SQL --- .../sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 9b8fb017a9..9911b1fb58 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -1411,7 +1411,7 @@ public final class DrawableDB { ds_obj_id, value, groupBy.attrName.toString()); if (DbType.POSTGRESQL == tskCase.getDatabaseType()) { - insertSQL += "ON CONFLICT DO NOTHING"; + insertSQL += " ON CONFLICT DO NOTHING"; } tskCase.getCaseDbAccessManager().insert(GROUPS_TABLENAME, insertSQL, caseDbTransaction); groupCache.put(cacheKey, Boolean.TRUE); From aee36df5eae1431e7ea6fc6dc46e445ac38cde7c Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 11 Oct 2018 13:22:01 -0400 Subject: [PATCH 09/25] 1066: Grouping by Camera Make/Model depends on data source selection, despite being told otherwise --- .../autopsy/imagegallery/datamodel/grouping/GroupManager.java | 2 +- .../src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 04f5906120..263e189b7d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -449,7 +449,7 @@ public class GroupManager { * * @param dataSource Data source to display or null to display all of them */ - synchronized void setDataSource(DataSource dataSource) { + public synchronized void setDataSource(DataSource dataSource) { dataSourceProp.set(dataSource); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 6ce152bfdb..bc0f5e5d84 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -185,6 +185,9 @@ public class Toolbar extends ToolBar { alert.initOwner(getScene().getWindow()); GuiUtils.setDialogIcons(alert); if (alert.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.OK) { + // Set the datasource selection to 'All', before switching group + controller.getGroupManager().setDataSource(null); + queryInvalidationListener.invalidated(observable); } else { Platform.runLater(() -> groupByBox.getSelectionModel().select(DrawableAttribute.PATH)); From 3c1db06fc40b8b0f603d9d92aa272d39ef8f7601 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 11 Oct 2018 15:03:25 -0400 Subject: [PATCH 10/25] Minimal fixes. --- .../datamodel/EamArtifactUtil.java | 5 +- .../autopsy/recentactivity/ExtractIE.java | 31 ++++---- .../autopsy/recentactivity/Firefox.java | 77 +++++++++---------- 3 files changed, 58 insertions(+), 55 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java index 2fb294cdfb..668e1408e8 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java @@ -127,7 +127,10 @@ public class EamArtifactUtil { || BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeID)) { // Lower-case this to normalize domains - value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN)).getValueString(); + BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN)); + if (attribute != null) { + value = attribute.getValueString(); + } } else if (correlationType.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID && (BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeID || BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeID diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java index bae13f9a34..357aaa813b 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java @@ -72,7 +72,7 @@ class ExtractIE extends Extract { private final String moduleTempResultsDir; private String PASCO_LIB_PATH; private final String JAVA_PATH; - private static final List IGNORE_URL_PREFIXES = Arrays.asList("res://", "?CodeDownloadErrorLog!"); + private static final String RESOURCE_URL_PREFIX = "res://"; private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); private Content dataSource; private IngestJobContext context; @@ -480,10 +480,6 @@ class ExtractIE extends Extract { String user = null; String realurl = null; String domain; - - if (isIgnoredUrl(lineBuff[1])) { - continue; - } /* * We've seen two types of lines: URL http://XYZ.com .... URL @@ -565,9 +561,12 @@ class ExtractIE extends Extract { "ExtractIE.parentModuleName.noSpace"), NbBundle.getMessage(this.getClass(), "ExtractIE.moduleName.text"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "ExtractIE.parentModuleName.noSpace"), domain)); + + if (isIgnoredUrl(lineBuff[1]) == false) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, + NbBundle.getMessage(this.getClass(), + "ExtractIE.parentModuleName.noSpace"), domain)); + } bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, NbBundle.getMessage(this.getClass(), "ExtractIE.parentModuleName.noSpace"), user)); @@ -604,13 +603,15 @@ class ExtractIE extends Extract { * @return True if the URL should be ignored; otherwise false. */ private boolean isIgnoredUrl(String url) { - for (String ignore : IGNORE_URL_PREFIXES) { - if (url.startsWith(ignore)) { - /* - * Ignore URLs that begin with the matched text. - */ - return true; - } + if (url == null || url.isEmpty()) { + return true; + } + + if (url.toLowerCase().startsWith(RESOURCE_URL_PREFIX)) { + /* + * Ignore URLs that begin with the matched text. + */ + return true; } return false; diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java index 837af069f5..6d0ae54a53 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Firefox.java @@ -133,15 +133,13 @@ class Firefox extends Extract { List> tempList = this.dbConnect(temps, HISTORY_QUERY); logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { - if (isIgnoredUrl(result.get("url").toString())) { - continue; - } + String url = result.get("url").toString(); Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), - ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS + ((url != null) ? url : ""))); //NON-NLS //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : ""))); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, NbBundle.getMessage(this.getClass(), @@ -159,10 +157,12 @@ class Firefox extends Extract { NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), NbBundle.getMessage(this.getClass(), "Firefox.moduleName"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "Firefox.parentModuleName.noSpace"), (Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS + if (isIgnoredUrl(url) == false) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, + NbBundle.getMessage(this.getClass(), + "Firefox.parentModuleName.noSpace"), Util.extractDomain(url))); //NON-NLS + } BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes); if (bbart != null) { bbartifacts.add(bbart); @@ -232,9 +232,6 @@ class Firefox extends Extract { logger.log(Level.INFO, "{0} - Now getting bookmarks from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { String url = result.get("url").toString(); - if (isIgnoredUrl(url)) { - continue; - } Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, @@ -255,10 +252,12 @@ class Firefox extends Extract { NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), NbBundle.getMessage(this.getClass(), "Firefox.moduleName"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "Firefox.parentModuleName.noSpace"), - (Util.extractDomain((url != null) ? url : "")))); //NON-NLS + if (isIgnoredUrl(url) == false) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, + NbBundle.getMessage(this.getClass(), + "Firefox.parentModuleName.noSpace"), + Util.extractDomain(url))); //NON-NLS + } BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes); if (bbart != null) { @@ -336,15 +335,13 @@ class Firefox extends Extract { List> tempList = this.dbConnect(temps, query); logger.log(Level.INFO, "{0} - Now getting cookies from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { - if (isIgnoredUrl(result.get("host").toString())) { - continue; - } + String host = result.get("host").toString(); Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), - ((result.get("host").toString() != null) ? result.get("host").toString() : ""))); //NON-NLS + ((host != null) ? host : ""))); //NON-NLS bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), @@ -368,11 +365,13 @@ class Firefox extends Extract { "Firefox.parentModuleName.noSpace"), (Long.valueOf(result.get("creationTime").toString())))); //NON-NLS } - String domain = Util.extractDomain(result.get("host").toString()); //NON-NLS - domain = domain.replaceFirst("^\\.+(?!$)", ""); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "Firefox.parentModuleName.noSpace"), domain)); + if (isIgnoredUrl(host) == false) { + String domain = Util.extractDomain(host); //NON-NLS + domain = domain.replaceFirst("^\\.+(?!$)", ""); + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, + NbBundle.getMessage(this.getClass(), + "Firefox.parentModuleName.noSpace"), domain)); + } BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes); if (bbart != null) { @@ -454,16 +453,14 @@ class Firefox extends Extract { List> tempList = this.dbConnect(temps, DOWNLOAD_QUERY); logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { - if (isIgnoredUrl(result.get("source").toString())) { - continue; - } + String source = result.get("source").toString(); Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), - ((result.get("source").toString() != null) ? result.get("source").toString() : ""))); //NON-NLS + source)); //NON-NLS //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : ""))); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED, NbBundle.getMessage(this.getClass(), @@ -496,10 +493,12 @@ class Firefox extends Extract { NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), NbBundle.getMessage(this.getClass(), "Firefox.moduleName"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "Firefox.parentModuleName.noSpace"), - (Util.extractDomain((result.get("source").toString() != null) ? result.get("source").toString() : "")))); //NON-NLS + if (isIgnoredUrl(source) == false) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, + NbBundle.getMessage(this.getClass(), + "Firefox.parentModuleName.noSpace"), + Util.extractDomain(source))); //NON-NLS + } BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes); if (bbart != null) { @@ -580,16 +579,14 @@ class Firefox extends Extract { logger.log(Level.INFO, "{0} - Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS for (HashMap result : tempList) { - if (isIgnoredUrl(result.get("url").toString())) { - continue; - } + String url = result.get("url").toString(); Collection bbattributes = new ArrayList<>(); bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), - ((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS + url)); //NON-NLS //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : ""))); //TODO Revisit usage of deprecated constructor as per TSK-583 //bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString())))); @@ -622,10 +619,12 @@ class Firefox extends Extract { NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName.noSpace"), NbBundle.getMessage(this.getClass(), "Firefox.moduleName"))); - bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, - NbBundle.getMessage(this.getClass(), - "Firefox.parentModuleName.noSpace"), - (Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS + if (isIgnoredUrl(url) == false) { + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN, + NbBundle.getMessage(this.getClass(), + "Firefox.parentModuleName.noSpace"), + Util.extractDomain(url))); //NON-NLS + } BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes); if (bbart != null) { From 6977f4d69d6f51c21450dff297c726317ecc2c0d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 11 Oct 2018 15:11:51 -0400 Subject: [PATCH 11/25] Simplified user@host parsing. --- .../autopsy/recentactivity/ExtractIE.java | 42 +++++-------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java index 357aaa813b..c24bf2857c 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java @@ -487,38 +487,16 @@ class ExtractIE extends Extract { */ if (lineBuff[1].contains("@")) { String url[] = lineBuff[1].split("@", 2); - URL urlObject = null; - - try { - /* - * Attempt to use the left portion of the input for the URL. - */ - urlObject = new URL(url[0]); - user = ""; - realurl = lineBuff[1].trim(); - } catch (MalformedURLException ex) { - /* - * Could not create a new URL object from the left portion - * of the input. The right portion will be used instead. - */ - } - - if (urlObject == null) { - /* - * The left portion of the input could not be used for the - * URL, so use the right portion instead. - */ - user = url[0]; - user = user.replace("Visited:", ""); //NON-NLS - user = user.replace(":Host:", ""); //NON-NLS - user = user.replaceAll("(:)(.*?)(:)", ""); - user = user.trim(); - realurl = url[1]; - realurl = realurl.replace("Visited:", ""); //NON-NLS - realurl = realurl.replaceAll(":(.*?):", ""); - realurl = realurl.replace(":Host:", ""); //NON-NLS - realurl = realurl.trim(); - } + user = url[0]; + user = user.replace("Visited:", ""); //NON-NLS + user = user.replace(":Host:", ""); //NON-NLS + user = user.replaceAll("(:)(.*?)(:)", ""); + user = user.trim(); + realurl = url[1]; + realurl = realurl.replace("Visited:", ""); //NON-NLS + realurl = realurl.replaceAll(":(.*?):", ""); + realurl = realurl.replace(":Host:", ""); //NON-NLS + realurl = realurl.trim(); } else { /* * Use the entire input for the URL. From 49c001e69fd80e290a1c9ff83c2dc28ac8b4bc35 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 11 Oct 2018 15:12:33 -0400 Subject: [PATCH 12/25] Cleanup. --- .../src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java index c24bf2857c..3e6a1e6348 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java @@ -31,12 +31,9 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.HashSet; From df419009c4f735692e901d9749295b386af6c071 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 11 Oct 2018 15:39:57 -0400 Subject: [PATCH 13/25] Refactor to remove public API additions for common properties search --- ...monAttributesSearchResultsViewerTable.java | 3 +- .../commonfilesearch/InstanceCountNode.java | 19 +++++---- ...stanceCountNodeTreeExpansionListener.java} | 40 +++++++++---------- .../corecomponents/TableFilterNode.java | 10 ----- .../directorytree/DataResultFilterNode.java | 12 ------ 5 files changed, 30 insertions(+), 54 deletions(-) rename Core/src/org/sleuthkit/autopsy/{corecomponents/DelayedLoadChildNodesOnTreeExpansion.java => commonfilesearch/InstanceCountNodeTreeExpansionListener.java} (56%) diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java index 97a41b27be..a33e23ffa0 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java @@ -29,7 +29,6 @@ import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; -import org.sleuthkit.autopsy.corecomponents.DelayedLoadChildNodesOnTreeExpansion; /** * DataResultViewerTable which overrides the default column @@ -70,7 +69,7 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa */ public CommonAttributesSearchResultsViewerTable() { super(); - outlineView.addTreeExpansionListener(new DelayedLoadChildNodesOnTreeExpansion()); + outlineView.addTreeExpansionListener(new InstanceCountNodeTreeExpansionListener()); } @NbBundle.Messages({ diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNode.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNode.java index fa298c121d..93de3267d0 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNode.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNode.java @@ -1,16 +1,16 @@ /* - * + * * Autopsy Forensic Browser - * + * * Copyright 2018 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.datamodel.NodeProperty; * Node used to indicate the number of matches found with the MD5 children of * this Node. */ -final public class InstanceCountNode extends DisplayableItemNode { +public final class InstanceCountNode extends DisplayableItemNode { private static final Logger logger = Logger.getLogger(InstanceCountNode.class.getName()); @@ -74,11 +74,10 @@ final public class InstanceCountNode extends DisplayableItemNode { } /** - * Refresh the node, by dynamically loading in the children when called, and - * calling the CommonAttributeValueNodeFactory to generate nodes for the - * children in attributeValues. + * Creates the Children of this node. By doing this here instead of in the + * constructor, lazy creation of the Children is made possible. */ - public void refresh() { + void createChildren() { attributeValues.displayDelayedMetadata(); setChildren(Children.create(new CommonAttributeValueNodeFactory(attributeValues.getMetadataList()), true)); } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DelayedLoadChildNodesOnTreeExpansion.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java similarity index 56% rename from Core/src/org/sleuthkit/autopsy/corecomponents/DelayedLoadChildNodesOnTreeExpansion.java rename to Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java index 6e6d28af2a..df2bfc2c7c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DelayedLoadChildNodesOnTreeExpansion.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java @@ -1,54 +1,54 @@ /* - * + * * Autopsy Forensic Browser - * + * * Copyright 2018 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.corecomponents; +package org.sleuthkit.autopsy.commonfilesearch; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import org.openide.explorer.view.Visualizer; import org.openide.nodes.Node; +import org.sleuthkit.autopsy.corecomponents.TableFilterNode; +import org.sleuthkit.autopsy.directorytree.DataResultFilterNode; /** - * A tree expansion listener that will trigger a recreation of childs through - * its child factory on re-expansion of a node (causes to recreate the - * ChildFactory for this purpose.). + * A tree expansion listener used to do lazy creation of the Childfren of an + * InstanceCountNode when the node is expanded. */ -public final class DelayedLoadChildNodesOnTreeExpansion implements TreeExpansionListener { - - /** - * A flag for avoiding endless recursion inside the expansion listener that - * could trigger collapsing and (re-)expanding nodes again. - * @param event - */ +final class InstanceCountNodeTreeExpansionListener implements TreeExpansionListener { @Override public synchronized void treeCollapsed(final TreeExpansionEvent event) { - // Do nothing on collapse. Netbeans should manage nodes falling out of scope and GC. } @Override public synchronized void treeExpanded(final TreeExpansionEvent event) { Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent()); if (eventNode instanceof TableFilterNode) { - final TableFilterNode node = (TableFilterNode) eventNode; - node.refresh(); + final TableFilterNode tableFilterNode = (TableFilterNode) eventNode; + DataResultFilterNode dataResultFilterNode = tableFilterNode.getLookup().lookup(DataResultFilterNode.class); + if (dataResultFilterNode != null) { + InstanceCountNode instanceCountNode = dataResultFilterNode.getLookup().lookup(InstanceCountNode.class); + if (instanceCountNode != null) { + instanceCountNode.createChildren(); + } + } } - } + } diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java index 2ba02f694a..eb36cf2e87 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/TableFilterNode.java @@ -128,16 +128,6 @@ public class TableFilterNode extends FilterNode { return null; } } - - /** - * Refreshes the inner node, which depending on the actual node type that was wrapped - * could trigger a dynamic refresh of the children, if supported. - */ - void refresh() { - DataResultFilterNode innerNode = getLookup().lookup(DataResultFilterNode.class); - innerNode.refresh(); - - } /** * @return the column order key, which allows custom column ordering to be diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index c94ad57094..3a27f9fa9b 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -140,18 +140,6 @@ public class DataResultFilterNode extends FilterNode { this.sourceEm = em; } - /** - * Refreshes the inner node. If the actual underlying node is an InstanceCountNode, - * refresh() that node, which refreshes the children. - * - */ - public void refresh() { - if (getOriginal() instanceof InstanceCountNode) { - InstanceCountNode innerNode = getLookup().lookup(InstanceCountNode.class); - innerNode.refresh(); - } - } - /** * Constructs a node used to wrap another node before passing it to the * result viewers. The wrapper node defines the actions associated with the From 1bf1d77532ac4ba17b2de03d75cf89c29efab042 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 11 Oct 2018 15:43:29 -0400 Subject: [PATCH 14/25] Refactor to remove public API additions for common properties search --- .../InstanceCountNodeTreeExpansionListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java index df2bfc2c7c..cbdc85ba38 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java @@ -41,9 +41,9 @@ final class InstanceCountNodeTreeExpansionListener implements TreeExpansionListe Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent()); if (eventNode instanceof TableFilterNode) { final TableFilterNode tableFilterNode = (TableFilterNode) eventNode; - DataResultFilterNode dataResultFilterNode = tableFilterNode.getLookup().lookup(DataResultFilterNode.class); + final DataResultFilterNode dataResultFilterNode = tableFilterNode.getLookup().lookup(DataResultFilterNode.class); if (dataResultFilterNode != null) { - InstanceCountNode instanceCountNode = dataResultFilterNode.getLookup().lookup(InstanceCountNode.class); + final InstanceCountNode instanceCountNode = dataResultFilterNode.getLookup().lookup(InstanceCountNode.class); if (instanceCountNode != null) { instanceCountNode.createChildren(); } From 7d7484aaefdca9973f155a594e73aad2f6d89c2d Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 11 Oct 2018 15:47:41 -0400 Subject: [PATCH 15/25] Refactor to remove public API additions for common properties search --- .../InstanceCountNodeTreeExpansionListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java index cbdc85ba38..3de4d44b7f 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/InstanceCountNodeTreeExpansionListener.java @@ -38,7 +38,7 @@ final class InstanceCountNodeTreeExpansionListener implements TreeExpansionListe @Override public synchronized void treeExpanded(final TreeExpansionEvent event) { - Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent()); + final Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent()); if (eventNode instanceof TableFilterNode) { final TableFilterNode tableFilterNode = (TableFilterNode) eventNode; final DataResultFilterNode dataResultFilterNode = tableFilterNode.getLookup().lookup(DataResultFilterNode.class); From 4a8aecb93904df3b371df814ec7773ee2da41c10 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 11 Oct 2018 18:16:46 -0400 Subject: [PATCH 16/25] Restore encapsulation of OutlineView in DataResultViewerTable --- ...monAttributesSearchResultsViewerTable.java | 43 ++++++++++--------- .../corecomponents/DataResultViewerTable.form | 1 - .../corecomponents/DataResultViewerTable.java | 13 +++++- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java index 97a41b27be..0812bd24a3 100644 --- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CommonAttributesSearchResultsViewerTable.java @@ -1,16 +1,16 @@ /* - * + * * Autopsy Forensic Browser - * + * * Copyright 2018 Basis Technology Corp. * Contact: carrier sleuthkit org - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -32,11 +32,11 @@ import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.DelayedLoadChildNodesOnTreeExpansion; /** - * DataResultViewerTable which overrides the default column - * header width calculations. The CommonAttributesSearchResultsViewerTable - * presents multiple tiers of data which are not always present and it may not - * make sense to try to calculate the column widths for such tables by sampling - * rows and looking for wide cells. Rather, we just pick some reasonable values. + * DataResultViewerTable which overrides the default column header + * width calculations. The CommonAttributesSearchResultsViewerTable + * presents multiple tiers of data which are not always present and it may not + * make sense to try to calculate the column widths for such tables by sampling + * rows and looking for wide cells. Rather, we just pick some reasonable values. */ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTable { @@ -44,7 +44,7 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa private static final long serialVersionUID = 1L; private static final Logger LOGGER = Logger.getLogger(CommonAttributesSearchResultsViewerTable.class.getName()); - + private static final int DEFAULT_WIDTH = 100; static { @@ -60,19 +60,20 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa COLUMN_WIDTHS = Collections.unmodifiableMap(map); } + /** - * Implements a DataResultViewerTable which constructs a tabular result viewer that - * displays the children of the given root node using an OutlineView. The explorer - * manager will be discovered at runtime. - * - * Adds a TreeExpansionsListener to the outlineView to receive tree expansion events - * which dynamically loads children nodes when requested. + * Implements a DataResultViewerTable which constructs a tabular result + * viewer that displays the children of the given root node using an + * OutlineView. The explorer manager will be discovered at runtime. + * + * Adds a TreeExpansionsListener to the outlineView to receive tree + * expansion events which dynamically loads children nodes when requested. */ public CommonAttributesSearchResultsViewerTable() { super(); - outlineView.addTreeExpansionListener(new DelayedLoadChildNodesOnTreeExpansion()); + addTreeExpansionListener(new DelayedLoadChildNodesOnTreeExpansion()); } - + @NbBundle.Messages({ "CommonFilesSearchResultsViewerTable.noDescText= ", "CommonFilesSearchResultsViewerTable.filesColLbl=Files", @@ -96,8 +97,8 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa final String headerValue = column.getHeaderValue().toString(); final Integer defaultWidth = COLUMN_WIDTHS.get(headerValue); - - if(defaultWidth == null){ + + if (defaultWidth == null) { column.setPreferredWidth(DEFAULT_WIDTH); LOGGER.log(Level.SEVERE, String.format("Tried to set width on a column not supported by the CommonFilesSearchResultsViewerTable: %s", headerValue)); } else { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form index 8ad47b32c7..d6c32623a4 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.form @@ -29,7 +29,6 @@ - diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java index 1679d0296a..bf18c4b831 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataResultViewerTable.java @@ -46,6 +46,7 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; +import javax.swing.event.TreeExpansionListener; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; @@ -265,6 +266,16 @@ public class DataResultViewerTable extends AbstractDataResultViewer { } } + /** + * Adds a tree expansion listener to the OutlineView of this tabular results + * viewer. + * + * @param listener The listener + */ + protected void addTreeExpansionListener(TreeExpansionListener listener) { + outlineView.addTreeExpansionListener(listener); + } + /** * Sets up the Outline view of this tabular result viewer by creating column * headers based on the children of the current root node. The persisted @@ -1036,7 +1047,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer { ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables - protected org.openide.explorer.view.OutlineView outlineView; + private org.openide.explorer.view.OutlineView outlineView; // End of variables declaration//GEN-END:variables } From e80553351cb0a444489b13438b5d44ded10c23b1 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Oct 2018 18:49:32 -0400 Subject: [PATCH 17/25] validate domains don't have special characters --- .../datamodel/EamArtifactUtil.java | 2 +- .../autopsy/recentactivity/Util.java | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java index 668e1408e8..30d539e87f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java @@ -174,7 +174,7 @@ public class EamArtifactUtil { return null; } - if (null != value) { + if ((null != value) && (value.isEmpty() == false)) { return makeCorrelationAttributeInstanceUsingTypeValue(bbArtifact, correlationType, value); } else { return null; diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java index 8b246b05aa..9bff067394 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java @@ -84,7 +84,12 @@ class Util { } } - public static String getBaseDomain(String url) { + /** + * + * @param url + * @return empty string if no domain could be found + */ + private static String getBaseDomain(String url) { String host = null; //strip protocol @@ -113,10 +118,21 @@ class Util { hostB.append("."); } } - - return hostB.toString(); + + + String base = hostB.toString(); + // verify there are no special characters in there + if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) { + return ""; + } + return base; } + /** + * + * @param value + * @return empty string if no domain name was found + */ public static String extractDomain(String value) { if (value == null) { return ""; From 2582ede1c49734ad331f6755bfa31c81d0685b54 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Thu, 11 Oct 2018 21:50:33 -0400 Subject: [PATCH 18/25] Updated to TSK 4.6.3 --- Core/nbproject/project.properties | 2 +- Core/nbproject/project.xml | 4 ++-- TSKVersion.xml | 2 +- unix_setup.sh | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index 7fbc57db78..ed92afe884 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -29,7 +29,7 @@ file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-tran file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar -file.reference.sleuthkit-postgresql-4.6.2.jar=release/modules/ext/sleuthkit-postgresql-4.6.2.jar +file.reference.sleuthkit-postgresql-4.6.3.jar=release/modules/ext/sleuthkit-postgresql-4.6.3.jar file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 0c61555746..d142e0b8c9 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -394,8 +394,8 @@ release/modules/ext/sevenzipjbinding.jar - ext/sleuthkit-postgresql-4.6.2.jar - release/modules/ext/sleuthkit-postgresql-4.6.2.jar + ext/sleuthkit-postgresql-4.6.3.jar + release/modules/ext/sleuthkit-postgresql-4.6.3.jar ext/mchange-commons-java-0.2.9.jar diff --git a/TSKVersion.xml b/TSKVersion.xml index 7350f25b66..d909ae3b26 100644 --- a/TSKVersion.xml +++ b/TSKVersion.xml @@ -1,3 +1,3 @@ - + diff --git a/unix_setup.sh b/unix_setup.sh index f18892dfdf..04766c7bc4 100755 --- a/unix_setup.sh +++ b/unix_setup.sh @@ -2,7 +2,7 @@ # Verifies programs are installed and copies native code into the Autopsy folder structure -TSK_VERSION=4.6.2 +TSK_VERSION=4.6.3 # Verify PhotoRec was installed photorec_filepath=/usr/bin/photorec From 6bf58a0d3ad42252b88105fa7cb81a773def4dc2 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 12 Oct 2018 12:07:41 -0400 Subject: [PATCH 19/25] NBM versioning updates for release 4.9.0 --- Core/manifest.mf | 2 +- Core/nbproject/project.properties | 2 +- Experimental/nbproject/project.xml | 2 +- ImageGallery/manifest.mf | 2 +- ImageGallery/nbproject/project.xml | 2 +- KeywordSearch/nbproject/project.xml | 2 +- RecentActivity/nbproject/project.xml | 2 +- thunderbirdparser/nbproject/project.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/manifest.mf b/Core/manifest.mf index 5eb077ef30..e3a95f497e 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -2,7 +2,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 24 +OpenIDE-Module-Implementation-Version: 25 OpenIDE-Module-Requires: org.openide.windows.WindowManager AutoUpdate-Show-In-Client: true AutoUpdate-Essential-Module: true diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties index ed92afe884..1b0a695edd 100644 --- a/Core/nbproject/project.properties +++ b/Core/nbproject/project.properties @@ -47,5 +47,5 @@ nbm.homepage=http://www.sleuthkit.org/ nbm.module.author=Brian Carrier nbm.needs.restart=true source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar -spec.version.base=10.12 +spec.version.base=10.13 diff --git a/Experimental/nbproject/project.xml b/Experimental/nbproject/project.xml index c0a18a9922..cb0d6bd6cb 100644 --- a/Experimental/nbproject/project.xml +++ b/Experimental/nbproject/project.xml @@ -135,7 +135,7 @@ 10 - 10.12 + 10.13 diff --git a/ImageGallery/manifest.mf b/ImageGallery/manifest.mf index 52bf6cfe1e..38081388f4 100644 --- a/ImageGallery/manifest.mf +++ b/ImageGallery/manifest.mf @@ -1,6 +1,6 @@ Manifest-Version: 1.0 OpenIDE-Module: org.sleuthkit.autopsy.imagegallery/2 -OpenIDE-Module-Implementation-Version: 3 +OpenIDE-Module-Implementation-Version: 4 OpenIDE-Module-Layer: org/sleuthkit/autopsy/imagegallery/layer.xml OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/imagegallery/Bundle.properties diff --git a/ImageGallery/nbproject/project.xml b/ImageGallery/nbproject/project.xml index dcaa641e75..8c7226ef37 100644 --- a/ImageGallery/nbproject/project.xml +++ b/ImageGallery/nbproject/project.xml @@ -127,7 +127,7 @@ 10 - 10.12 + 10.13 diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 343dc691e7..f6ca42f988 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -119,7 +119,7 @@ 10 - 10.12 + 10.13 diff --git a/RecentActivity/nbproject/project.xml b/RecentActivity/nbproject/project.xml index 4d85f94e9b..7b7ae18347 100644 --- a/RecentActivity/nbproject/project.xml +++ b/RecentActivity/nbproject/project.xml @@ -60,7 +60,7 @@ 10 - 10.12 + 10.13 diff --git a/thunderbirdparser/nbproject/project.xml b/thunderbirdparser/nbproject/project.xml index d4c0a0b53d..10437cbd97 100644 --- a/thunderbirdparser/nbproject/project.xml +++ b/thunderbirdparser/nbproject/project.xml @@ -36,7 +36,7 @@ 10 - 10.12 + 10.13 From f94d8e6da33ba22cf01bd769cc5e07dd933194e9 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Fri, 12 Oct 2018 12:23:44 -0400 Subject: [PATCH 20/25] Updated for 4.9.0 release --- NEWS.txt | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index 3fcbff5b40..f0414d48ba 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,9 +1,39 @@ +---------------- VERSION 4.9.0 -------------- + +New Features: +- Removed data from table that are time intensive and can be found in content viewers (such as hash set hits) +- Added ability to find common items (files, emails, etc.) between current case and past cases using the Central Repository. +- Added ability to ignore common items that exist in a large number of cases by using Central Repository data. +- Data is validated and normalized before being entered into the Central Repository. +- Allow users to specify that an ad-hoc keyword search should not be saved to database +- New “Annotations” content viewer that shows all tags and comments associated with an item +- Added 2 icons to the table to show the item’s score (if it is notable or suspicious) and if it has a comment. +- Added column to the table to show previous number of occurrences. +- Tags are now associated with the user (in a multi-user environment) and you can hide other people’s tags +- New Display options area that unifies various new settings. +- Hash sets can be copied into the user’s config folder (AppData), which makes it easier to run Autopsy from a Live Triage USB and not care about what drive letter it gets. +- Image Gallery stores its groups and seen status in Case DB instead of its own. +- Image Gallery works better in multi-user setups and reloads the database when other nodes add data sources. +- Image Gallery saves which user saw a group and gives user option of seeing only their unseen groups or all unseen groups. +- Saves last export location and pre-populates that in the file picker +- Provide feedback about why some right click options are disabled (ingest is running, not file content, etc.) + +Bug Fixes: +- Substring keyword search is more accurate (now uses regular expression) +- New text extractor for SQLite that better deals with full text search tables +- Better deal with Unicode text files that do not have Byte Order Marker +- Embedded file extractor module is now faster because it uses a different 7ZIP API. +- Fixed various HTML report bugs +- Duplicate hash set hits are not created when you run the Hash Ingest Module twice. +- Auto ingest (in Experimental) scan times of input folders is faster. + + ---------------- VERSION 4.8.0 -------------- New Features: - Data Source Grouping: -- The case tree view can now be grouped by data source. -- Keyword and file search can now be restricted to a data source. -- Central Repository / Corrrelation: +- Central Repository / Correlation: -- New common files search feature that finds files that exist in multiple devices in the same case. -- The Other Occurrences content viewer now shows matches in the current case (in addition to central repository). -- Central repository options panel now shows cases that are in repo. @@ -31,7 +61,7 @@ New Features: - A graph visualization was added to the Communications tool to make it easier to find messages and relationships. - A new "Application" content viewer (lower right) that will contain file-type specific viewers (to reduce number of tabs). - New viewer for SQLite databases (in Application content viewer) -- New viewer for binary PLists (in Appilcation content viewer) +- New viewer for binary PLists (in Application content viewer) - L01 files can be imported as data sources. - Ingest filters can now use date range conditions for triage. - Passwords to open password protected archive files can be entered (by right clicking on the file). From a59eadb393816b29f8201f95fa5e5e92cf2cd01d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 12 Oct 2018 16:07:35 -0400 Subject: [PATCH 21/25] 4313 add option to disable limiting of deleted file display to 10k --- .../autopsy/corecomponents/Bundle.properties | 2 + .../corecomponents/ViewPreferencesPanel.form | 117 +++++++----- .../corecomponents/ViewPreferencesPanel.java | 108 +++++++---- .../autopsy/datamodel/DeletedContent.java | 50 ++--- .../deletedFiles/DeletedFilePreferences.java | 171 ++++++++++++++++++ 5 files changed, 345 insertions(+), 103 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/deletedFiles/DeletedFilePreferences.java diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index de261f16d2..12ba493380 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -190,3 +190,5 @@ ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the: ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for: ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns to reduce loading times +ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000 +ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed: diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form index 5ab351c170..ddeb57bd74 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.form @@ -79,65 +79,72 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -174,6 +181,11 @@ + + + + + @@ -327,6 +339,23 @@ + + + + + + + + + + + + + + + + + @@ -388,7 +417,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java index 7ab3bbc84e..51d4120449 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ViewPreferencesPanel.java @@ -25,6 +25,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.CasePreferences; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil; import org.sleuthkit.autopsy.core.UserPreferences; +import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences; import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; /** @@ -61,10 +62,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { dataSourcesHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInDataSourcesTree()); viewsHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInViewsTree()); - + commentsOccurencesColumnsCheckbox.setEnabled(EamDbUtil.useCentralRepo()); commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences()); + deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles()); + // Current Case Settings boolean caseIsOpen = Case.isCaseOpen(); currentCaseSettingsPanel.setEnabled(caseIsOpen); @@ -91,6 +94,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { storeGroupItemsInTreeByDataSource(); DirectoryTreeTopComponent.getDefault().setShowRejectedResults(hideRejectedResultsCheckbox.isSelected() == false); + + DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected()); } /** @@ -135,6 +140,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { hideOtherUsersTagsLabel = new javax.swing.JLabel(); commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox(); centralRepoLabel = new javax.swing.JLabel(); + deletedFilesLimitCheckbox = new javax.swing.JCheckBox(); + deletedFilesLimitLabel = new javax.swing.JLabel(); currentCaseSettingsPanel = new javax.swing.JPanel(); groupByDataSourceCheckbox = new javax.swing.JCheckBox(); currentSessionSettingsPanel = new javax.swing.JPanel(); @@ -228,6 +235,15 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { org.openide.awt.Mnemonics.setLocalizedText(centralRepoLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.centralRepoLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitCheckbox.text")); // NOI18N + deletedFilesLimitCheckbox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + deletedFilesLimitCheckboxActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitLabel.text")); // NOI18N + javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel); globalSettingsPanel.setLayout(globalSettingsPanelLayout); globalSettingsPanelLayout.setHorizontalGroup( @@ -235,46 +251,51 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { .addGroup(globalSettingsPanelLayout.createSequentialGroup() .addContainerGap() .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(globalSettingsPanelLayout.createSequentialGroup() - .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(hideKnownFilesLabel) - .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(globalSettingsPanelLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(dataSourcesHideSlackCheckbox) - .addComponent(viewsHideSlackCheckbox))) - .addComponent(hideSlackFilesLabel)) - .addGroup(globalSettingsPanelLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(dataSourcesHideKnownCheckbox) - .addComponent(viewsHideKnownCheckbox))))) - .addGap(18, 18, 18) - .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(displayTimeLabel) - .addGroup(globalSettingsPanelLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(keepCurrentViewerRadioButton) - .addComponent(useBestViewerRadioButton) - .addComponent(useGMTTimeRadioButton) - .addComponent(useLocalTimeRadioButton))) - .addComponent(selectFileLabel))) - .addComponent(hideOtherUsersTagsLabel) - .addComponent(centralRepoLabel) .addGroup(globalSettingsPanelLayout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(commentsOccurencesColumnsCheckbox) - .addComponent(hideOtherUsersTagsCheckbox)))) - .addContainerGap(16, Short.MAX_VALUE)) + .addComponent(hideOtherUsersTagsCheckbox) + .addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(globalSettingsPanelLayout.createSequentialGroup() + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(globalSettingsPanelLayout.createSequentialGroup() + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(hideKnownFilesLabel) + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(globalSettingsPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dataSourcesHideSlackCheckbox) + .addComponent(viewsHideSlackCheckbox))) + .addComponent(hideSlackFilesLabel)) + .addGroup(globalSettingsPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(dataSourcesHideKnownCheckbox) + .addComponent(viewsHideKnownCheckbox))))) + .addGap(18, 18, 18) + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(displayTimeLabel) + .addGroup(globalSettingsPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(keepCurrentViewerRadioButton) + .addComponent(useBestViewerRadioButton) + .addComponent(useGMTTimeRadioButton) + .addComponent(useLocalTimeRadioButton))) + .addComponent(selectFileLabel))) + .addComponent(hideOtherUsersTagsLabel) + .addComponent(centralRepoLabel) + .addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 10, Short.MAX_VALUE))) + .addContainerGap()) ); globalSettingsPanelLayout.setVerticalGroup( globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(globalSettingsPanelLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap() .addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(globalSettingsPanelLayout.createSequentialGroup() .addComponent(hideKnownFilesLabel) @@ -307,7 +328,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(centralRepoLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(commentsOccurencesColumnsCheckbox)) + .addComponent(commentsOccurencesColumnsCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(deletedFilesLimitLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) ); currentCaseSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.currentCaseSettingsPanel.border.title"))); // NOI18N @@ -350,7 +376,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { currentSessionSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(currentSessionSettingsPanelLayout.createSequentialGroup() .addContainerGap() - .addComponent(hideRejectedResultsCheckbox) + .addComponent(hideRejectedResultsCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); currentSessionSettingsPanelLayout.setVerticalGroup( @@ -501,6 +527,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { } }//GEN-LAST:event_commentsOccurencesColumnsCheckboxActionPerformed + private void deletedFilesLimitCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deletedFilesLimitCheckboxActionPerformed + if (immediateUpdates) { + DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected()); + } else { + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + }//GEN-LAST:event_deletedFilesLimitCheckboxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel centralRepoLabel; @@ -509,6 +543,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { private javax.swing.JPanel currentSessionSettingsPanel; private javax.swing.JCheckBox dataSourcesHideKnownCheckbox; private javax.swing.JCheckBox dataSourcesHideSlackCheckbox; + private javax.swing.JCheckBox deletedFilesLimitCheckbox; + private javax.swing.JLabel deletedFilesLimitLabel; private javax.swing.JLabel displayTimeLabel; private javax.swing.JPanel globalSettingsPanel; private javax.swing.JCheckBox groupByDataSourceCheckbox; @@ -527,4 +563,4 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel { private javax.swing.JCheckBox viewsHideKnownCheckbox; private javax.swing.JCheckBox viewsHideSlackCheckbox; // End of variables declaration//GEN-END:variables -} \ No newline at end of file +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 57bd68911c..55384344bc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; import static org.sleuthkit.autopsy.datamodel.Bundle.*; +import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -111,11 +112,11 @@ public class DeletedContent implements AutopsyVisitableItem { this.skCase = skCase; this.datasourceObjId = dsObjId; } - + long filteringDataSourceObjId() { return this.datasourceObjId; } - + @Override public T accept(AutopsyItemVisitor visitor) { return visitor.visit(this); @@ -191,9 +192,10 @@ public class DeletedContent implements AutopsyVisitableItem { * fired. Other nodes are listening to this for changes. */ private static final class DeletedContentsChildrenObservable extends Observable { + private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of( - Case.Events.DATA_SOURCE_ADDED, - Case.Events.CURRENT_CASE + Case.Events.DATA_SOURCE_ADDED, + Case.Events.CURRENT_CASE ); DeletedContentsChildrenObservable() { @@ -213,12 +215,11 @@ public class DeletedContent implements AutopsyVisitableItem { String eventType = evt.getPropertyName(); if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { /** - * + // @@@ COULD CHECK If the new file is deleted - * before notifying... Checking for a current case is a - * stop gap measure + update(); until a different way of - * handling the closing of cases is worked out. - * Currently, remote events may be received for a case - * that is already closed. + * + // @@@ COULD CHECK If the new file is deleted before + * notifying... Checking for a current case is a stop gap + * measure + update(); until a different way of handling the + * closing of cases is worked out. Currently, remote events + * may be received for a case that is already closed. */ try { Case.getCurrentCaseThrows(); @@ -234,10 +235,10 @@ public class DeletedContent implements AutopsyVisitableItem { || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString()) || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { /** - * Checking for a current case is a stop gap measure - * until a different way of handling the closing of - * cases is worked out. Currently, remote events may be - * received for a case that is already closed. + * Checking for a current case is a stop gap measure until a + * different way of handling the closing of cases is worked + * out. Currently, remote events may be received for a case + * that is already closed. */ try { Case.getCurrentCaseThrows(); @@ -282,7 +283,7 @@ public class DeletedContent implements AutopsyVisitableItem { // Use version that has observer for updates @Deprecated DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, long dsObjId) { - super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId ), true), Lookups.singleton(filter.getDisplayName())); + super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId), true), Lookups.singleton(filter.getDisplayName())); this.filter = filter; this.datasourceObjId = dsObjId; init(); @@ -366,7 +367,7 @@ public class DeletedContent implements AutopsyVisitableItem { private final SleuthkitCase skCase; private final DeletedContent.DeletedContentFilter filter; private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName()); - private static final int MAX_OBJECTS = 10001; + private final Observable notifier; private final long datasourceObjId; @@ -385,7 +386,7 @@ public class DeletedContent implements AutopsyVisitableItem { @Override public void update(Observable o, Object arg) { refresh(true); - } + } } @Override @@ -408,18 +409,19 @@ public class DeletedContent implements AutopsyVisitableItem { + "There are more Deleted Files than can be displayed." + " Only the first {0} Deleted Files will be shown."}) protected boolean createKeys(List list) { + DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault(); List queryList = runFsQuery(); - if (queryList.size() == MAX_OBJECTS) { + if (deletedPreferences.getShouldLimitDeletedFiles() && queryList.size() == deletedPreferences.getDeletedFilesLimit()) { queryList.remove(queryList.size() - 1); // only show the dialog once - not each time we refresh if (maxFilesDialogShown == false) { maxFilesDialogShown = true; SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), - DeletedContent_createKeys_maxObjects_msg(MAX_OBJECTS - 1)) + DeletedContent_createKeys_maxObjects_msg(deletedPreferences.getDeletedFilesLimit() - 1)) ); } - } + } list.addAll(queryList); return true; } @@ -463,10 +465,12 @@ public class DeletedContent implements AutopsyVisitableItem { } if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) { - query += " AND data_source_obj_id = " + filteringDSObjId; + query += " AND data_source_obj_id = " + filteringDSObjId; + } + DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault(); + if (deletedPreferences.getShouldLimitDeletedFiles()) { + query += " LIMIT " + deletedPreferences.getDeletedFilesLimit(); //NON-NLS } - - query += " LIMIT " + MAX_OBJECTS; //NON-NLS return query; } diff --git a/Core/src/org/sleuthkit/autopsy/deletedFiles/DeletedFilePreferences.java b/Core/src/org/sleuthkit/autopsy/deletedFiles/DeletedFilePreferences.java new file mode 100644 index 0000000000..4eadd3611d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/deletedFiles/DeletedFilePreferences.java @@ -0,0 +1,171 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.deletedFiles; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Properties; +import java.util.logging.Level; +import org.sleuthkit.autopsy.casemodule.CasePreferences; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; + +/** + * Class to store settings related to the display of deleted files. + */ +public class DeletedFilePreferences { + + private static final String SETTINGS_FILE = "DeletedFilePreferences.properties"; //NON-NLS + private static final String KEY_LIMIT_DELETED_FILES = "limitDeletedFiles"; //NON-NLS + private static final String KEY_LIMIT_VALUE = "limitValue"; + private static final String VALUE_TRUE = "true"; //NON-NLS + private static final String VALUE_FALSE = "false"; //NON-NLS + private static final int DEFAULT_MAX_OBJECTS = 10001; + private static final Logger logger = Logger.getLogger(CasePreferences.class.getName()); + private static DeletedFilePreferences defaultInstance; + private static boolean limitDeletedFiles = true; + private static int deletedFilesLimit = DEFAULT_MAX_OBJECTS; + + /** + * Get the settings for the display of deleted files. + * + * @return defaultInstance with freshly loaded + */ + public static synchronized DeletedFilePreferences getDefault() { + if (defaultInstance == null) { + defaultInstance = new DeletedFilePreferences(); + } + defaultInstance.loadFromStorage(); + return defaultInstance; + } + + /** + * Prevent instantiation. + */ + private DeletedFilePreferences() { + } + + /** + * Get the 'limitDeletedFiles' value. This can be true or false. It will + * default to true if it was not saved correctly previously.s + * + * @return true if the number of deleted files displayed should be limied, + * false if it should not be limited. + */ + public boolean getShouldLimitDeletedFiles() { + return limitDeletedFiles; + } + + /** + * Set the 'limitDeletedFiles' value to true or false. + * + * @param value true if the number of deleted files displayed should be + * limied, false if it should not be limited. + */ + public void setShouldLimitDeletedFiles(boolean value) { + limitDeletedFiles = value; + saveToStorage(); + DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe(); + } + + /** + * Get the 'limitValue' value. This is an interger value and will default to + * DEFAULT_MAX_OBJECTS if it was not previously saved correctly. + * + * @return an integer representing the max number of deleted files to display. + */ + public int getDeletedFilesLimit() { + return deletedFilesLimit; + } + + /** + * Set the 'limitValue' for max number of deleted files to display. + * + * @param value an integer representing the max number of deleted files to display. + */ + public void setDeletedFilesLimit(int value) { + deletedFilesLimit = value; + saveToStorage(); + DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe(); + + } + + /** + * Load deleted file preferences from the settings file. + */ + private void loadFromStorage() { + Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS + if (settingsFile.toFile().exists()) { + // Read the settings + try (InputStream inputStream = Files.newInputStream(settingsFile)) { + Properties props = new Properties(); + props.load(inputStream); + String limitDeletedFilesValue = props.getProperty(KEY_LIMIT_DELETED_FILES); + if (limitDeletedFilesValue != null) { + switch (limitDeletedFilesValue) { + case VALUE_TRUE: + limitDeletedFiles = true; + break; + case VALUE_FALSE: + limitDeletedFiles = false; + break; + default: + logger.log(Level.WARNING, String.format("Unexpected value '%s' for limit deleted files using value of true instead", + limitDeletedFilesValue)); + limitDeletedFiles = true; + break; + } + } + String limitValue = props.getProperty(KEY_LIMIT_VALUE); + try { + if (limitValue != null) { + deletedFilesLimit = Integer.valueOf(limitValue); + + } + } catch (NumberFormatException ex) { + logger.log(Level.INFO, String.format("Unexpected value '%s' for limit, expected an integer using default of 10,001 instead", + limitValue)); + deletedFilesLimit = DEFAULT_MAX_OBJECTS; + } + } catch (IOException ex) { + logger.log(Level.SEVERE, "Error reading deletedFilesPreferences file", ex); + } + } + } + + /** + * Store deleted file preferences in the settings file. + */ + private void saveToStorage() { + Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS + Properties props = new Properties(); + props.setProperty(KEY_LIMIT_DELETED_FILES, (limitDeletedFiles ? VALUE_TRUE : VALUE_FALSE)); + props.setProperty(KEY_LIMIT_VALUE, String.valueOf(deletedFilesLimit)); + try (OutputStream fos = Files.newOutputStream(settingsFile)) { + props.store(fos, ""); //NON-NLS + } catch (IOException ex) { + logger.log(Level.SEVERE, "Error writing deletedFilesPreferences file", ex); + } + } +} From 9230451cb79a988b459b8a2835cf27b1f3fb972a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sat, 13 Oct 2018 21:08:04 -0400 Subject: [PATCH 22/25] Remove SQLiteUtil from public API for future work --- .../org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java | 1 - .../autopsy/{coreutils => contentviewers}/SqliteUtil.java | 4 ++-- .../core/core.jar/org/netbeans/core/startup/Bundle.properties | 2 +- .../org/netbeans/core/windows/view/ui/Bundle.properties | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) rename Core/src/org/sleuthkit/autopsy/{coreutils => contentviewers}/SqliteUtil.java (98%) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java index 576dc4f94e..9c09ca01ca 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java @@ -53,7 +53,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.coreutils.SqliteUtil; /** * A file content viewer for SQLite database files. diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/SqliteUtil.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SqliteUtil.java similarity index 98% rename from Core/src/org/sleuthkit/autopsy/coreutils/SqliteUtil.java rename to Core/src/org/sleuthkit/autopsy/contentviewers/SqliteUtil.java index 4250487298..4fc220cf0d 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/SqliteUtil.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SqliteUtil.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.coreutils; +package org.sleuthkit.autopsy.contentviewers; import java.io.File; import java.io.IOException; @@ -34,7 +34,7 @@ import org.sleuthkit.datamodel.TskCoreException; * Sqlite utility class. Find and copy metafiles, write sqlite abstract files to * temp directory, and generate unique temp directory paths. */ -public final class SqliteUtil { +final class SqliteUtil { private SqliteUtil() { diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 088cafd41a..91571da9bf 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Fri, 05 Oct 2018 09:58:28 -0400 +#Sat, 13 Oct 2018 21:02:18 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 5678704094..90fb6cf276 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Fri, 05 Oct 2018 09:58:28 -0400 +#Sat, 13 Oct 2018 21:02:18 -0400 CTL_MainWindow_Title=Autopsy 4.9.0 CTL_MainWindow_Title_No_Project=Autopsy 4.9.0 From 66476b9693d655efb24434b870438a8789e60870 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Sun, 14 Oct 2018 21:47:11 -0400 Subject: [PATCH 23/25] fix Keyword Search SQLiteUtil compile error --- .../keywordsearch/SqliteTextExtractor.java | 1 - .../autopsy/keywordsearch/SqliteUtil.java | 130 ++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100755 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteUtil.java diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteTextExtractor.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteTextExtractor.java index f5cebb42d3..c8bbe289e4 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteTextExtractor.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteTextExtractor.java @@ -33,7 +33,6 @@ import java.util.LinkedList; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.SqliteUtil; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteUtil.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteUtil.java new file mode 100755 index 0000000000..08eefe7232 --- /dev/null +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SqliteUtil.java @@ -0,0 +1,130 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2018-2018 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.keywordsearch; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.casemodule.services.Services; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Sqlite utility class. Find and copy metafiles, write sqlite abstract files to + * temp directory, and generate unique temp directory paths. + */ +final class SqliteUtil { + + private SqliteUtil() { + + } + + /** + * Overloaded implementation of + * {@link #findAndCopySQLiteMetaFile(AbstractFile, String) findAndCopySQLiteMetaFile} + * , automatically tries to copy -wal and -shm files without needing to know + * their existence. + * + * @param sqliteFile file which has -wal and -shm meta files + * + * @throws NoCurrentCaseException Case has been closed. + * @throws TskCoreException fileManager cannot find AbstractFile + * files. + * @throws IOException Issue during writing to file. + */ + public static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile) + throws NoCurrentCaseException, TskCoreException, IOException { + + findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal"); + findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm"); + } + + /** + * Searches for a meta file associated with the give SQLite database. If + * found, it copies this file into the temp directory of the current case. + * + * @param sqliteFile file being processed + * @param metaFileName name of meta file to look for + * + * @throws NoCurrentCaseException Case has been closed. + * @throws TskCoreException fileManager cannot find AbstractFile + * files. + * @throws IOException Issue during writing to file. + */ + public static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile, + String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException { + + Case openCase = Case.getCurrentCaseThrows(); + SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase(); + Services services = new Services(sleuthkitCase); + FileManager fileManager = services.getFileManager(); + + List metaFiles = fileManager.findFiles( + sqliteFile.getDataSource(), metaFileName, + sqliteFile.getParent().getName()); + + if (metaFiles != null) { + for (AbstractFile metaFile : metaFiles) { + writeAbstractFileToLocalDisk(metaFile); + } + } + } + + /** + * Copies the file contents into a unique path in the current case temp + * directory. + * + * @param file AbstractFile from the data source + * + * @return The path of the file on disk + * + * @throws IOException Exception writing file contents + * @throws NoCurrentCaseException Current case closed during file copying + */ + public static String writeAbstractFileToLocalDisk(AbstractFile file) + throws IOException, NoCurrentCaseException { + + String localDiskPath = getUniqueTempDirectoryPath(file); + File localDatabaseFile = new File(localDiskPath); + if (!localDatabaseFile.exists()) { + ContentUtils.writeToFile(file, localDatabaseFile); + } + return localDiskPath; + } + + /** + * Generates a unique local disk path that resides in the temp directory of + * the current case. + * + * @param file The database abstract file + * + * @return Unique local disk path living in the temp directory of the case + * + * @throws org.sleuthkit.autopsy.casemodule.NoCurrentCaseException + */ + public static String getUniqueTempDirectoryPath(AbstractFile file) throws NoCurrentCaseException { + return Case.getCurrentCaseThrows().getTempDirectory() + + File.separator + file.getId() + file.getName(); + } +} From e032ab67e5873d67e2d1b587b81f6287fcbe2e3f Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Sun, 14 Oct 2018 23:54:27 -0400 Subject: [PATCH 24/25] Set to release --- nbproject/project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nbproject/project.properties b/nbproject/project.properties index 6b846f5808..fe54a129df 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -6,8 +6,8 @@ app.name=${branding.token} ### if left unset, version will default to today's date app.version=4.9.0 ### build.type must be one of: DEVELOPMENT, RELEASE -#build.type=RELEASE -build.type=DEVELOPMENT +build.type=RELEASE +#build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.experimental=Experimental From 5035b7074f63be5039363defd8f571af50cef826 Mon Sep 17 00:00:00 2001 From: Brian Carrier Date: Mon, 15 Oct 2018 15:02:00 -0400 Subject: [PATCH 25/25] Changed back to develop --- nbproject/project.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nbproject/project.properties b/nbproject/project.properties index fe54a129df..6b846f5808 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -6,8 +6,8 @@ app.name=${branding.token} ### if left unset, version will default to today's date app.version=4.9.0 ### build.type must be one of: DEVELOPMENT, RELEASE -build.type=RELEASE -#build.type=DEVELOPMENT +#build.type=RELEASE +build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.experimental=Experimental