From 0ae4510b18f154c39292b3441a1d16f707014c10 Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 2 Jun 2020 09:44:33 -0400 Subject: [PATCH 01/22] Throttle number of Extracted Content node refreshes to once every 5 seconds. --- .../autopsy/datamodel/ExtractedContent.java | 22 ++++++-- .../autopsy/datamodel/RefreshThrottler.java | 52 +++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index db7acfc739..0d6cf2d378 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -151,6 +152,8 @@ public class ExtractedContent implements AutopsyVisitableItem { // maps the artifact type to its child node private final HashMap typeNodeList = new HashMap<>(); + private final RefreshThrottler refreshThrottler = new RefreshThrottler(); + @SuppressWarnings("deprecation") TypeFactory() { super(); @@ -174,6 +177,10 @@ public class ExtractedContent implements AutopsyVisitableItem { private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { + if (!refreshThrottler.isRefreshDue()) { + return; + } + /** * This is a stop gap measure until a different way of handling * the closing of cases is worked out. Currently, remote events @@ -188,7 +195,8 @@ public class ExtractedContent implements AutopsyVisitableItem { */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) { - refresh(true); + refresh(false); + refreshThrottler.setLastRefreshTime(Instant.now()); } } catch (NoCurrentCaseException notUsed) { /** @@ -204,7 +212,7 @@ public class ExtractedContent implements AutopsyVisitableItem { */ try { Case.getCurrentCaseThrows(); - refresh(true); + refresh(false); } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. @@ -358,6 +366,7 @@ public class ExtractedContent implements AutopsyVisitableItem { private class ArtifactFactory extends BaseChildFactory { private BlackboardArtifact.Type type; + private final RefreshThrottler refreshThrottler = new RefreshThrottler(); ArtifactFactory(BlackboardArtifact.Type type) { super(type.getTypeName()); @@ -369,6 +378,10 @@ public class ExtractedContent implements AutopsyVisitableItem { public void propertyChange(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { + if (!refreshThrottler.isRefreshDue()) { + return; + } + /** * Checking for a current case is a stop gap measure until a * different way of handling the closing of cases is worked @@ -385,7 +398,8 @@ public class ExtractedContent implements AutopsyVisitableItem { */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); if (null != event && event.getBlackboardArtifactType().equals(type)) { - refresh(true); + refresh(false); + refreshThrottler.setLastRefreshTime(Instant.now()); } } catch (NoCurrentCaseException notUsed) { /** @@ -402,7 +416,7 @@ public class ExtractedContent implements AutopsyVisitableItem { */ try { Case.getCurrentCaseThrows(); - refresh(true); + refresh(false); } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java new file mode 100644 index 0000000000..b098bb0230 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java @@ -0,0 +1,52 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2020 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.datamodel; + +import java.time.Instant; + +/** + * Utility class that can be used by UI nodes to reduce the number of + * potentially expensive UI refresh events. + */ +class RefreshThrottler { + + // The last time a refresh was performed. + private Instant lastRefreshTime; + private static final long MIN_SECONDS_BETWEEN_RERFESH = 5; + + RefreshThrottler() { + // Initialize to EPOCH to guarantee the first refresh + lastRefreshTime = Instant.EPOCH; + } + + /** + * @return true if a refresh is due, false otherwise + */ + boolean isRefreshDue() { + return Instant.now().isAfter(lastRefreshTime.plusSeconds(MIN_SECONDS_BETWEEN_RERFESH)); + } + + /** + * Update the last time a refresh was performed. + * @param refreshTime The last time a refresh was performed. + */ + void setLastRefreshTime(Instant refreshTime) { + lastRefreshTime = refreshTime; + } +} From bf929f1cd214be7e53729a611cd861adbe755102 Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 8 Jun 2020 17:05:55 -0400 Subject: [PATCH 02/22] Second pass at refresh throttling. --- .../autopsy/datamodel/ExtractedContent.java | 207 +++++++++--------- .../autopsy/datamodel/RefreshThrottler.java | 71 ++++-- 2 files changed, 153 insertions(+), 125 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 0d6cf2d378..16f66e9e48 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -146,13 +146,13 @@ public class ExtractedContent implements AutopsyVisitableItem { * This area has all of the blackboard artifacts that are not displayed in a * more specific form elsewhere in the tree. */ - private class TypeFactory extends ChildFactory.Detachable { + private class TypeFactory extends ChildFactory.Detachable implements RefreshThrottler.Refresher { private final ArrayList doNotShow = new ArrayList<>(); // maps the artifact type to its child node private final HashMap typeNodeList = new HashMap<>(); - private final RefreshThrottler refreshThrottler = new RefreshThrottler(); + private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); @SuppressWarnings("deprecation") TypeFactory() { @@ -176,49 +176,7 @@ public class ExtractedContent implements AutopsyVisitableItem { private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { - if (!refreshThrottler.isRefreshDue()) { - return; - } - - /** - * This 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(); - /** - * Due to some unresolved issues with how cases are closed, - * it is possible for the event to have a null oldValue if - * the event is a remote event. - */ - final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); - if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) { - refresh(false); - refreshThrottler.setLastRefreshTime(Instant.now()); - } - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { - /** - * This 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(); - refresh(false); - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { + if (eventType.equals(Case.Events.CURRENT_CASE.toString())) { // case was closed. Remove listeners so that we don't get called with a stale case handle if (evt.getNewValue() == null) { removeNotify(); @@ -229,15 +187,13 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override protected void addNotify() { - IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl); - IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl); + refreshThrottler.registerForIngestEvents(INGEST_JOB_EVENTS_OF_INTEREST, INGEST_MODULE_EVENTS_OF_INTEREST); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl); } @Override protected void removeNotify() { - IngestManager.getInstance().removeIngestJobEventListener(pcl); - IngestManager.getInstance().removeIngestModuleEventListener(pcl); + refreshThrottler.unregisterEventListener(); Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl); typeNodeList.clear(); } @@ -281,6 +237,49 @@ public class ExtractedContent implements AutopsyVisitableItem { typeNodeList.put(key, node); return node; } + + @Override + public void refresh(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { + /** + * This 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(); + /** + * Due to some unresolved issues with how cases are closed, + * it is possible for the event to have a null oldValue if + * the event is a remote event. + */ + final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); + if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) { + refresh(false); + } + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + /** + * This 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(); + refresh(false); + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } + } } /** @@ -363,79 +362,24 @@ public class ExtractedContent implements AutopsyVisitableItem { /** * Creates children for a given artifact type */ - private class ArtifactFactory extends BaseChildFactory { + private class ArtifactFactory extends BaseChildFactory implements RefreshThrottler.Refresher { private BlackboardArtifact.Type type; - private final RefreshThrottler refreshThrottler = new RefreshThrottler(); + private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); ArtifactFactory(BlackboardArtifact.Type type) { super(type.getTypeName()); this.type = type; } - private final PropertyChangeListener pcl = new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { - if (!refreshThrottler.isRefreshDue()) { - return; - } - - /** - * 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(); - /** - * Even with the check above, it is still possible that - * the case will be closed in a different thread before - * this code executes. If that happens, it is possible - * for the event to have a null oldValue. - */ - final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); - if (null != event && event.getBlackboardArtifactType().equals(type)) { - refresh(false); - refreshThrottler.setLastRefreshTime(Instant.now()); - } - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.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. - */ - try { - Case.getCurrentCaseThrows(); - refresh(false); - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } - } - }; - @Override protected void onAdd() { - IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl); - IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl); + refreshThrottler.registerForIngestEvents(INGEST_JOB_EVENTS_OF_INTEREST, INGEST_MODULE_EVENTS_OF_INTEREST); } @Override protected void onRemove() { - IngestManager.getInstance().removeIngestJobEventListener(pcl); - IngestManager.getInstance().removeIngestModuleEventListener(pcl); + refreshThrottler.unregisterEventListener(); } @Override @@ -465,5 +409,52 @@ public class ExtractedContent implements AutopsyVisitableItem { } return Collections.emptyList(); } + + @Override + public void refresh(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestModuleEvent.DATA_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. + */ + try { + Case.getCurrentCaseThrows(); + /** + * Even with the check above, it is still possible that the + * case will be closed in a different thread before this + * code executes. If that happens, it is possible for the + * event to have a null oldValue. + */ + final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); + if (null != event && event.getBlackboardArtifactType().equals(type)) { + refresh(false); + } + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.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. + */ + try { + Case.getCurrentCaseThrows(); + refresh(false); + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java index b098bb0230..5e55ca758f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java @@ -18,7 +18,16 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.time.Instant; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Set; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent; +import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent; /** * Utility class that can be used by UI nodes to reduce the number of @@ -26,27 +35,55 @@ import java.time.Instant; */ class RefreshThrottler { - // The last time a refresh was performed. - private Instant lastRefreshTime; + interface Refresher { + + void refresh(PropertyChangeEvent evt); + } + + static ScheduledThreadPoolExecutor refreshExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("Node Refresh Thread").build()); + private final AtomicReference refreshTaskRef = new AtomicReference<>(null); + + private final Refresher refresher; + private static final long MIN_SECONDS_BETWEEN_RERFESH = 5; - RefreshThrottler() { - // Initialize to EPOCH to guarantee the first refresh - lastRefreshTime = Instant.EPOCH; + private final class RefreshTask implements Runnable { + + private final PropertyChangeEvent event; + + RefreshTask(PropertyChangeEvent event) { + this.event = event; + } + + @Override + public void run() { + refresher.refresh(event); + refreshTaskRef.set(null); + } } - /** - * @return true if a refresh is due, false otherwise - */ - boolean isRefreshDue() { - return Instant.now().isAfter(lastRefreshTime.plusSeconds(MIN_SECONDS_BETWEEN_RERFESH)); + private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString()) + || eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { + RefreshTask task = new RefreshTask(evt); + if (refreshTaskRef.compareAndSet(null, task)) { + refreshExecutor.schedule(task, MIN_SECONDS_BETWEEN_RERFESH, TimeUnit.SECONDS); + } + } + }; + + RefreshThrottler(Refresher r) { + refresher = r; } - /** - * Update the last time a refresh was performed. - * @param refreshTime The last time a refresh was performed. - */ - void setLastRefreshTime(Instant refreshTime) { - lastRefreshTime = refreshTime; + void registerForIngestEvents(Set jobEventsOfInterest, Set moduleEventsOfInterest) { + IngestManager.getInstance().addIngestJobEventListener(jobEventsOfInterest, pcl); + IngestManager.getInstance().addIngestModuleEventListener(moduleEventsOfInterest, pcl); + } + + void unregisterEventListener() { + IngestManager.getInstance().removeIngestJobEventListener(pcl); + IngestManager.getInstance().removeIngestModuleEventListener(pcl); } } From 752538e76ac792903021dee25e96b188c9650ea7 Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 9 Jun 2020 12:40:42 -0400 Subject: [PATCH 03/22] Changed module event refresh. Added comments. --- .../autopsy/datamodel/ExtractedContent.java | 9 ++-- .../autopsy/datamodel/RefreshThrottler.java | 43 ++++++++++++++++--- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 16f66e9e48..789faedc04 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -64,7 +64,6 @@ import org.sleuthkit.datamodel.TskCoreException; public class ExtractedContent implements AutopsyVisitableItem { private static final Set INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.COMPLETED, IngestManager.IngestJobEvent.CANCELLED); - private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); public static final String NAME = NbBundle.getMessage(RootNode.class, "ExtractedContentNode.name.text"); private final long filteringDSObjId; // 0 if not filtering/grouping by data source private SleuthkitCase skCase; // set to null after case has been closed @@ -187,13 +186,15 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override protected void addNotify() { - refreshThrottler.registerForIngestEvents(INGEST_JOB_EVENTS_OF_INTEREST, INGEST_MODULE_EVENTS_OF_INTEREST); + refreshThrottler.registerForIngestModuleEvents(); + IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl); Case.addEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl); } @Override protected void removeNotify() { refreshThrottler.unregisterEventListener(); + IngestManager.getInstance().removeIngestJobEventListener(pcl); Case.removeEventTypeSubscriber(EnumSet.of(Case.Events.CURRENT_CASE), pcl); typeNodeList.clear(); } @@ -364,7 +365,7 @@ public class ExtractedContent implements AutopsyVisitableItem { */ private class ArtifactFactory extends BaseChildFactory implements RefreshThrottler.Refresher { - private BlackboardArtifact.Type type; + private final BlackboardArtifact.Type type; private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); ArtifactFactory(BlackboardArtifact.Type type) { @@ -374,7 +375,7 @@ public class ExtractedContent implements AutopsyVisitableItem { @Override protected void onAdd() { - refreshThrottler.registerForIngestEvents(INGEST_JOB_EVENTS_OF_INTEREST, INGEST_MODULE_EVENTS_OF_INTEREST); + refreshThrottler.registerForIngestModuleEvents(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java index 5e55ca758f..46f368f553 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java @@ -21,13 +21,12 @@ package org.sleuthkit.autopsy.datamodel; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.EnumSet; import java.util.Set; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent; -import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent; /** * Utility class that can be used by UI nodes to reduce the number of @@ -35,20 +34,40 @@ import org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent; */ class RefreshThrottler { + /** + * The Refresher interface needs to be implemented by ChildFactory instances + * that wish to take advantage of throttled refresh functionality. + */ interface Refresher { + /** + * The RefreshThrottler calls this method when the RefreshTask runs. + * + * @param evt The event that happened to occur at the time a new refresh + * was due. + */ void refresh(PropertyChangeEvent evt); } static ScheduledThreadPoolExecutor refreshExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("Node Refresh Thread").build()); + + // Keep a thread safe reference to the current refresh task (if any) private final AtomicReference refreshTaskRef = new AtomicReference<>(null); + // The factory instance that will be called when a refresh is due. private final Refresher refresher; private static final long MIN_SECONDS_BETWEEN_RERFESH = 5; + private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); + + /** + * A RefreshTask is scheduled to run when an event arrives and there isn't + * one already scheduled. + */ private final class RefreshTask implements Runnable { + // The event that happened to occur when this task was scheduled. private final PropertyChangeEvent event; RefreshTask(PropertyChangeEvent event) { @@ -57,11 +76,17 @@ class RefreshThrottler { @Override public void run() { + // Call refresh on the factory refresher.refresh(event); + // Clear the refresh task reference refreshTaskRef.set(null); } } + /** + * PropertyChangeListener that reacts to DATA_ADDED and CONTENT_CHANGED + * events and schedules a refresh task if one is not already scheduled. + */ private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString()) @@ -77,13 +102,17 @@ class RefreshThrottler { refresher = r; } - void registerForIngestEvents(Set jobEventsOfInterest, Set moduleEventsOfInterest) { - IngestManager.getInstance().addIngestJobEventListener(jobEventsOfInterest, pcl); - IngestManager.getInstance().addIngestModuleEventListener(moduleEventsOfInterest, pcl); + /** + * Set up listener for ingest module events of interest. + */ + void registerForIngestModuleEvents() { + IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl); } - + + /** + * Remove ingest module event listener. + */ void unregisterEventListener() { - IngestManager.getInstance().removeIngestJobEventListener(pcl); IngestManager.getInstance().removeIngestModuleEventListener(pcl); } } From 751edacd7f03cda91412a5a7547cc0717a1e8ff5 Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 9 Jun 2020 12:41:44 -0400 Subject: [PATCH 04/22] Removed unneeded import. --- Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index 789faedc04..bd72024722 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.datamodel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; From a59a60f1d3c1d4cccb2bc3c3ac9f98cad88ba206 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 9 Jun 2020 15:13:06 -0400 Subject: [PATCH 05/22] 6457-discovery ui polish --- .../discovery/Bundle.properties-MERGED | 61 +++++++++-------- .../autopsy/discovery/DiscoveryDialog.form | 20 +++--- .../autopsy/discovery/DiscoveryDialog.java | 18 ++--- .../discovery/DiscoveryTopComponent.java | 19 ++++++ .../autopsy/discovery/FileSearchData.java | 68 +++++++++++-------- .../discovery/FileSearchFiltering.java | 33 ++++----- 6 files changed, 127 insertions(+), 92 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index 0779798a6e..50de856d7b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -57,18 +57,24 @@ FileSearch.InterestingItemGroupKey.noSets=None FileSearch.KeywordListGroupKey.noKeywords=None FileSearch.NoGroupingGroupKey.allFiles=All Files FileSearch.ObjectDetectedGroupKey.noSets=None -FileSearchData.FileSize.LARGE_IMAGE.displayName=Large: 1-50MB -FileSearchData.FileSize.LARGE_VIDEO.displayName=Large: 1-5GB -FileSearchData.FileSize.MEDIUM_IMAGE.displayName=Medium: 100KB-1MB -FileSearchData.FileSize.MEDIUM_VIDEO.displayName=Medium: 100MB-1GB -FileSearchData.FileSize.SMALL_IMAGE.displayName=Small: 16-100KB -FileSearchData.FileSize.SMALL_VIDEO.displayName=Small: 500KB-100MB -FileSearchData.FileSize.XLARGE_IMAGE.displayName=XLarge: 50-200MB -FileSearchData.FileSize.XLARGE_VIDEO.displayName=XLarge: 5-10GB -FileSearchData.FileSize.XSMALL_IMAGE.displayName=XSmall: 0-16KB -FileSearchData.FileSize.XSMALL_VIDEO.displayName=XSmall: 0-500KB -FileSearchData.FileSize.XXLARGE_IMAGE.displayName=XXLarge: 200MB+ -FileSearchData.FileSize.XXLARGE_VIDEO.displayName=XXLarge: 10GB+ +FileSearchData.FileSize.100kbto1mb=: 100KB-1MB +FileSearchData.FileSize.100mbto1gb=: 100MB-1GB +FileSearchData.FileSize.10PlusGb=: 10GB+ +FileSearchData.FileSize.16kbto100kb=: 16-100KB +FileSearchData.FileSize.1gbto5gb=: 1-5GB +FileSearchData.FileSize.1mbto50mb=: 1-50MB +FileSearchData.FileSize.200PlusMb=: 200MB+ +FileSearchData.FileSize.500kbto100mb=: 500KB-100MB +FileSearchData.FileSize.50mbto200mb=: 50-200MB +FileSearchData.FileSize.5gbto10gb=: 5-10GB +FileSearchData.FileSize.LARGE.displayName=Large +FileSearchData.FileSize.MEDIUM.displayName=Medium +FileSearchData.FileSize.SMALL.displayName=Small +FileSearchData.FileSize.upTo16kb=: 0-16KB +FileSearchData.FileSize.upTo500kb=: 0-500KB +FileSearchData.FileSize.XLARGE.displayName=XLarge +FileSearchData.FileSize.XSMALL.displayName=XSmall +FileSearchData.FileSize.XXLARGE.displayName=XXLarge FileSearchData.FileType.Audio.displayName=Audio FileSearchData.FileType.Documents.displayName=Documents FileSearchData.FileType.Executables.displayName=Executables @@ -106,25 +112,25 @@ FileSearchFiltering.concatenateSetNamesForDisplay.comma=, # {1} - Data source ID FileSearchFiltering.DataSourceFilter.datasource={0}({1}) # {0} - filters -FileSearchFiltering.DataSourceFilter.desc=Files in data source(s): {0} +FileSearchFiltering.DataSourceFilter.desc=In data source(s): {0} FileSearchFiltering.DataSourceFilter.or=\ or # {0} - filters FileSearchFiltering.FileTypeFilter.desc=Files with type: {0} FileSearchFiltering.FileTypeFilter.or=\ or # {0} - filters -FileSearchFiltering.FrequencyFilter.desc=Files with frequency: {0} +FileSearchFiltering.FrequencyFilter.desc=With frequency: {0} FileSearchFiltering.FrequencyFilter.or=\ or # {0} - filters -FileSearchFiltering.HashSetFilter.desc=Files with hash set hits in set(s): {0} +FileSearchFiltering.HashSetFilter.desc=With hash set hits in set(s): {0} # {0} - filters -FileSearchFiltering.InterestingItemSetFilter.desc=Files with interesting item hits in set(s): {0} +FileSearchFiltering.InterestingItemSetFilter.desc=With interesting item hits in set(s): {0} # {0} - filters -FileSearchFiltering.KeywordListFilter.desc=Files with keywords in list(s): {0} -FileSearchFiltering.KnownFilter.desc=Files which are not known +FileSearchFiltering.KeywordListFilter.desc=With keywords in list(s): {0} +FileSearchFiltering.KnownFilter.desc=Which are not known # {0} - filters -FileSearchFiltering.ObjectDetectionFilter.desc=Files with objects detected in set(s): {0} +FileSearchFiltering.ObjectDetectionFilter.desc=With objects detected in set(s): {0} # {0} - filters -FileSearchFiltering.ParentFilter.desc=Files with paths matching: {0} +FileSearchFiltering.ParentFilter.desc=With paths matching: {0} FileSearchFiltering.ParentFilter.exact=(exact match) FileSearchFiltering.ParentFilter.or=\ or FileSearchFiltering.ParentFilter.substring=(substring) @@ -132,19 +138,16 @@ FileSearchFiltering.ParentSearchTerm.excludeString=\ (exclude) FileSearchFiltering.ParentSearchTerm.fullString=\ (exact) FileSearchFiltering.ParentSearchTerm.includeString=\ (include) FileSearchFiltering.ParentSearchTerm.subString=\ (substring) -FileSearchFiltering.PreviouslyNotableFilter.desc=Files that were previously marked as notable +FileSearchFiltering.PreviouslyNotableFilter.desc=That were previously marked as notable # {0} - filters -FileSearchFiltering.ScoreFilter.desc=Files with score(s) of : {0} +FileSearchFiltering.ScoreFilter.desc=With score(s) of : {0} # {0} - filters -FileSearchFiltering.SizeFilter.desc=Files with size in range(s): {0} -FileSearchFiltering.SizeFilter.or=\ or -# {0} - Minimum bytes -# {1} - Maximum bytes -FileSearchFiltering.SizeFilter.range=({0} to {1}) +FileSearchFiltering.SizeFilter.desc=With size(s): {0} +FileSearchFiltering.SizeFilter.or=, or # {0} - tag names -FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0} +FileSearchFiltering.TagsFilter.desc=That have been tagged {0} FileSearchFiltering.TagsFilter.or=\ or -FileSearchFiltering.UserCreatedFilter.desc=Files that contain EXIF data +FileSearchFiltering.UserCreatedFilter.desc=That contain EXIF data FileSearchPanel.sortingPanel.border.title=Grouping FileSearchPanel.addButton.text=Add FileSearchPanel.substringRadioButton.text=Substring diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form index d19a7dda96..19116a24fe 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form @@ -43,23 +43,25 @@ - - - - - - - - + + + + + + + + + + + - diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 948dbd4bee..33f69712f0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -275,19 +275,21 @@ final class DiscoveryDialog extends javax.swing.JDialog { toolBarPanelLayout.setHorizontalGroup( toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(toolBarPanelLayout.createSequentialGroup() - .addContainerGap(196, Short.MAX_VALUE) - .addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, toolBarPanelLayout.createSequentialGroup() - .addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(step1Label, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap() + .addGroup(toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(toolBarPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) .addComponent(imagesButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(videosButton, javax.swing.GroupLayout.PREFERRED_SIZE, 110, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(documentsButton))) - .addContainerGap(196, Short.MAX_VALUE)) + .addComponent(documentsButton) + .addContainerGap(370, Short.MAX_VALUE)) + .addGroup(toolBarPanelLayout.createSequentialGroup() + .addComponent(step1Label, javax.swing.GroupLayout.PREFERRED_SIZE, 243, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(filler1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(391, Short.MAX_VALUE)))) ); toolBarPanelLayout.setVerticalGroup( toolBarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 30341184ad..0b33929a2a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -24,6 +24,9 @@ import java.awt.Graphics; import java.util.List; import java.util.stream.Collectors; import javax.swing.JSplitPane; +import javax.swing.border.Border; +import javax.swing.plaf.basic.BasicSplitPaneDivider; +import javax.swing.plaf.basic.BasicSplitPaneUI; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.windows.Mode; @@ -67,6 +70,22 @@ public final class DiscoveryTopComponent extends TopComponent { mainSplitPane.setLeftComponent(groupListPanel); rightSplitPane.setTopComponent(resultsPanel); rightSplitPane.setBottomComponent(detailsPanel); + //set color of divider + rightSplitPane.setUI(new BasicSplitPaneUI() { + @Override + public BasicSplitPaneDivider createDefaultDivider() { + return new BasicSplitPaneDivider(this) { + private static final long serialVersionUID = 1L; + + @Override + public void paint(Graphics g) { + g.setColor(Color.YELLOW); + g.fillRect(0, 0, getSize().width, getSize().height); + super.paint(g); + } + }; + } + }); } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java index 7ef5e1188f..a9c54d3d98 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchData.java @@ -126,39 +126,46 @@ final class FileSearchData { * Enum representing the file size */ @NbBundle.Messages({ - "FileSearchData.FileSize.XXLARGE_IMAGE.displayName=XXLarge: 200MB+", - "FileSearchData.FileSize.XLARGE_IMAGE.displayName=XLarge: 50-200MB", - "FileSearchData.FileSize.LARGE_IMAGE.displayName=Large: 1-50MB", - "FileSearchData.FileSize.MEDIUM_IMAGE.displayName=Medium: 100KB-1MB", - "FileSearchData.FileSize.SMALL_IMAGE.displayName=Small: 16-100KB", - "FileSearchData.FileSize.XSMALL_IMAGE.displayName=XSmall: 0-16KB", - "FileSearchData.FileSize.XXLARGE_VIDEO.displayName=XXLarge: 10GB+", - "FileSearchData.FileSize.XLARGE_VIDEO.displayName=XLarge: 5-10GB", - "FileSearchData.FileSize.LARGE_VIDEO.displayName=Large: 1-5GB", - "FileSearchData.FileSize.MEDIUM_VIDEO.displayName=Medium: 100MB-1GB", - "FileSearchData.FileSize.SMALL_VIDEO.displayName=Small: 500KB-100MB", - "FileSearchData.FileSize.XSMALL_VIDEO.displayName=XSmall: 0-500KB",}) + "FileSearchData.FileSize.XXLARGE.displayName=XXLarge", + "FileSearchData.FileSize.XLARGE.displayName=XLarge", + "FileSearchData.FileSize.LARGE.displayName=Large", + "FileSearchData.FileSize.MEDIUM.displayName=Medium", + "FileSearchData.FileSize.SMALL.displayName=Small", + "FileSearchData.FileSize.XSMALL.displayName=XSmall", + "FileSearchData.FileSize.10PlusGb=: 10GB+", + "FileSearchData.FileSize.5gbto10gb=: 5-10GB", + "FileSearchData.FileSize.1gbto5gb=: 1-5GB", + "FileSearchData.FileSize.100mbto1gb=: 100MB-1GB", + "FileSearchData.FileSize.200PlusMb=: 200MB+", + "FileSearchData.FileSize.50mbto200mb=: 50-200MB", + "FileSearchData.FileSize.500kbto100mb=: 500KB-100MB", + "FileSearchData.FileSize.1mbto50mb=: 1-50MB", + "FileSearchData.FileSize.100kbto1mb=: 100KB-1MB", + "FileSearchData.FileSize.16kbto100kb=: 16-100KB", + "FileSearchData.FileSize.upTo500kb=: 0-500KB", + "FileSearchData.FileSize.upTo16kb=: 0-16KB",}) enum FileSize { - XXLARGE_VIDEO(0, 10000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_VIDEO_displayName()), - XLARGE_VIDEO(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_VIDEO_displayName()), - LARGE_VIDEO(2, 1000 * BYTES_PER_MB, 5000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_VIDEO_displayName()), - MEDIUM_VIDEO(3, 100 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_VIDEO_displayName()), - SMALL_VIDEO(4, 500000, 100 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_SMALL_VIDEO_displayName()), - XSMALL_VIDEO(5, 0, 500000, Bundle.FileSearchData_FileSize_XSMALL_VIDEO_displayName()), - XXLARGE_IMAGE(6, 200 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_IMAGE_displayName()), - XLARGE_IMAGE(7, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_IMAGE_displayName()), - LARGE_IMAGE(8, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_IMAGE_displayName()), - MEDIUM_IMAGE(9, 100000, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_IMAGE_displayName()), - SMALL_IMAGE(10, 16000, 100000, Bundle.FileSearchData_FileSize_SMALL_IMAGE_displayName()), - XSMALL_IMAGE(11, 0, 16000, Bundle.FileSearchData_FileSize_XSMALL_IMAGE_displayName()); + XXLARGE_VIDEO(0, 10000 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_displayName(), Bundle.FileSearchData_FileSize_10PlusGb()), + XLARGE_VIDEO(1, 5000 * BYTES_PER_MB, 10000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_displayName(), Bundle.FileSearchData_FileSize_5gbto10gb()), + LARGE_VIDEO(2, 1000 * BYTES_PER_MB, 5000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_displayName(), Bundle.FileSearchData_FileSize_1gbto5gb()), + MEDIUM_VIDEO(3, 100 * BYTES_PER_MB, 1000 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_displayName(), Bundle.FileSearchData_FileSize_100mbto1gb()), + SMALL_VIDEO(4, 500000, 100 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_SMALL_displayName(), Bundle.FileSearchData_FileSize_500kbto100mb()), + XSMALL_VIDEO(5, 0, 500000, Bundle.FileSearchData_FileSize_XSMALL_displayName(), Bundle.FileSearchData_FileSize_upTo500kb()), + XXLARGE_IMAGE(6, 200 * BYTES_PER_MB, -1, Bundle.FileSearchData_FileSize_XXLARGE_displayName(), Bundle.FileSearchData_FileSize_200PlusMb()), + XLARGE_IMAGE(7, 50 * BYTES_PER_MB, 200 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_XLARGE_displayName(), Bundle.FileSearchData_FileSize_50mbto200mb()), + LARGE_IMAGE(8, 1 * BYTES_PER_MB, 50 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_LARGE_displayName(), Bundle.FileSearchData_FileSize_1mbto50mb()), + MEDIUM_IMAGE(9, 100000, 1 * BYTES_PER_MB, Bundle.FileSearchData_FileSize_MEDIUM_displayName(), Bundle.FileSearchData_FileSize_100kbto1mb()), + SMALL_IMAGE(10, 16000, 100000, Bundle.FileSearchData_FileSize_SMALL_displayName(), Bundle.FileSearchData_FileSize_16kbto100kb()), + XSMALL_IMAGE(11, 0, 16000, Bundle.FileSearchData_FileSize_XSMALL_displayName(), Bundle.FileSearchData_FileSize_upTo16kb()); private final int ranking; // Must be unique for each value private final long minBytes; // Note that the size must be strictly greater than this to match private final long maxBytes; - private final String displayName; + private final String sizeGroup; + private final String displaySize; final static long NO_MAXIMUM = -1; - FileSize(int ranking, long minB, long maxB, String displayName) { + FileSize(int ranking, long minB, long maxB, String displayName, String displaySize) { this.ranking = ranking; this.minBytes = minB; if (maxB >= 0) { @@ -166,7 +173,8 @@ final class FileSearchData { } else { this.maxBytes = NO_MAXIMUM; } - this.displayName = displayName; + this.sizeGroup = displayName; + this.displaySize = displaySize; } /** @@ -246,7 +254,11 @@ final class FileSearchData { @Override public String toString() { - return displayName; + return sizeGroup + displaySize; + } + + String getSizeGroup(){ + return sizeGroup; } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java index 326bc7c15c..bfcf309835 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java @@ -207,11 +207,8 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.SizeFilter.desc=Files with size in range(s): {0}", - "FileSearchFiltering.SizeFilter.or= or ", - "# {0} - Minimum bytes", - "# {1} - Maximum bytes", - "FileSearchFiltering.SizeFilter.range=({0} to {1})",}) + "FileSearchFiltering.SizeFilter.desc=With size(s): {0}", + "FileSearchFiltering.SizeFilter.or=, or "}) @Override String getDesc() { String desc = ""; // NON-NLS @@ -219,7 +216,7 @@ class FileSearchFiltering { if (!desc.isEmpty()) { desc += Bundle.FileSearchFiltering_SizeFilter_or(); } - desc += Bundle.FileSearchFiltering_SizeFilter_range(size.getMinBytes(), size.getMaxBytes()); + desc += size.getSizeGroup(); } desc = Bundle.FileSearchFiltering_SizeFilter_desc(desc); return desc; @@ -364,7 +361,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ParentFilter.desc=Files with paths matching: {0}", + "FileSearchFiltering.ParentFilter.desc=With paths matching: {0}", "FileSearchFiltering.ParentFilter.or= or ", "FileSearchFiltering.ParentFilter.exact=(exact match)", "FileSearchFiltering.ParentFilter.substring=(substring)",}) @@ -417,7 +414,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.DataSourceFilter.desc=Files in data source(s): {0}", + "FileSearchFiltering.DataSourceFilter.desc=In data source(s): {0}", "FileSearchFiltering.DataSourceFilter.or= or ", "# {0} - Data source name", "# {1} - Data source ID", @@ -466,7 +463,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.KeywordListFilter.desc=Files with keywords in list(s): {0}",}) + "FileSearchFiltering.KeywordListFilter.desc=With keywords in list(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames)); @@ -586,7 +583,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.FrequencyFilter.desc=Files with frequency: {0}", + "FileSearchFiltering.FrequencyFilter.desc=With frequency: {0}", "FileSearchFiltering.FrequencyFilter.or= or ",}) @Override String getDesc() { @@ -632,7 +629,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.HashSetFilter.desc=Files with hash set hits in set(s): {0}",}) + "FileSearchFiltering.HashSetFilter.desc=With hash set hits in set(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames)); @@ -670,7 +667,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.InterestingItemSetFilter.desc=Files with interesting item hits in set(s): {0}",}) + "FileSearchFiltering.InterestingItemSetFilter.desc=With interesting item hits in set(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames)); @@ -708,7 +705,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ObjectDetectionFilter.desc=Files with objects detected in set(s): {0}",}) + "FileSearchFiltering.ObjectDetectionFilter.desc=With objects detected in set(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames)); @@ -784,7 +781,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ScoreFilter.desc=Files with score(s) of : {0}",}) + "FileSearchFiltering.ScoreFilter.desc=With score(s) of : {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_ScoreFilter_desc( @@ -826,7 +823,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - tag names", - "FileSearchFiltering.TagsFilter.desc=Files that have been tagged {0}", + "FileSearchFiltering.TagsFilter.desc=That have been tagged {0}", "FileSearchFiltering.TagsFilter.or= or ",}) @Override String getDesc() { @@ -862,7 +859,7 @@ class FileSearchFiltering { } @NbBundle.Messages({ - "FileSearchFiltering.UserCreatedFilter.desc=Files that contain EXIF data",}) + "FileSearchFiltering.UserCreatedFilter.desc=That contain EXIF data",}) @Override String getDesc() { return Bundle.FileSearchFiltering_UserCreatedFilter_desc(); @@ -931,7 +928,7 @@ class FileSearchFiltering { } @NbBundle.Messages({ - "FileSearchFiltering.PreviouslyNotableFilter.desc=Files that were previously marked as notable",}) + "FileSearchFiltering.PreviouslyNotableFilter.desc=That were previously marked as notable",}) @Override String getDesc() { return Bundle.FileSearchFiltering_PreviouslyNotableFilter_desc(); @@ -949,7 +946,7 @@ class FileSearchFiltering { } @NbBundle.Messages({ - "FileSearchFiltering.KnownFilter.desc=Files which are not known"}) + "FileSearchFiltering.KnownFilter.desc=Which are not known"}) @Override String getDesc() { return Bundle.FileSearchFiltering_KnownFilter_desc(); From ef4269933d6c8e467143b700e472d9f0b50605bb Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 10 Jun 2020 13:59:34 -0400 Subject: [PATCH 06/22] Changed to first check every event to see if it would result in a refresh. --- .../autopsy/datamodel/ExtractedContent.java | 103 ++++++++++++------ .../autopsy/datamodel/RefreshThrottler.java | 57 +++++----- 2 files changed, 99 insertions(+), 61 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java index bd72024722..8d9943ffc4 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContent.java @@ -150,6 +150,11 @@ public class ExtractedContent implements AutopsyVisitableItem { // maps the artifact type to its child node private final HashMap typeNodeList = new HashMap<>(); + /** + * RefreshThrottler is used to limit the number of refreshes performed + * when CONTENT_CHANGED and DATA_ADDED ingest module events are + * received. + */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); @SuppressWarnings("deprecation") @@ -180,6 +185,21 @@ public class ExtractedContent implements AutopsyVisitableItem { removeNotify(); skCase = null; } + } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { + /** + * This 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(); + refresh(false); + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } } }; @@ -239,7 +259,12 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - public void refresh(PropertyChangeEvent evt) { + public void refresh() { + refresh(false); + } + + @Override + public boolean isRefreshRequired(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { /** @@ -256,29 +281,15 @@ public class ExtractedContent implements AutopsyVisitableItem { */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); if (null != event && !(this.doNotShow.contains(event.getBlackboardArtifactType()))) { - refresh(false); + return true; } } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ } - } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { - /** - * This 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(); - refresh(false); - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } + } + return false; } } @@ -365,6 +376,12 @@ public class ExtractedContent implements AutopsyVisitableItem { private class ArtifactFactory extends BaseChildFactory implements RefreshThrottler.Refresher { private final BlackboardArtifact.Type type; + + /** + * RefreshThrottler is used to limit the number of refreshes performed + * when CONTENT_CHANGED and DATA_ADDED ingest module events are + * received. + */ private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); ArtifactFactory(BlackboardArtifact.Type type) { @@ -372,14 +389,37 @@ public class ExtractedContent implements AutopsyVisitableItem { this.type = type; } + private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.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. + */ + try { + Case.getCurrentCaseThrows(); + refresh(false); + } catch (NoCurrentCaseException notUsed) { + /** + * Case is closed, do nothing. + */ + } + } + }; + @Override protected void onAdd() { refreshThrottler.registerForIngestModuleEvents(); + IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl); } @Override protected void onRemove() { refreshThrottler.unregisterEventListener(); + IngestManager.getInstance().removeIngestJobEventListener(pcl); } @Override @@ -411,7 +451,12 @@ public class ExtractedContent implements AutopsyVisitableItem { } @Override - public void refresh(PropertyChangeEvent evt) { + public void refresh() { + refresh(false); + } + + @Override + public boolean isRefreshRequired(PropertyChangeEvent evt) { String eventType = evt.getPropertyName(); if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString())) { @@ -431,30 +476,16 @@ public class ExtractedContent implements AutopsyVisitableItem { */ final ModuleDataEvent event = (ModuleDataEvent) evt.getOldValue(); if (null != event && event.getBlackboardArtifactType().equals(type)) { - refresh(false); + return true; } - } catch (NoCurrentCaseException notUsed) { - /** - * Case is closed, do nothing. - */ - } - } else if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.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. - */ - try { - Case.getCurrentCaseThrows(); - refresh(false); + } catch (NoCurrentCaseException notUsed) { /** * Case is closed, do nothing. */ } } + return false; } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java index 46f368f553..f5a146dd94 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java @@ -30,7 +30,8 @@ import org.sleuthkit.autopsy.ingest.IngestManager; /** * Utility class that can be used by UI nodes to reduce the number of - * potentially expensive UI refresh events. + * potentially expensive UI refresh events when DATA_ADDED and CONTENT_CHANGED + * ingest manager events are received. */ class RefreshThrottler { @@ -43,23 +44,29 @@ class RefreshThrottler { /** * The RefreshThrottler calls this method when the RefreshTask runs. * - * @param evt The event that happened to occur at the time a new refresh - * was due. */ - void refresh(PropertyChangeEvent evt); + void refresh(); + + /** + * Determine whether the given event should result in a refresh. + * + * @param evt + * + * @return true if event should trigger a refresh, otherwise false. + */ + boolean isRefreshRequired(PropertyChangeEvent evt); } static ScheduledThreadPoolExecutor refreshExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactoryBuilder().setNameFormat("Node Refresh Thread").build()); - // Keep a thread safe reference to the current refresh task (if any) - private final AtomicReference refreshTaskRef = new AtomicReference<>(null); + private final AtomicReference refreshTaskRef; // The factory instance that will be called when a refresh is due. private final Refresher refresher; private static final long MIN_SECONDS_BETWEEN_RERFESH = 5; - private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED); + private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED, IngestManager.IngestModuleEvent.CONTENT_CHANGED); /** * A RefreshTask is scheduled to run when an event arrives and there isn't @@ -67,17 +74,10 @@ class RefreshThrottler { */ private final class RefreshTask implements Runnable { - // The event that happened to occur when this task was scheduled. - private final PropertyChangeEvent event; - - RefreshTask(PropertyChangeEvent event) { - this.event = event; - } - @Override public void run() { // Call refresh on the factory - refresher.refresh(event); + refresher.refresh(); // Clear the refresh task reference refreshTaskRef.set(null); } @@ -87,19 +87,26 @@ class RefreshThrottler { * PropertyChangeListener that reacts to DATA_ADDED and CONTENT_CHANGED * events and schedules a refresh task if one is not already scheduled. */ - private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> { - String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString()) - || eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { - RefreshTask task = new RefreshTask(evt); - if (refreshTaskRef.compareAndSet(null, task)) { - refreshExecutor.schedule(task, MIN_SECONDS_BETWEEN_RERFESH, TimeUnit.SECONDS); - } - } - }; + private final PropertyChangeListener pcl; RefreshThrottler(Refresher r) { + this.refreshTaskRef = new AtomicReference<>(null); refresher = r; + + pcl = (PropertyChangeEvent evt) -> { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestModuleEvent.DATA_ADDED.toString()) + || eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { + if (!refresher.isRefreshRequired(evt)) { + return; + } + + RefreshTask task = new RefreshTask(); + if (refreshTaskRef.compareAndSet(null, task)) { + refreshExecutor.schedule(task, MIN_SECONDS_BETWEEN_RERFESH, TimeUnit.SECONDS); + } + } + }; } /** From 60dae2406f988ffec3e7d00101d8b97ea1c50cb7 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 10 Jun 2020 14:02:54 -0400 Subject: [PATCH 07/22] Make FileTypesByExtension use RefreshThrottler. --- .../datamodel/FileTypesByExtension.java | 75 +++++++++++++------ 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 83b05019ca..a0db1eed65 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -82,39 +82,26 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { * Listens for case and ingest invest. Updates observers when events are * fired. FileType and FileTypes nodes are all listening to this. */ - private class FileTypesByExtObservable extends Observable { + private class FileTypesByExtObservable extends Observable implements RefreshThrottler.Refresher { private final PropertyChangeListener pcl; private final Set CASE_EVENTS_OF_INTEREST; + /** + * RefreshThrottler is used to limit the number of refreshes performed + * when CONTENT_CHANGED and DATA_ADDED ingest module events are + * received. + */ + private final RefreshThrottler refreshThrottler = new RefreshThrottler(this); private FileTypesByExtObservable() { super(); this.CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.DATA_SOURCE_ADDED, Case.Events.CURRENT_CASE); this.pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString()) || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { - /** - * If a new file has been added but does not have an extension - * there is nothing to do. - */ - if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) { - if ((evt.getOldValue() instanceof ModuleContentEvent) == false) { - return; - } - ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue(); - if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) { - return; - } - AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource(); - if (abstractFile.getNameExtension().isEmpty()) { - return; - } - } - /** * Checking for a current case is a stop gap measure until a * different way of handling the closing of cases is worked @@ -139,14 +126,14 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { }; IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl); - IngestManager.getInstance().addIngestModuleEventListener(INGEST_MODULE_EVENTS_OF_INTEREST, pcl); + refreshThrottler.registerForIngestModuleEvents(); Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl); } private void removeListeners() { deleteObservers(); IngestManager.getInstance().removeIngestJobEventListener(pcl); - IngestManager.getInstance().removeIngestModuleEventListener(pcl); + refreshThrottler.unregisterEventListener(); Case.removeEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl); } @@ -154,7 +141,49 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { setChanged(); notifyObservers(); } + + @Override + public void refresh() { + typesRoot.updateShowCounts(); + update(); + } + + @Override + public boolean isRefreshRequired(PropertyChangeEvent evt) { + String eventType = evt.getPropertyName(); + if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.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. + */ + try { + Case.getCurrentCaseThrows(); + /** + * If a new file has been added but does not have an + * extension there is nothing to do. + */ + if ((evt.getOldValue() instanceof ModuleContentEvent) == true) { + ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue(); + if ((moduleContentEvent.getSource() instanceof AbstractFile) == true) { + AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource(); + if (!abstractFile.getNameExtension().isEmpty()) { + return true; + } + } + } + } catch (NoCurrentCaseException ex) { + /** + * Case is closed, do nothing. + */ + } + } + return false; + } } + private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text"); /** From 1e4b6d28156d1fa3c2227330dd84127a2dcc1dba Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 10 Jun 2020 14:39:09 -0400 Subject: [PATCH 08/22] Shut Codacy up. --- .../datamodel/FileTypesByExtension.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index a0db1eed65..566545eecd 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -165,19 +165,22 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { * If a new file has been added but does not have an * extension there is nothing to do. */ - if ((evt.getOldValue() instanceof ModuleContentEvent) == true) { - ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue(); - if ((moduleContentEvent.getSource() instanceof AbstractFile) == true) { - AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource(); - if (!abstractFile.getNameExtension().isEmpty()) { - return true; - } - } + if ((evt.getOldValue() instanceof ModuleContentEvent) == false) { + return false; + } + ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue(); + if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) { + return false; + } + AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource(); + if (!abstractFile.getNameExtension().isEmpty()) { + return true; } } catch (NoCurrentCaseException ex) { /** - * Case is closed, do nothing. + * Case is closed, no refresh needed. */ + return false; } } return false; From 12326adbfd178d6621e5dd21f2b1fc1e7e339854 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 16 Jun 2020 10:25:00 -0400 Subject: [PATCH 09/22] 6457 adjustments to buttons for show/hide --- .../discovery/DiscoveryTopComponent.form | 2 +- .../discovery/DiscoveryTopComponent.java | 60 ++++++++++++++---- .../autopsy/discovery/arrow-down.png | Bin 0 -> 1264 bytes .../sleuthkit/autopsy/discovery/arrow-up.png | Bin 0 -> 1297 bytes 4 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/arrow-up.png diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form index 4e62b44cb9..d82dd550a8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form @@ -41,7 +41,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 0b33929a2a..69c23e0927 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -20,11 +20,16 @@ package org.sleuthkit.autopsy.discovery; import com.google.common.eventbus.Subscribe; import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Graphics; import java.util.List; import java.util.stream.Collectors; +import javax.swing.Box.Filler; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; import javax.swing.JSplitPane; -import javax.swing.border.Border; import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneUI; import org.openide.util.NbBundle; @@ -74,20 +79,50 @@ public final class DiscoveryTopComponent extends TopComponent { rightSplitPane.setUI(new BasicSplitPaneUI() { @Override public BasicSplitPaneDivider createDefaultDivider() { - return new BasicSplitPaneDivider(this) { - private static final long serialVersionUID = 1L; - - @Override - public void paint(Graphics g) { - g.setColor(Color.YELLOW); - g.fillRect(0, 0, getSize().width, getSize().height); - super.paint(g); - } - }; + return new LabeledSplitPaneDivider(this); } }); } + private final class LabeledSplitPaneDivider extends BasicSplitPaneDivider { + + private static final long serialVersionUID = 1L; + + LabeledSplitPaneDivider(BasicSplitPaneUI ui) { + super(ui); + this.add(new JLabel("Details Area")); + this.add(new Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(32000, 0))); + JButton upButton = new JButton(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-up.png"))); + upButton.setBorder(null); + upButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + handleDetailsVisibleEvent(new DiscoveryEventUtils.DetailsVisibleEvent(true)); + } + }); + this.add(upButton); + JButton downButton = new JButton(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-down.png"))); + downButton.setBorder(null); + downButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + handleDetailsVisibleEvent(new DiscoveryEventUtils.DetailsVisibleEvent(false)); + } + }); + this.add(downButton); + this.setLayout(new FlowLayout(FlowLayout.LEFT)); + } + + @Override + public void paint(Graphics g) { + + this.setLayout(new FlowLayout(FlowLayout.LEFT)); + g.setColor(new Color(170, 170, 170)); + g.fillRect(0, 0, getSize().width, getSize().height); + super.paint(g); + } + } + /** * Get the current DiscoveryTopComponent if it is open. * @@ -148,7 +183,7 @@ public final class DiscoveryTopComponent extends TopComponent { mainSplitPane.setDividerLocation(250); mainSplitPane.setPreferredSize(new java.awt.Dimension(1100, 700)); - rightSplitPane.setDividerSize(15); + rightSplitPane.setDividerSize(25); rightSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); rightSplitPane.setResizeWeight(1.0); rightSplitPane.setPreferredSize(new java.awt.Dimension(800, 700)); @@ -288,6 +323,7 @@ public final class DiscoveryTopComponent extends TopComponent { newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text()); progressMessageTextArea.setForeground(Color.red); progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchCancelled_text()); + } /** diff --git a/Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png b/Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png new file mode 100644 index 0000000000000000000000000000000000000000..aeafeeb91a62dde9b66608ca3ce2de73ff005f80 GIT binary patch literal 1264 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 Hu0mjf6S`ks literal 0 HcmV?d00001 From 60ae7c2e5ea3f8ea5b53d3a64a25a37e3a2fb0a8 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 16 Jun 2020 17:07:46 -0400 Subject: [PATCH 10/22] 6457 try and fix center gap --- .../autopsy/discovery/Bundle.properties | 6 ++ .../discovery/Bundle.properties-MERGED | 4 + .../autopsy/discovery/DiscoveryDialog.form | 3 - .../autopsy/discovery/DiscoveryDialog.java | 1 - .../discovery/DiscoveryTopComponent.form | 2 +- .../discovery/DiscoveryTopComponent.java | 53 +++-------- .../discovery/LabeledSplitPaneDivider.form | 93 ++++++++++++++++++ .../discovery/LabeledSplitPaneDivider.java | 94 +++++++++++++++++++ 8 files changed, 212 insertions(+), 44 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index 52c989c8e7..e55bcd1915 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -101,3 +101,9 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show DiscoveryDialog.step1Label.text=Step 1: Choose result type +DividerPanel.jLabel1.text=jLabel1 +DividerPanel.jButton1.text=jButton1 +DividerPanel.jButton2.text=jButton2 +LabeledSplitPaneDivider.jLabel1.text=Details Area +LabeledSplitPaneDivider.jButton1.text= +LabeledSplitPaneDivider.jButton2.text= diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index 50de856d7b..4430a59ee8 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -7,6 +7,7 @@ DataSourceModuleWrapper.fileTypeModule.text=File Type Identification module was DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data source: {0}\n DiscoveryDialog.name.text=Discovery DiscoveryTopComponent.cancelButton.text=Cancel Search +DiscoveryTopComponent.details.label=Details Area DiscoveryTopComponent.name=\ Discovery DiscoveryTopComponent.newSearch.text=New Search DiscoveryTopComponent.searchCancelled.text=Search has been cancelled. @@ -262,6 +263,9 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show DiscoveryDialog.step1Label.text=Step 1: Choose result type +DividerPanel.jLabel1.text=jLabel1 +DividerPanel.jButton1.text=jButton1 +DividerPanel.jButton2.text=jButton2 VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form index 19116a24fe..936dbeed1d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form @@ -6,9 +6,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 33f69712f0..0b88343f8c 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -226,7 +226,6 @@ final class DiscoveryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setMinimumSize(new java.awt.Dimension(600, 300)); - setPreferredSize(new java.awt.Dimension(1000, 650)); imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form index d82dd550a8..4a1f471190 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.form @@ -41,7 +41,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 69c23e0927..4bf574e094 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -19,17 +19,19 @@ package org.sleuthkit.autopsy.discovery; import com.google.common.eventbus.Subscribe; +import java.awt.BorderLayout; import java.awt.Color; -import java.awt.Dimension; +import java.awt.Cursor; import java.awt.FlowLayout; import java.awt.Graphics; import java.util.List; import java.util.stream.Collectors; -import javax.swing.Box.Filler; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; +import javax.swing.JPanel; import javax.swing.JSplitPane; +import javax.swing.SwingConstants; import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneUI; import org.openide.util.NbBundle; @@ -79,48 +81,21 @@ public final class DiscoveryTopComponent extends TopComponent { rightSplitPane.setUI(new BasicSplitPaneUI() { @Override public BasicSplitPaneDivider createDefaultDivider() { - return new LabeledSplitPaneDivider(this); + return new BasicSplitPaneDividerImpl(this); + } }); } - private final class LabeledSplitPaneDivider extends BasicSplitPaneDivider { + final class BasicSplitPaneDividerImpl extends BasicSplitPaneDivider { + + BasicSplitPaneDividerImpl(BasicSplitPaneUI ui) { + super(ui); + this.setLayout(new BorderLayout()); + this.add(new LabeledSplitPaneDivider()); + } private static final long serialVersionUID = 1L; - - LabeledSplitPaneDivider(BasicSplitPaneUI ui) { - super(ui); - this.add(new JLabel("Details Area")); - this.add(new Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(32000, 0))); - JButton upButton = new JButton(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-up.png"))); - upButton.setBorder(null); - upButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - handleDetailsVisibleEvent(new DiscoveryEventUtils.DetailsVisibleEvent(true)); - } - }); - this.add(upButton); - JButton downButton = new JButton(new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-down.png"))); - downButton.setBorder(null); - downButton.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - handleDetailsVisibleEvent(new DiscoveryEventUtils.DetailsVisibleEvent(false)); - } - }); - this.add(downButton); - this.setLayout(new FlowLayout(FlowLayout.LEFT)); - } - - @Override - public void paint(Graphics g) { - - this.setLayout(new FlowLayout(FlowLayout.LEFT)); - g.setColor(new Color(170, 170, 170)); - g.fillRect(0, 0, getSize().width, getSize().height); - super.paint(g); - } } /** @@ -183,7 +158,7 @@ public final class DiscoveryTopComponent extends TopComponent { mainSplitPane.setDividerLocation(250); mainSplitPane.setPreferredSize(new java.awt.Dimension(1100, 700)); - rightSplitPane.setDividerSize(25); + rightSplitPane.setDividerSize(35); rightSplitPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); rightSplitPane.setResizeWeight(1.0); rightSplitPane.setPreferredSize(new java.awt.Dimension(800, 700)); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form b/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form new file mode 100644 index 0000000000..e3831b25ac --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form @@ -0,0 +1,93 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java new file mode 100644 index 0000000000..a2bb654c9d --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java @@ -0,0 +1,94 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.discovery; + +/** + * + * @author wschaefer + */ +public class LabeledSplitPaneDivider extends javax.swing.JPanel { + + /** + * Creates new form LabeledSplitPaneDivider + */ + public LabeledSplitPaneDivider() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + jLabel1 = new javax.swing.JLabel(); + jButton1 = new javax.swing.JButton(); + jButton2 = new javax.swing.JButton(); + + setBackground(new java.awt.Color(170, 170, 170)); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(LabeledSplitPaneDivider.class, "LabeledSplitPaneDivider.jLabel1.text")); // NOI18N + + jButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-down.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(LabeledSplitPaneDivider.class, "LabeledSplitPaneDivider.jButton1.text")); // NOI18N + jButton1.setBorder(null); + jButton1.setMargin(new java.awt.Insets(0, 0, 0, 0)); + jButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton1ActionPerformed(evt); + } + }); + + jButton2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-up.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(LabeledSplitPaneDivider.class, "LabeledSplitPaneDivider.jButton2.text")); // NOI18N + jButton2.setBorder(null); + jButton2.setMargin(new java.awt.Insets(0, 0, 0, 0)); + jButton2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + jButton2ActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 270, Short.MAX_VALUE) + .addComponent(jButton2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButton1)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(jButton1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jButton2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(0, 0, 0)) + ); + }// //GEN-END:initComponents + + private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed + DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(true)); + }//GEN-LAST:event_jButton2ActionPerformed + + private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed + DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false)); + }//GEN-LAST:event_jButton1ActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton jButton1; + private javax.swing.JButton jButton2; + private javax.swing.JLabel jLabel1; + // End of variables declaration//GEN-END:variables +} From 4a7a425b81414df412c718cfbaeda94707549a9a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 16 Jun 2020 17:39:01 -0400 Subject: [PATCH 11/22] 6457 adjust panel size and focus --- .../autopsy/discovery/Bundle.properties | 6 +- .../discovery/Bundle.properties-MERGED | 4 +- .../discovery/DiscoveryTopComponent.java | 11 +- .../discovery/LabeledSplitPaneDivider.form | 93 ------------ .../discovery/LabeledSplitPaneDivider.java | 94 ------------ .../discovery/ResultsSplitPaneDivider.form | 141 ++++++++++++++++++ .../discovery/ResultsSplitPaneDivider.java | 121 +++++++++++++++ 7 files changed, 270 insertions(+), 200 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form delete mode 100644 Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.form create mode 100644 Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.java diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index e55bcd1915..11626b384e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -104,6 +104,6 @@ DiscoveryDialog.step1Label.text=Step 1: Choose result type DividerPanel.jLabel1.text=jLabel1 DividerPanel.jButton1.text=jButton1 DividerPanel.jButton2.text=jButton2 -LabeledSplitPaneDivider.jLabel1.text=Details Area -LabeledSplitPaneDivider.jButton1.text= -LabeledSplitPaneDivider.jButton2.text= +ResultsSplitPaneDivider.hideButton.text= +ResultsSplitPaneDivider.showButton.text= +ResultsSplitPaneDivider.detailsLabel.text=Details Area diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index 4430a59ee8..4e8a849c0a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -7,7 +7,6 @@ DataSourceModuleWrapper.fileTypeModule.text=File Type Identification module was DataSourceModuleWrapper.hashModule.text=Hash Lookup module was not run on data source: {0}\n DiscoveryDialog.name.text=Discovery DiscoveryTopComponent.cancelButton.text=Cancel Search -DiscoveryTopComponent.details.label=Details Area DiscoveryTopComponent.name=\ Discovery DiscoveryTopComponent.newSearch.text=New Search DiscoveryTopComponent.searchCancelled.text=Search has been cancelled. @@ -266,6 +265,9 @@ DiscoveryDialog.step1Label.text=Step 1: Choose result type DividerPanel.jLabel1.text=jLabel1 DividerPanel.jButton1.text=jButton1 DividerPanel.jButton2.text=jButton2 +ResultsSplitPaneDivider.hideButton.text= +ResultsSplitPaneDivider.showButton.text= +ResultsSplitPaneDivider.detailsLabel.text=Details Area VideoThumbnailPanel.bytes.text=bytes VideoThumbnailPanel.deleted.text=All instances of file are deleted. VideoThumbnailPanel.gigaBytes.text=GB diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 4bf574e094..c7ddaa867e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -21,17 +21,10 @@ package org.sleuthkit.autopsy.discovery; import com.google.common.eventbus.Subscribe; import java.awt.BorderLayout; import java.awt.Color; -import java.awt.Cursor; -import java.awt.FlowLayout; import java.awt.Graphics; import java.util.List; import java.util.stream.Collectors; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; import javax.swing.JSplitPane; -import javax.swing.SwingConstants; import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneUI; import org.openide.util.NbBundle; @@ -92,7 +85,7 @@ public final class DiscoveryTopComponent extends TopComponent { BasicSplitPaneDividerImpl(BasicSplitPaneUI ui) { super(ui); this.setLayout(new BorderLayout()); - this.add(new LabeledSplitPaneDivider()); + this.add(new ResultsSplitPaneDivider()); } private static final long serialVersionUID = 1L; @@ -107,7 +100,7 @@ public final class DiscoveryTopComponent extends TopComponent { return (DiscoveryTopComponent) WindowManager.getDefault().findTopComponent(PREFERRED_ID); } - /** +/** * Reset the top component so it isn't displaying any results. */ public void resetTopComponent() { diff --git a/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form b/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form deleted file mode 100644 index e3831b25ac..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.form +++ /dev/null @@ -1,93 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java deleted file mode 100644 index a2bb654c9d..0000000000 --- a/Core/src/org/sleuthkit/autopsy/discovery/LabeledSplitPaneDivider.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package org.sleuthkit.autopsy.discovery; - -/** - * - * @author wschaefer - */ -public class LabeledSplitPaneDivider extends javax.swing.JPanel { - - /** - * Creates new form LabeledSplitPaneDivider - */ - public LabeledSplitPaneDivider() { - initComponents(); - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - jLabel1 = new javax.swing.JLabel(); - jButton1 = new javax.swing.JButton(); - jButton2 = new javax.swing.JButton(); - - setBackground(new java.awt.Color(170, 170, 170)); - - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(LabeledSplitPaneDivider.class, "LabeledSplitPaneDivider.jLabel1.text")); // NOI18N - - jButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-down.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton1, org.openide.util.NbBundle.getMessage(LabeledSplitPaneDivider.class, "LabeledSplitPaneDivider.jButton1.text")); // NOI18N - jButton1.setBorder(null); - jButton1.setMargin(new java.awt.Insets(0, 0, 0, 0)); - jButton1.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jButton1ActionPerformed(evt); - } - }); - - jButton2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-up.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton2, org.openide.util.NbBundle.getMessage(LabeledSplitPaneDivider.class, "LabeledSplitPaneDivider.jButton2.text")); // NOI18N - jButton2.setBorder(null); - jButton2.setMargin(new java.awt.Insets(0, 0, 0, 0)); - jButton2.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - jButton2ActionPerformed(evt); - } - }); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 270, Short.MAX_VALUE) - .addComponent(jButton2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jButton1)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jButton1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jButton2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(0, 0, 0)) - ); - }// //GEN-END:initComponents - - private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed - DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(true)); - }//GEN-LAST:event_jButton2ActionPerformed - - private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false)); - }//GEN-LAST:event_jButton1ActionPerformed - - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton jButton1; - private javax.swing.JButton jButton2; - private javax.swing.JLabel jLabel1; - // End of variables declaration//GEN-END:variables -} diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.form b/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.form new file mode 100644 index 0000000000..48ae94d8a9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.form @@ -0,0 +1,141 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.java b/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.java new file mode 100644 index 0000000000..0a89f28711 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/discovery/ResultsSplitPaneDivider.java @@ -0,0 +1,121 @@ +/* + * Autopsy + * + * Copyright 2020 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.discovery; + +import java.awt.Cursor; + +/** + * Panel for separating the results list from the details area. + */ +final class ResultsSplitPaneDivider extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + + /** + * Creates new form LabeledSplitPaneDivider. + */ + ResultsSplitPaneDivider() { + initComponents(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + javax.swing.JLabel detailsLabel = new javax.swing.JLabel(); + javax.swing.JButton hideButton = new javax.swing.JButton(); + javax.swing.JButton showButton = new javax.swing.JButton(); + javax.swing.Box.Filler filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); + javax.swing.Box.Filler filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); + + setBackground(new java.awt.Color(170, 170, 170)); + + org.openide.awt.Mnemonics.setLocalizedText(detailsLabel, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.detailsLabel.text")); // NOI18N + detailsLabel.setFocusable(false); + + hideButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-down.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hideButton, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.hideButton.text")); // NOI18N + hideButton.setBorder(null); + hideButton.setFocusable(false); + hideButton.setMargin(new java.awt.Insets(0, 0, 0, 0)); + hideButton.setCursor(Cursor.getDefaultCursor()); + hideButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + hideButtonActionPerformed(evt); + } + }); + + showButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/discovery/arrow-up.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(showButton, org.openide.util.NbBundle.getMessage(ResultsSplitPaneDivider.class, "ResultsSplitPaneDivider.showButton.text")); // NOI18N + showButton.setBorder(null); + showButton.setFocusable(false); + showButton.setMargin(new java.awt.Insets(0, 0, 0, 0)); + showButton.setCursor(Cursor.getDefaultCursor()); + showButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + showButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(detailsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 251, Short.MAX_VALUE) + .addComponent(showButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(hideButton) + .addContainerGap()) + .addComponent(filler2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(filler1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(filler2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(hideButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(showButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(detailsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 0, 0) + .addComponent(filler1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void showButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showButtonActionPerformed + DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(true)); + }//GEN-LAST:event_showButtonActionPerformed + + private void hideButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_hideButtonActionPerformed + DiscoveryEventUtils.getDiscoveryEventBus().post(new DiscoveryEventUtils.DetailsVisibleEvent(false)); + }//GEN-LAST:event_hideButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables +} From fe27321e8f4fd753b1f0f01226d283f078cbd80c Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 16 Jun 2020 17:41:24 -0400 Subject: [PATCH 12/22] 6457 add comment --- .../autopsy/discovery/DiscoveryTopComponent.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index c7ddaa867e..790d9e82da 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -80,8 +80,17 @@ public final class DiscoveryTopComponent extends TopComponent { }); } - final class BasicSplitPaneDividerImpl extends BasicSplitPaneDivider { + /** + * Private class for replacing the divider for the results split pane. + */ + private final class BasicSplitPaneDividerImpl extends BasicSplitPaneDivider { + /** + * Construct a new BasicSplitPaneDividerImpl. + * + * @param ui The component which contains the split pane this divider is + * in. + */ BasicSplitPaneDividerImpl(BasicSplitPaneUI ui) { super(ui); this.setLayout(new BorderLayout()); @@ -100,7 +109,7 @@ public final class DiscoveryTopComponent extends TopComponent { return (DiscoveryTopComponent) WindowManager.getDefault().findTopComponent(PREFERRED_ID); } -/** + /** * Reset the top component so it isn't displaying any results. */ public void resetTopComponent() { From b4287cc53dfdb79ebb4132f8e18cd47ef600e4fd Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Thu, 18 Jun 2020 23:37:58 -0400 Subject: [PATCH 13/22] Update ExtractRegistry.java Add "Recent File List" to check in while loop and exit if it does contain it. --- .../org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 80171f0672..7c3e52b81e 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -1388,7 +1388,8 @@ class ExtractRegistry extends Extract { line = reader.readLine(); // Columns are // FileX -> - while (!line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.contains("Applets")) { + while (!line.contains(SECTION_DIVIDER) && !line.isEmpty() && !line.contains("Applets") + && !line.contains(("Recent File List"))) { // Split line on "> " which is the record delimiter between position and file String tokens[] = line.split("> "); String fileName = tokens[1]; From 01494b3fb22f83b4355025608def834c2ce24a1c Mon Sep 17 00:00:00 2001 From: Mark McKinnon Date: Fri, 19 Jun 2020 14:34:32 -0400 Subject: [PATCH 14/22] Fix Undefined Value in Autopsy Regripper Plugins Check for undefined values in Autopsy regripper plugins, this is for Autopsy version of regripper not full version of regripper. --- thirdparty/rr/plugins/arunmru.pl | 73 ++--- thirdparty/rr/plugins/autopsylogin.pl | 62 ++-- thirdparty/rr/plugins/autopsyntusernetwork.pl | 107 +++---- thirdparty/rr/plugins/autopsyrecentdocs.pl | 150 ++++----- thirdparty/rr/plugins/autopsyshellfolders.pl | 55 ++-- thirdparty/rr/plugins/officedocs.pl | 220 ++++++------- thirdparty/rr/plugins/officedocs2010.pl | 289 +++++++++--------- 7 files changed, 485 insertions(+), 471 deletions(-) diff --git a/thirdparty/rr/plugins/arunmru.pl b/thirdparty/rr/plugins/arunmru.pl index 504700f145..9d8ed281bd 100644 --- a/thirdparty/rr/plugins/arunmru.pl +++ b/thirdparty/rr/plugins/arunmru.pl @@ -36,43 +36,44 @@ sub pluginmain { my $class = shift; my $ntuser = shift; #::logMsg("autospyrunmru"); - my $reg = Parse::Win32Registry->new($ntuser); - my $root_key = $reg->get_root_key; + if (defined(Parse::Win32Registry->new($ntuser))) { + my $reg = Parse::Win32Registry->new($ntuser); + my $root_key = $reg->get_root_key; - my $key_path = 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU'; - my $key; - if ($key = $root_key->get_subkey($key_path)) { - #::rptMsg("RunMru"); - #::rptMsg($key_path); - - my @vals = $key->get_list_of_values(); - ::rptMsg(""); - ::rptMsg("".gmtime($key->get_timestamp()).""); - ::rptMsg(""); - my %runvals; - my $mru; - if (scalar(@vals) > 0) { - foreach my $v (@vals) { - $runvals{$v->get_name()} = $v->get_data() unless ($v->get_name() =~ m/^MRUList/i); - $mru = $v->get_data() if ($v->get_name() =~ m/^MRUList/i); - } - ::rptMsg("".$mru.""); - foreach my $r (sort keys %runvals) { - ::rptMsg("".$r." ".$runvals{$r}.""); - } - } - else { - #::rptMsg($key_path." has no values."); - #::logMsg($key_path." has no values."); - } - ::rptMsg(""); - ::rptMsg(""); - } - else { - #::rptMsg($key_path." not found."); - #::logMsg($key_path." not found."); - } - + my $key_path = 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU'; + my $key; + if ($key = $root_key->get_subkey($key_path)) { + #::rptMsg("RunMru"); + #::rptMsg($key_path); + + my @vals = $key->get_list_of_values(); + ::rptMsg(""); + ::rptMsg("".gmtime($key->get_timestamp()).""); + ::rptMsg(""); + my %runvals; + my $mru; + if (scalar(@vals) > 0) { + foreach my $v (@vals) { + $runvals{$v->get_name()} = $v->get_data() unless ($v->get_name() =~ m/^MRUList/i); + $mru = $v->get_data() if ($v->get_name() =~ m/^MRUList/i); + } + ::rptMsg("".$mru.""); + foreach my $r (sort keys %runvals) { + ::rptMsg("".$r." ".$runvals{$r}.""); + } + } + else { + #::rptMsg($key_path." has no values."); + #::logMsg($key_path." has no values."); + } + ::rptMsg(""); + ::rptMsg(""); + } + else { + #::rptMsg($key_path." not found."); + #::logMsg($key_path." not found."); + } + } } 1; diff --git a/thirdparty/rr/plugins/autopsylogin.pl b/thirdparty/rr/plugins/autopsylogin.pl index ab0365817e..2a72ba6936 100644 --- a/thirdparty/rr/plugins/autopsylogin.pl +++ b/thirdparty/rr/plugins/autopsylogin.pl @@ -35,36 +35,38 @@ sub pluginmain { my $class = shift; my $ntuser = shift; #::logMsg("||logonusername||"); - my $reg = Parse::Win32Registry->new($ntuser); - my $root_key = $reg->get_root_key; - - my $logon_name = "Username"; - - my $key_path = 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'; - my $key; - if ($key = $root_key->get_subkey($key_path)) { - my @vals = $key->get_list_of_values(); - if (scalar(@vals) > 0) { - #::rptMsg("Logon User Name"); - #::rptMsg($key_path); - ::rptMsg(""); - ::rptMsg("".gmtime($key->get_timestamp()).""); - foreach my $v (@vals) { - if ($v->get_name() eq $logon_name) { - ::rptMsg(" ".$v->get_data() .""); - } - } - ::rptMsg(""); - } - else { - #::rptMsg($key_path." has no values."); - #::logMsg($key_path." has no values."); - } - } - else { - #::rptMsg($key_path." not found."); - #::logMsg($key_path." not found."); - } + if (defined(Parse::Win32Registry->new($ntuser))) { + my $reg = Parse::Win32Registry->new($ntuser); + my $root_key = $reg->get_root_key; + + my $logon_name = "Username"; + + my $key_path = 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'; + my $key; + if ($key = $root_key->get_subkey($key_path)) { + my @vals = $key->get_list_of_values(); + if (scalar(@vals) > 0) { + #::rptMsg("Logon User Name"); + #::rptMsg($key_path); + ::rptMsg(""); + ::rptMsg("".gmtime($key->get_timestamp()).""); + foreach my $v (@vals) { + if ($v->get_name() eq $logon_name) { + ::rptMsg(" ".$v->get_data() .""); + } + } + ::rptMsg(""); + } + else { + #::rptMsg($key_path." has no values."); + #::logMsg($key_path." has no values."); + } + } + else { + #::rptMsg($key_path." not found."); + #::logMsg($key_path." not found."); + } + } } 1; diff --git a/thirdparty/rr/plugins/autopsyntusernetwork.pl b/thirdparty/rr/plugins/autopsyntusernetwork.pl index 715e89b8ff..910679be95 100644 --- a/thirdparty/rr/plugins/autopsyntusernetwork.pl +++ b/thirdparty/rr/plugins/autopsyntusernetwork.pl @@ -30,64 +30,67 @@ sub pluginmain { my $ntuser = shift; #::logMsg("Launching ntusernetwork v.".$VERSION); #::rptMsg("ntusernetwork v.".$VERSION); # banner - #::rptMsg("(".$config{hive}.") ".getShortDescr()."\n"); # banner - my $reg = Parse::Win32Registry->new($ntuser); - my $root_key = $reg->get_root_key; - - ::rptMsg(""); - ::rptMsg(""); - ::rptMsg(""); + #::rptMsg("(".$config{hive}.") ".getShortDescr()."\n"); # banner + if (defined(Parse::Win32Registry->new($ntuser))) { + + my $reg = Parse::Win32Registry->new($ntuser); + my $root_key = $reg->get_root_key; + + ::rptMsg(""); + ::rptMsg(""); + ::rptMsg(""); - my $key_path = 'Network'; - my $key; - if ($key = $root_key->get_subkey($key_path)) { + my $key_path = 'Network'; + my $key; + if ($key = $root_key->get_subkey($key_path)) { - my @subkeys = $key->get_list_of_subkeys(); - if (scalar @subkeys > 0) { - foreach my $s (@subkeys) { - #::rptMsg($key_path."\\".$s->get_name()); - my $localPath = $key_path."\\".$s->get_name(); + my @subkeys = $key->get_list_of_subkeys(); + if (scalar @subkeys > 0) { + foreach my $s (@subkeys) { + #::rptMsg($key_path."\\".$s->get_name()); + my $localPath = $key_path."\\".$s->get_name(); - my $remotePath; - eval { - $remotePath = $s->get_value("RemotePath")->get_data(); - }; - if ($@) { - # ::rptMsg("OS value not found."); - } - else { - ::rptMsg("". $remotePath . ""); - } - } - } + my $remotePath; + eval { + $remotePath = $s->get_value("RemotePath")->get_data(); + }; + if ($@) { + # ::rptMsg("OS value not found."); + } + else { + ::rptMsg("". $remotePath . ""); + } + } + } - # ::rptMsg($key_path); - # ::rptMsg(""); + # ::rptMsg($key_path); + # ::rptMsg(""); - - # my @subkeys = $key->get_list_of_subkeys(); - # if (scalar @subkeys > 0) { - # foreach my $s (@subkeys) { - # ::rptMsg($key_path."\\".$s->get_name()); - # ::rptMsg("LastWrite time: ".gmtime($s->get_timestamp())); - # my @vals = $s->get_list_of_values(); - # if (scalar @vals > 0) { - # foreach my $v (@vals) { - # ::rptMsg(sprintf " %-15s %-25s",$v->get_name(),$v->get_data()); - # } - # ::rptMsg(""); - # } - # } - # } - # else { - # ::rptMsg($key_path." key has no subkeys."); - # } - } - else { - #::rptMsg($key_path." key not found."); - } - ::rptMsg(""); + + # my @subkeys = $key->get_list_of_subkeys(); + # if (scalar @subkeys > 0) { + # foreach my $s (@subkeys) { + # ::rptMsg($key_path."\\".$s->get_name()); + # ::rptMsg("LastWrite time: ".gmtime($s->get_timestamp())); + # my @vals = $s->get_list_of_values(); + # if (scalar @vals > 0) { + # foreach my $v (@vals) { + # ::rptMsg(sprintf " %-15s %-25s",$v->get_name(),$v->get_data()); + # } + # ::rptMsg(""); + # } + # } + # } + # else { + # ::rptMsg($key_path." key has no subkeys."); + # } + } + else { + #::rptMsg($key_path." key not found."); + } + ::rptMsg(""); + } } 1; diff --git a/thirdparty/rr/plugins/autopsyrecentdocs.pl b/thirdparty/rr/plugins/autopsyrecentdocs.pl index 776126175b..e2a05aa699 100644 --- a/thirdparty/rr/plugins/autopsyrecentdocs.pl +++ b/thirdparty/rr/plugins/autopsyrecentdocs.pl @@ -41,80 +41,82 @@ sub pluginmain { my $class = shift; my $ntuser = shift; #::logMsg("||recentdocs||"); - my $reg = Parse::Win32Registry->new($ntuser); - my $root_key = $reg->get_root_key; - my $key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs"; - my $key; - if ($key = $root_key->get_subkey($key_path)) { - #::rptMsg("RecentDocs"); - #::rptMsg("**All values printed in MRUList\\MRUListEx order."); - #::rptMsg($key_path); - ::rptMsg("".gmtime($key->get_timestamp()).""); -# Get RecentDocs values - my %rdvals = getRDValues($key); - if (%rdvals) { - my $tag; - if (exists $rdvals{"MRUListEx"}) { - $tag = "MRUListEx"; - } - elsif (exists $rdvals{"MRUList"}) { - $tag = "MRUList"; - } - else { - - } - - my @list = split(/,/,$rdvals{$tag}); - foreach my $i (@list) { - ::rptMsg("".$rdvals{$i} . ""); - } - - } - else { - #::rptMsg($key_path." has no values."); - #::logMsg("Error: ".$key_path." has no values."); - } - ::rptMsg(""); -# Get RecentDocs subkeys' values - my @subkeys = $key->get_list_of_subkeys(); - if (scalar(@subkeys) > 0) { - foreach my $s (@subkeys) { - #::rptMsg($key_path."\\".$s->get_name()); - #::rptMsg("LastWrite Time ".gmtime($s->get_timestamp())." (UTC)"); - - my %rdvals = getRDValues($s); - if (%rdvals) { - my $tag; - if (exists $rdvals{"MRUListEx"}) { - $tag = "MRUListEx"; - } - elsif (exists $rdvals{"MRUList"}) { - $tag = "MRUList"; - } - else { - - } - - my @list = split(/,/,$rdvals{$tag}); - #::rptMsg($tag." = ".$rdvals{$tag}); - foreach my $i (@list) { - #::rptMsg("".$rdvals{$i}); - } - - #::rptMsg(""); - } - else { - #::rptMsg($key_path." has no values."); - } - } - } - else { - #::rptMsg($key_path." has no subkeys."); - } - } - else { - #::rptMsg($key_path." not found."); - } + if (defined(Parse::Win32Registry->new($ntuser))) { + my $reg = Parse::Win32Registry->new($ntuser); + my $root_key = $reg->get_root_key; + my $key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RecentDocs"; + my $key; + if ($key = $root_key->get_subkey($key_path)) { + #::rptMsg("RecentDocs"); + #::rptMsg("**All values printed in MRUList\\MRUListEx order."); + #::rptMsg($key_path); + ::rptMsg("".gmtime($key->get_timestamp()).""); + # Get RecentDocs values + my %rdvals = getRDValues($key); + if (%rdvals) { + my $tag; + if (exists $rdvals{"MRUListEx"}) { + $tag = "MRUListEx"; + } + elsif (exists $rdvals{"MRUList"}) { + $tag = "MRUList"; + } + else { + + } + + my @list = split(/,/,$rdvals{$tag}); + foreach my $i (@list) { + ::rptMsg("".$rdvals{$i} . ""); + } + + } + else { + #::rptMsg($key_path." has no values."); + #::logMsg("Error: ".$key_path." has no values."); + } + ::rptMsg(""); + # Get RecentDocs subkeys' values + my @subkeys = $key->get_list_of_subkeys(); + if (scalar(@subkeys) > 0) { + foreach my $s (@subkeys) { + #::rptMsg($key_path."\\".$s->get_name()); + #::rptMsg("LastWrite Time ".gmtime($s->get_timestamp())." (UTC)"); + + my %rdvals = getRDValues($s); + if (%rdvals) { + my $tag; + if (exists $rdvals{"MRUListEx"}) { + $tag = "MRUListEx"; + } + elsif (exists $rdvals{"MRUList"}) { + $tag = "MRUList"; + } + else { + + } + + my @list = split(/,/,$rdvals{$tag}); + #::rptMsg($tag." = ".$rdvals{$tag}); + foreach my $i (@list) { + #::rptMsg("".$rdvals{$i}); + } + + #::rptMsg(""); + } + else { + #::rptMsg($key_path." has no values."); + } + } + } + else { + #::rptMsg($key_path." has no subkeys."); + } + } + else { + #::rptMsg($key_path." not found."); + } + } } diff --git a/thirdparty/rr/plugins/autopsyshellfolders.pl b/thirdparty/rr/plugins/autopsyshellfolders.pl index d625820ec5..01a5b22e6a 100644 --- a/thirdparty/rr/plugins/autopsyshellfolders.pl +++ b/thirdparty/rr/plugins/autopsyshellfolders.pl @@ -41,32 +41,35 @@ sub pluginmain { my $class = shift; my $hive = shift; #::logMsg("Launching shellfolders v.".$VERSION); - my $reg = Parse::Win32Registry->new($hive); - my $root_key = $reg->get_root_key; + if (defined(Parse::Win32Registry->new($hive))) { + my $reg = Parse::Win32Registry->new($hive); - my $key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; - my $key; - if ($key = $root_key->get_subkey($key_path)) { - ::rptMsg(""); - ::rptMsg("".gmtime($key->get_timestamp()).""); - - my @vals = $key->get_list_of_values(); - ::rptMsg(""); - if (scalar(@vals) > 0) { - foreach my $v (@vals) { - my $str = sprintf "%-20s %-40s","get_name()."\">",$v->get_data().""; - ::rptMsg($str); - } - ::rptMsg(""); - } - else { - #::rptMsg($key_path." has no values."); - } - ::rptMsg(""); - } - else { - #::rptMsg($key_path." not found."); - #::logMsg($key_path." not found."); - } + my $root_key = $reg->get_root_key; + + my $key_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"; + my $key; + if ($key = $root_key->get_subkey($key_path)) { + ::rptMsg(""); + ::rptMsg("".gmtime($key->get_timestamp()).""); + + my @vals = $key->get_list_of_values(); + ::rptMsg(""); + if (scalar(@vals) > 0) { + foreach my $v (@vals) { + my $str = sprintf "%-20s %-40s","get_name()."\">",$v->get_data().""; + ::rptMsg($str); + } + ::rptMsg(""); + } + else { + #::rptMsg($key_path." has no values."); + } + ::rptMsg(""); + } + else { + #::rptMsg($key_path." not found."); + #::logMsg($key_path." not found."); + } + } } 1; diff --git a/thirdparty/rr/plugins/officedocs.pl b/thirdparty/rr/plugins/officedocs.pl index 707a5c254f..fac96f52ff 100644 --- a/thirdparty/rr/plugins/officedocs.pl +++ b/thirdparty/rr/plugins/officedocs.pl @@ -37,115 +37,117 @@ sub pluginmain { # ::rptMsg("officedocs v.".$VERSION); # 20110830 [fpi] + banner # ::rptMsg("(".getHive().") ".getShortDescr()."\n"); # 20110830 [fpi] + banner ::rptMsg(""); - my $reg = Parse::Win32Registry->new($ntuser); - my $root_key = $reg->get_root_key; - #::rptMsg("officedocs v.".$VERSION); -# First, let's find out which version of Office is installed - my $version; - my $tag = 0; - my @versions = ("7\.0","8\.0", "9\.0", "10\.0", "11\.0","12\.0"); - foreach my $ver (@versions) { - my $key_path = "Software\\Microsoft\\Office\\".$ver."\\Common\\Open Find"; - if (defined($root_key->get_subkey($key_path))) { - $version = $ver; - $tag = 1; - } - } - - if ($tag) { - #::rptMsg("MSOffice version ".$version." located."); - my $key_path = "Software\\Microsoft\\Office\\".$version; - my $of_key = $root_key->get_subkey($key_path); - ::rptMsg(" ".gmtime($of_key->get_timestamp()).""); - ::rptMsg(""); - if ($of_key) { -# Attempt to retrieve Word docs - my @funcs = ("Open","Save As","File Save"); - foreach my $func (@funcs) { - my $word = "Common\\Open Find\\Microsoft Office Word\\Settings\\".$func."\\File Name MRU"; - my $word_key = $of_key->get_subkey($word); - if ($word_key) { - #::rptMsg($word); - - #::rptMsg(""); - my $value = $word_key->get_value("Value")->get_data(); - my @data = split(/\00/,$value); - ::rptMsg("". @data . ""); - #map{::rptMsg("$_");}@data; - } - else { -# ::rptMsg("Could not access ".$word); - } - #::rptMsg(""); - } -# Attempt to retrieve Excel docs - my $excel = 'Excel\\Recent Files'; - if (my $excel_key = $of_key->get_subkey($excel)) { - #::rptMsg($key_path."\\".$excel); - #::rptMsg("LastWrite Time ".gmtime($excel_key->get_timestamp())." (UTC)"); - my @vals = $excel_key->get_list_of_values(); - if (scalar(@vals) > 0) { - my %files; -# Retrieve values and load into a hash for sorting - foreach my $v (@vals) { - my $val = $v->get_name(); - my $data = $v->get_data(); - my $tag = (split(/File/,$val))[1]; - $files{$tag} = $val.":".$data; - } -# Print sorted content to report file - foreach my $u (sort {$a <=> $b} keys %files) { - my ($val,$data) = split(/:/,$files{$u},2); - ::rptMsg("".$data . ""); - } - } - else { - #::rptMsg($key_path.$excel." has no values."); - } - } - else { - #::rptMsg($key_path.$excel." not found."); - } - #::rptMsg(""); -# Attempt to retrieve PowerPoint docs - my $ppt = 'PowerPoint\\Recent File List'; - if (my $ppt_key = $of_key->get_subkey($ppt)) { - #::rptMsg($key_path."\\".$ppt); - #::rptMsg("LastWrite Time ".gmtime($ppt_key->get_timestamp())." (UTC)"); - my @vals = $ppt_key->get_list_of_values(); - if (scalar(@vals) > 0) { - my %files; -# Retrieve values and load into a hash for sorting - foreach my $v (@vals) { - my $val = $v->get_name(); - my $data = $v->get_data(); - my $tag = (split(/File/,$val))[1]; - $files{$tag} = $val.":".$data; - } -# Print sorted content to report file - foreach my $u (sort {$a <=> $b} keys %files) { - my ($val,$data) = split(/:/,$files{$u},2); - ::rptMsg("".$data . ""); - } - } - else { - #::rptMsg($key_path."\\".$ppt." has no values."); - } - } - else { - #::rptMsg($key_path."\\".$ppt." not found."); - } - } - else { - #::rptMsg("Could not access ".$key_path); - #::logMsg("Could not access ".$key_path); - } - ::rptMsg(""); - } - else { - #::logMsg("MSOffice version not found."); - #::rptMsg("MSOffice version not found."); - } + if (defined(Parse::Win32Registry->new($ntuser))) { + my $reg = Parse::Win32Registry->new($ntuser); + my $root_key = $reg->get_root_key; + #::rptMsg("officedocs v.".$VERSION); + # First, let's find out which version of Office is installed + my $version; + my $tag = 0; + my @versions = ("7\.0","8\.0", "9\.0", "10\.0", "11\.0","12\.0"); + foreach my $ver (@versions) { + my $key_path = "Software\\Microsoft\\Office\\".$ver."\\Common\\Open Find"; + if (defined($root_key->get_subkey($key_path))) { + $version = $ver; + $tag = 1; + } + } + + if ($tag) { + #::rptMsg("MSOffice version ".$version." located."); + my $key_path = "Software\\Microsoft\\Office\\".$version; + my $of_key = $root_key->get_subkey($key_path); + ::rptMsg(" ".gmtime($of_key->get_timestamp()).""); + ::rptMsg(""); + if ($of_key) { + # Attempt to retrieve Word docs + my @funcs = ("Open","Save As","File Save"); + foreach my $func (@funcs) { + my $word = "Common\\Open Find\\Microsoft Office Word\\Settings\\".$func."\\File Name MRU"; + my $word_key = $of_key->get_subkey($word); + if ($word_key) { + #::rptMsg($word); + + #::rptMsg(""); + my $value = $word_key->get_value("Value")->get_data(); + my @data = split(/\00/,$value); + ::rptMsg("". @data . ""); + #map{::rptMsg("$_");}@data; + } + else { + # ::rptMsg("Could not access ".$word); + } + #::rptMsg(""); + } + # Attempt to retrieve Excel docs + my $excel = 'Excel\\Recent Files'; + if (my $excel_key = $of_key->get_subkey($excel)) { + #::rptMsg($key_path."\\".$excel); + #::rptMsg("LastWrite Time ".gmtime($excel_key->get_timestamp())." (UTC)"); + my @vals = $excel_key->get_list_of_values(); + if (scalar(@vals) > 0) { + my %files; + # Retrieve values and load into a hash for sorting + foreach my $v (@vals) { + my $val = $v->get_name(); + my $data = $v->get_data(); + my $tag = (split(/File/,$val))[1]; + $files{$tag} = $val.":".$data; + } + # Print sorted content to report file + foreach my $u (sort {$a <=> $b} keys %files) { + my ($val,$data) = split(/:/,$files{$u},2); + ::rptMsg("".$data . ""); + } + } + else { + #::rptMsg($key_path.$excel." has no values."); + } + } + else { + #::rptMsg($key_path.$excel." not found."); + } + #::rptMsg(""); + # Attempt to retrieve PowerPoint docs + my $ppt = 'PowerPoint\\Recent File List'; + if (my $ppt_key = $of_key->get_subkey($ppt)) { + #::rptMsg($key_path."\\".$ppt); + #::rptMsg("LastWrite Time ".gmtime($ppt_key->get_timestamp())." (UTC)"); + my @vals = $ppt_key->get_list_of_values(); + if (scalar(@vals) > 0) { + my %files; + # Retrieve values and load into a hash for sorting + foreach my $v (@vals) { + my $val = $v->get_name(); + my $data = $v->get_data(); + my $tag = (split(/File/,$val))[1]; + $files{$tag} = $val.":".$data; + } + # Print sorted content to report file + foreach my $u (sort {$a <=> $b} keys %files) { + my ($val,$data) = split(/:/,$files{$u},2); + ::rptMsg("".$data . ""); + } + } + else { + #::rptMsg($key_path."\\".$ppt." has no values."); + } + } + else { + #::rptMsg($key_path."\\".$ppt." not found."); + } + } + else { + #::rptMsg("Could not access ".$key_path); + #::logMsg("Could not access ".$key_path); + } + ::rptMsg(""); + } + else { + #::logMsg("MSOffice version not found."); + #::rptMsg("MSOffice version not found."); + } + } ::rptMsg(""); } diff --git a/thirdparty/rr/plugins/officedocs2010.pl b/thirdparty/rr/plugins/officedocs2010.pl index 2783dc01f6..15073deed3 100644 --- a/thirdparty/rr/plugins/officedocs2010.pl +++ b/thirdparty/rr/plugins/officedocs2010.pl @@ -72,150 +72,151 @@ sub pluginmain { #::logMsg("Launching officedocs2010 v.".$VERSION); #::rptMsg("officedocs2010 v.".$VERSION); # 20110830 [fpi] + banner #::rptMsg("(".getHive().") ".getShortDescr()."\n"); # 20110830 [fpi] + banner - - my $reg = Parse::Win32Registry->new($ntuser); - my $root_key = $reg->get_root_key; - # ::rptMsg("officedocs v.".$VERSION); # 20110830 [fpi] - redundant - my $tag = 0; - my $key_path = "Software\\Microsoft\\Office\\14.0"; - if (defined($root_key->get_subkey($key_path))) { - $tag = 1; - } - - if ($tag) { - #::rptMsg("MSOffice version 2010 located."); - my $key_path = "Software\\Microsoft\\Office\\14.0"; - my $of_key = $root_key->get_subkey($key_path); - if ($of_key) { -# Attempt to retrieve Word docs - my $word = 'Word\\File MRU'; - if (my $word_key = $of_key->get_subkey($word)) { - #::rptMsg($key_path."\\".$word); - #::rptMsg("LastWrite Time ".gmtime($word_key->get_timestamp())." (UTC)"); - my @vals = $word_key->get_list_of_values(); - if (scalar(@vals) > 0) { - my %files; -# Retrieve values and load into a hash for sorting - foreach my $v (@vals) { - my $val = $v->get_name(); - if ($val eq "Max Display") { next; } - my $data = getWinTS($v->get_data()); - my $tag = (split(/Item/,$val))[1]; - $files{$tag} = $val.":".$data; - } -# Print sorted content to report file - foreach my $u (sort {$a <=> $b} keys %files) { - my ($val,$data) = split(/:/,$files{$u},2); - ::rptMsg("".$data . ""); - } - } - else { - #::rptMsg($key_path.$word." has no values."); - } - } - else { - #::rptMsg($key_path.$word." not found."); - } - #::rptMsg(""); -# Attempt to retrieve Excel docs - my $excel = 'Excel\\File MRU'; - if (my $excel_key = $of_key->get_subkey($excel)) { - #::rptMsg($key_path."\\".$excel); - #::rptMsg("LastWrite Time ".gmtime($excel_key->get_timestamp())." (UTC)"); - my @vals = $excel_key->get_list_of_values(); - if (scalar(@vals) > 0) { - my %files; -# Retrieve values and load into a hash for sorting - foreach my $v (@vals) { - my $val = $v->get_name(); - if ($val eq "Max Display") { next; } - my $data = getWinTS($v->get_data()); - my $tag = (split(/Item/,$val))[1]; - $files{$tag} = $val.":".$data; - } -# Print sorted content to report file - foreach my $u (sort {$a <=> $b} keys %files) { - my ($val,$data) = split(/:/,$files{$u},2); - ::rptMsg("".$data . ""); - } - } - else { - #::rptMsg($key_path.$excel." has no values."); - } - } - else { - #::rptMsg($key_path.$excel." not found."); - } - #::rptMsg(""); -# Attempt to retrieve Access docs - my $access = 'Access\\File MRU'; - if (my $access_key = $of_key->get_subkey($access)) { - #::rptMsg($key_path."\\".$access); - #::rptMsg("LastWrite Time ".gmtime($access_key->get_timestamp())." (UTC)"); - my @vals = $access_key->get_list_of_values(); - if (scalar(@vals) > 0) { - my %files; -# Retrieve values and load into a hash for sorting - foreach my $v (@vals) { - my $val = $v->get_name(); - if ($val eq "Max Display") { next; } - my $data = getWinTS($v->get_data()); - my $tag = (split(/Item/,$val))[1]; - $files{$tag} = $val.":".$data; - } -# Print sorted content to report file - foreach my $u (sort {$a <=> $b} keys %files) { - my ($val,$data) = split(/:/,$files{$u},2); - ::rptMsg("".$data . ""); - } - } - else { - # ::rptMsg($key_path.$access." has no values."); - } - } - else { - # ::rptMsg($key_path.$access." not found."); - } - #::rptMsg(""); -# Attempt to retrieve PowerPoint docs - my $ppt = 'PowerPoint\\File MRU'; - if (my $ppt_key = $of_key->get_subkey($ppt)) { - #::rptMsg($key_path."\\".$ppt); - #::rptMsg("LastWrite Time ".gmtime($ppt_key->get_timestamp())." (UTC)"); - my @vals = $ppt_key->get_list_of_values(); - if (scalar(@vals) > 0) { - my %files; -# Retrieve values and load into a hash for sorting - foreach my $v (@vals) { - my $val = $v->get_name(); - if ($val eq "Max Display") { next; } - my $data = getWinTS($v->get_data()); - my $tag = (split(/Item/,$val))[1]; - $files{$tag} = $val.":".$data; - } -# Print sorted content to report file - foreach my $u (sort {$a <=> $b} keys %files) { - my ($val,$data) = split(/:/,$files{$u},2); - ::rptMsg("".$data . ""); - } - } - else { - # ::rptMsg($key_path."\\".$ppt." has no values."); - } - } - else { - # ::rptMsg($key_path."\\".$ppt." not found."); - } - } - else { - # ::rptMsg("Could not access ".$key_path); - # ::logMsg("Could not access ".$key_path); - } - } - else { - # ::logMsg("MSOffice version not found."); - # ::rptMsg("MSOffice version not found."); - } + if (defined(Parse::Win32Registry->new($ntuser))) { + my $reg = Parse::Win32Registry->new($ntuser); + my $root_key = $reg->get_root_key; + # ::rptMsg("officedocs v.".$VERSION); # 20110830 [fpi] - redundant + my $tag = 0; + my $key_path = "Software\\Microsoft\\Office\\14.0"; + if (defined($root_key->get_subkey($key_path))) { + $tag = 1; + } + + if ($tag) { + #::rptMsg("MSOffice version 2010 located."); + my $key_path = "Software\\Microsoft\\Office\\14.0"; + my $of_key = $root_key->get_subkey($key_path); + if ($of_key) { + # Attempt to retrieve Word docs + my $word = 'Word\\File MRU'; + if (my $word_key = $of_key->get_subkey($word)) { + #::rptMsg($key_path."\\".$word); + #::rptMsg("LastWrite Time ".gmtime($word_key->get_timestamp())." (UTC)"); + my @vals = $word_key->get_list_of_values(); + if (scalar(@vals) > 0) { + my %files; + # Retrieve values and load into a hash for sorting + foreach my $v (@vals) { + my $val = $v->get_name(); + if ($val eq "Max Display") { next; } + my $data = getWinTS($v->get_data()); + my $tag = (split(/Item/,$val))[1]; + $files{$tag} = $val.":".$data; + } + # Print sorted content to report file + foreach my $u (sort {$a <=> $b} keys %files) { + my ($val,$data) = split(/:/,$files{$u},2); + ::rptMsg("".$data . ""); + } + } + else { + #::rptMsg($key_path.$word." has no values."); + } + } + else { + #::rptMsg($key_path.$word." not found."); + } + #::rptMsg(""); + # Attempt to retrieve Excel docs + my $excel = 'Excel\\File MRU'; + if (my $excel_key = $of_key->get_subkey($excel)) { + #::rptMsg($key_path."\\".$excel); + #::rptMsg("LastWrite Time ".gmtime($excel_key->get_timestamp())." (UTC)"); + my @vals = $excel_key->get_list_of_values(); + if (scalar(@vals) > 0) { + my %files; + # Retrieve values and load into a hash for sorting + foreach my $v (@vals) { + my $val = $v->get_name(); + if ($val eq "Max Display") { next; } + my $data = getWinTS($v->get_data()); + my $tag = (split(/Item/,$val))[1]; + $files{$tag} = $val.":".$data; + } + # Print sorted content to report file + foreach my $u (sort {$a <=> $b} keys %files) { + my ($val,$data) = split(/:/,$files{$u},2); + ::rptMsg("".$data . ""); + } + } + else { + #::rptMsg($key_path.$excel." has no values."); + } + } + else { + #::rptMsg($key_path.$excel." not found."); + } + #::rptMsg(""); + # Attempt to retrieve Access docs + my $access = 'Access\\File MRU'; + if (my $access_key = $of_key->get_subkey($access)) { + #::rptMsg($key_path."\\".$access); + #::rptMsg("LastWrite Time ".gmtime($access_key->get_timestamp())." (UTC)"); + my @vals = $access_key->get_list_of_values(); + if (scalar(@vals) > 0) { + my %files; + # Retrieve values and load into a hash for sorting + foreach my $v (@vals) { + my $val = $v->get_name(); + if ($val eq "Max Display") { next; } + my $data = getWinTS($v->get_data()); + my $tag = (split(/Item/,$val))[1]; + $files{$tag} = $val.":".$data; + } + # Print sorted content to report file + foreach my $u (sort {$a <=> $b} keys %files) { + my ($val,$data) = split(/:/,$files{$u},2); + ::rptMsg("".$data . ""); + } + } + else { + # ::rptMsg($key_path.$access." has no values."); + } + } + else { + # ::rptMsg($key_path.$access." not found."); + } + #::rptMsg(""); + # Attempt to retrieve PowerPoint docs + my $ppt = 'PowerPoint\\File MRU'; + if (my $ppt_key = $of_key->get_subkey($ppt)) { + #::rptMsg($key_path."\\".$ppt); + #::rptMsg("LastWrite Time ".gmtime($ppt_key->get_timestamp())." (UTC)"); + my @vals = $ppt_key->get_list_of_values(); + if (scalar(@vals) > 0) { + my %files; + # Retrieve values and load into a hash for sorting + foreach my $v (@vals) { + my $val = $v->get_name(); + if ($val eq "Max Display") { next; } + my $data = getWinTS($v->get_data()); + my $tag = (split(/Item/,$val))[1]; + $files{$tag} = $val.":".$data; + } + # Print sorted content to report file + foreach my $u (sort {$a <=> $b} keys %files) { + my ($val,$data) = split(/:/,$files{$u},2); + ::rptMsg("".$data . ""); + } + } + else { + # ::rptMsg($key_path."\\".$ppt." has no values."); + } + } + else { + # ::rptMsg($key_path."\\".$ppt." not found."); + } + } + else { + # ::rptMsg("Could not access ".$key_path); + # ::logMsg("Could not access ".$key_path); + } + } + else { + # ::logMsg("MSOffice version not found."); + # ::rptMsg("MSOffice version not found."); + } + } } 1; From 03d445a89e34082c537ce131f861454925b1e661 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 23 Jun 2020 14:00:14 -0400 Subject: [PATCH 15/22] 6457 remove obsolete bundle properties --- Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties | 3 --- .../org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED | 3 --- 2 files changed, 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties index 11626b384e..795018f1ac 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties @@ -101,9 +101,6 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show DiscoveryDialog.step1Label.text=Step 1: Choose result type -DividerPanel.jLabel1.text=jLabel1 -DividerPanel.jButton1.text=jButton1 -DividerPanel.jButton2.text=jButton2 ResultsSplitPaneDivider.hideButton.text= ResultsSplitPaneDivider.showButton.text= ResultsSplitPaneDivider.detailsLabel.text=Details Area diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index 4e8a849c0a..f74e2882b5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -262,9 +262,6 @@ DocumentFilterPanel.documentsFiltersSplitPane.border.title=Step 2: Filter which ImageFilterPanel.imageFiltersSplitPane.border.title=Step 2: Filter which images to show VideoFilterPanel.videoFiltersSplitPane.border.title=Step 2: Filter which videos to show DiscoveryDialog.step1Label.text=Step 1: Choose result type -DividerPanel.jLabel1.text=jLabel1 -DividerPanel.jButton1.text=jButton1 -DividerPanel.jButton2.text=jButton2 ResultsSplitPaneDivider.hideButton.text= ResultsSplitPaneDivider.showButton.text= ResultsSplitPaneDivider.detailsLabel.text=Details Area From 583ccf22e148134cca43c177dc01ce40e224b02a Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 24 Jun 2020 08:24:59 -0400 Subject: [PATCH 16/22] Fix typo. --- .../src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java index f5a146dd94..a8d3ed5581 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RefreshThrottler.java @@ -64,7 +64,7 @@ class RefreshThrottler { // The factory instance that will be called when a refresh is due. private final Refresher refresher; - private static final long MIN_SECONDS_BETWEEN_RERFESH = 5; + private static final long MIN_SECONDS_BETWEEN_REFRESH = 5; private static final Set INGEST_MODULE_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestModuleEvent.DATA_ADDED, IngestManager.IngestModuleEvent.CONTENT_CHANGED); @@ -103,7 +103,7 @@ class RefreshThrottler { RefreshTask task = new RefreshTask(); if (refreshTaskRef.compareAndSet(null, task)) { - refreshExecutor.schedule(task, MIN_SECONDS_BETWEEN_RERFESH, TimeUnit.SECONDS); + refreshExecutor.schedule(task, MIN_SECONDS_BETWEEN_REFRESH, TimeUnit.SECONDS); } } }; From 5df0c457d6dbcac59cd257c7abe15684bcde6d55 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 24 Jun 2020 10:06:58 -0400 Subject: [PATCH 17/22] 6457 change display string for filter results based on feedback --- .../discovery/Bundle.properties-MERGED | 26 +++++++++---------- .../discovery/DiscoveryTopComponent.java | 4 +-- .../discovery/FileSearchFiltering.java | 26 +++++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index f74e2882b5..f345be6246 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -11,7 +11,7 @@ DiscoveryTopComponent.name=\ Discovery DiscoveryTopComponent.newSearch.text=New Search DiscoveryTopComponent.searchCancelled.text=Search has been cancelled. # {0} - search -DiscoveryTopComponent.searchComplete.text=Results for {0} +DiscoveryTopComponent.searchComplete.text=Results with {0} # {0} - searchType DiscoveryTopComponent.searchInProgress.text=Performing search for results of type {0}. Please wait. DiscoveryUiUtility.bytes.text=bytes @@ -112,27 +112,27 @@ FileSearchFiltering.concatenateSetNamesForDisplay.comma=, # {1} - Data source ID FileSearchFiltering.DataSourceFilter.datasource={0}({1}) # {0} - filters -FileSearchFiltering.DataSourceFilter.desc=In data source(s): {0} -FileSearchFiltering.DataSourceFilter.or=\ or +FileSearchFiltering.DataSourceFilter.desc=data source(s): {0} +FileSearchFiltering.DataSourceFilter.or=, # {0} - filters -FileSearchFiltering.FileTypeFilter.desc=Files with type: {0} -FileSearchFiltering.FileTypeFilter.or=\ or +FileSearchFiltering.FileTypeFilter.desc=type: {0} +FileSearchFiltering.FileTypeFilter.or=, # {0} - filters -FileSearchFiltering.FrequencyFilter.desc=With frequency: {0} -FileSearchFiltering.FrequencyFilter.or=\ or +FileSearchFiltering.FrequencyFilter.desc=past occurrences: {0} +FileSearchFiltering.FrequencyFilter.or=, # {0} - filters FileSearchFiltering.HashSetFilter.desc=With hash set hits in set(s): {0} # {0} - filters FileSearchFiltering.InterestingItemSetFilter.desc=With interesting item hits in set(s): {0} # {0} - filters -FileSearchFiltering.KeywordListFilter.desc=With keywords in list(s): {0} +FileSearchFiltering.KeywordListFilter.desc=keywords in list(s): {0} FileSearchFiltering.KnownFilter.desc=Which are not known # {0} - filters FileSearchFiltering.ObjectDetectionFilter.desc=With objects detected in set(s): {0} # {0} - filters -FileSearchFiltering.ParentFilter.desc=With paths matching: {0} +FileSearchFiltering.ParentFilter.desc=paths matching: {0} FileSearchFiltering.ParentFilter.exact=(exact match) -FileSearchFiltering.ParentFilter.or=\ or +FileSearchFiltering.ParentFilter.or=, FileSearchFiltering.ParentFilter.substring=(substring) FileSearchFiltering.ParentSearchTerm.excludeString=\ (exclude) FileSearchFiltering.ParentSearchTerm.fullString=\ (exact) @@ -142,11 +142,11 @@ FileSearchFiltering.PreviouslyNotableFilter.desc=That were previously marked as # {0} - filters FileSearchFiltering.ScoreFilter.desc=With score(s) of : {0} # {0} - filters -FileSearchFiltering.SizeFilter.desc=With size(s): {0} -FileSearchFiltering.SizeFilter.or=, or +FileSearchFiltering.SizeFilter.desc=size(s): {0} +FileSearchFiltering.SizeFilter.or=, # {0} - tag names FileSearchFiltering.TagsFilter.desc=That have been tagged {0} -FileSearchFiltering.TagsFilter.or=\ or +FileSearchFiltering.TagsFilter.or=, FileSearchFiltering.UserCreatedFilter.desc=That contain EXIF data FileSearchPanel.sortingPanel.border.title=Grouping FileSearchPanel.addButton.text=Add diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java index 790d9e82da..607459325d 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryTopComponent.java @@ -280,11 +280,11 @@ public final class DiscoveryTopComponent extends TopComponent { @Subscribe @Messages({"DiscoveryTopComponent.newSearch.text=New Search", "# {0} - search", - "DiscoveryTopComponent.searchComplete.text=Results for {0}"}) + "DiscoveryTopComponent.searchComplete.text=Results with {0}"}) void handleSearchCompleteEvent(DiscoveryEventUtils.SearchCompleteEvent searchCompleteEvent) { newSearchButton.setText(Bundle.DiscoveryTopComponent_newSearch_text()); progressMessageTextArea.setForeground(Color.black); - progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(FileFilter::getDesc).collect(Collectors.joining(", ")))); + progressMessageTextArea.setText(Bundle.DiscoveryTopComponent_searchComplete_text(searchCompleteEvent.getFilters().stream().map(FileFilter::getDesc).collect(Collectors.joining("; ")))); progressMessageTextArea.setCaretPosition(0); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java index bfcf309835..f2d75c6c78 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java @@ -207,8 +207,8 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.SizeFilter.desc=With size(s): {0}", - "FileSearchFiltering.SizeFilter.or=, or "}) + "FileSearchFiltering.SizeFilter.desc=size(s): {0}", + "FileSearchFiltering.SizeFilter.or=, "}) @Override String getDesc() { String desc = ""; // NON-NLS @@ -361,8 +361,8 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ParentFilter.desc=With paths matching: {0}", - "FileSearchFiltering.ParentFilter.or= or ", + "FileSearchFiltering.ParentFilter.desc=paths matching: {0}", + "FileSearchFiltering.ParentFilter.or=, ", "FileSearchFiltering.ParentFilter.exact=(exact match)", "FileSearchFiltering.ParentFilter.substring=(substring)",}) @Override @@ -414,8 +414,8 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.DataSourceFilter.desc=In data source(s): {0}", - "FileSearchFiltering.DataSourceFilter.or= or ", + "FileSearchFiltering.DataSourceFilter.desc=data source(s): {0}", + "FileSearchFiltering.DataSourceFilter.or=, ", "# {0} - Data source name", "# {1} - Data source ID", "FileSearchFiltering.DataSourceFilter.datasource={0}({1})",}) @@ -463,7 +463,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.KeywordListFilter.desc=With keywords in list(s): {0}",}) + "FileSearchFiltering.KeywordListFilter.desc=keywords in list(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames)); @@ -513,8 +513,8 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.FileTypeFilter.desc=Files with type: {0}", - "FileSearchFiltering.FileTypeFilter.or= or ",}) + "FileSearchFiltering.FileTypeFilter.desc=type: {0}", + "FileSearchFiltering.FileTypeFilter.or=, ",}) @Override String getDesc() { String desc = ""; @@ -583,8 +583,8 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.FrequencyFilter.desc=With frequency: {0}", - "FileSearchFiltering.FrequencyFilter.or= or ",}) + "FileSearchFiltering.FrequencyFilter.desc=past occurrences: {0}", + "FileSearchFiltering.FrequencyFilter.or=, ",}) @Override String getDesc() { String desc = ""; // NON-NLS @@ -592,7 +592,7 @@ class FileSearchFiltering { if (!desc.isEmpty()) { desc += Bundle.FileSearchFiltering_FrequencyFilter_or(); } - desc += freq.name(); + desc += freq.toString(); } return Bundle.FileSearchFiltering_FrequencyFilter_desc(desc); } @@ -824,7 +824,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - tag names", "FileSearchFiltering.TagsFilter.desc=That have been tagged {0}", - "FileSearchFiltering.TagsFilter.or= or ",}) + "FileSearchFiltering.TagsFilter.or=, ",}) @Override String getDesc() { String desc = ""; // NON-NLS From ed8810a9b0e4fb04d852afd706342e2fc2ac2f94 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 24 Jun 2020 12:35:57 -0400 Subject: [PATCH 18/22] 6457 change arrow icons, fix video size, change text a bit --- .../discovery/Bundle.properties-MERGED | 28 +++++++++--------- .../autopsy/discovery/DiscoveryDialog.form | 3 ++ .../autopsy/discovery/DiscoveryDialog.java | 1 + .../discovery/DocumentFilterPanel.java | 1 - .../discovery/FileSearchFiltering.java | 28 +++++++++--------- .../autopsy/discovery/VideoFilterPanel.form | 13 +++++--- .../autopsy/discovery/VideoFilterPanel.java | 8 +++-- .../autopsy/discovery/arrow-down.png | Bin 1264 -> 7271 bytes .../sleuthkit/autopsy/discovery/arrow-up.png | Bin 1297 -> 7285 bytes 9 files changed, 46 insertions(+), 36 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index f345be6246..a7855005dd 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -112,25 +112,25 @@ FileSearchFiltering.concatenateSetNamesForDisplay.comma=, # {1} - Data source ID FileSearchFiltering.DataSourceFilter.datasource={0}({1}) # {0} - filters -FileSearchFiltering.DataSourceFilter.desc=data source(s): {0} +FileSearchFiltering.DataSourceFilter.desc=Data source(s): {0} FileSearchFiltering.DataSourceFilter.or=, # {0} - filters -FileSearchFiltering.FileTypeFilter.desc=type: {0} +FileSearchFiltering.FileTypeFilter.desc=Type: {0} FileSearchFiltering.FileTypeFilter.or=, # {0} - filters -FileSearchFiltering.FrequencyFilter.desc=past occurrences: {0} +FileSearchFiltering.FrequencyFilter.desc=Past occurrences: {0} FileSearchFiltering.FrequencyFilter.or=, # {0} - filters -FileSearchFiltering.HashSetFilter.desc=With hash set hits in set(s): {0} +FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0} # {0} - filters -FileSearchFiltering.InterestingItemSetFilter.desc=With interesting item hits in set(s): {0} +FileSearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0} # {0} - filters -FileSearchFiltering.KeywordListFilter.desc=keywords in list(s): {0} -FileSearchFiltering.KnownFilter.desc=Which are not known +FileSearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0} +FileSearchFiltering.KnownFilter.desc=which are not known # {0} - filters -FileSearchFiltering.ObjectDetectionFilter.desc=With objects detected in set(s): {0} +FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0} # {0} - filters -FileSearchFiltering.ParentFilter.desc=paths matching: {0} +FileSearchFiltering.ParentFilter.desc=Paths matching: {0} FileSearchFiltering.ParentFilter.exact=(exact match) FileSearchFiltering.ParentFilter.or=, FileSearchFiltering.ParentFilter.substring=(substring) @@ -138,16 +138,16 @@ FileSearchFiltering.ParentSearchTerm.excludeString=\ (exclude) FileSearchFiltering.ParentSearchTerm.fullString=\ (exact) FileSearchFiltering.ParentSearchTerm.includeString=\ (include) FileSearchFiltering.ParentSearchTerm.subString=\ (substring) -FileSearchFiltering.PreviouslyNotableFilter.desc=That were previously marked as notable +FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable # {0} - filters -FileSearchFiltering.ScoreFilter.desc=With score(s) of : {0} +FileSearchFiltering.ScoreFilter.desc=Score(s) of : {0} # {0} - filters -FileSearchFiltering.SizeFilter.desc=size(s): {0} +FileSearchFiltering.SizeFilter.desc=Size(s): {0} FileSearchFiltering.SizeFilter.or=, # {0} - tag names -FileSearchFiltering.TagsFilter.desc=That have been tagged {0} +FileSearchFiltering.TagsFilter.desc=Tagged {0} FileSearchFiltering.TagsFilter.or=, -FileSearchFiltering.UserCreatedFilter.desc=That contain EXIF data +FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data FileSearchPanel.sortingPanel.border.title=Grouping FileSearchPanel.addButton.text=Add FileSearchPanel.substringRadioButton.text=Substring diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form index 936dbeed1d..19116a24fe 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.form @@ -6,6 +6,9 @@ + + +
diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java index 0b88343f8c..33f69712f0 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DiscoveryDialog.java @@ -226,6 +226,7 @@ final class DiscoveryDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setMinimumSize(new java.awt.Dimension(600, 300)); + setPreferredSize(new java.awt.Dimension(1000, 650)); imagesButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/pictures-icon.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(imagesButton, org.openide.util.NbBundle.getMessage(DiscoveryDialog.class, "DiscoveryDialog.imagesButton.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java index 9756045387..216a3c12b3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/DocumentFilterPanel.java @@ -45,7 +45,6 @@ final class DocumentFilterPanel extends AbstractFiltersPanel { addFilter(new PastOccurrencesFilterPanel(), true, pastOccurrencesIndices, 0); addFilter(new HashSetFilterPanel(), false, null, 1); addFilter(new InterestingItemsFilterPanel(), false, null, 1); - addFilter(new ObjectDetectedFilterPanel(), false, null, 1); addFilter(new ParentFolderFilterPanel(), false, null, 1); addPanelsToScrollPane(documentsFiltersSplitPane); } diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java index f2d75c6c78..2d8b776b90 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java @@ -207,7 +207,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.SizeFilter.desc=size(s): {0}", + "FileSearchFiltering.SizeFilter.desc=Size(s): {0}", "FileSearchFiltering.SizeFilter.or=, "}) @Override String getDesc() { @@ -361,7 +361,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ParentFilter.desc=paths matching: {0}", + "FileSearchFiltering.ParentFilter.desc=Paths matching: {0}", "FileSearchFiltering.ParentFilter.or=, ", "FileSearchFiltering.ParentFilter.exact=(exact match)", "FileSearchFiltering.ParentFilter.substring=(substring)",}) @@ -414,7 +414,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.DataSourceFilter.desc=data source(s): {0}", + "FileSearchFiltering.DataSourceFilter.desc=Data source(s): {0}", "FileSearchFiltering.DataSourceFilter.or=, ", "# {0} - Data source name", "# {1} - Data source ID", @@ -463,7 +463,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.KeywordListFilter.desc=keywords in list(s): {0}",}) + "FileSearchFiltering.KeywordListFilter.desc=Keywords in list(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_KeywordListFilter_desc(concatenateSetNamesForDisplay(listNames)); @@ -513,7 +513,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.FileTypeFilter.desc=type: {0}", + "FileSearchFiltering.FileTypeFilter.desc=Type: {0}", "FileSearchFiltering.FileTypeFilter.or=, ",}) @Override String getDesc() { @@ -583,7 +583,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.FrequencyFilter.desc=past occurrences: {0}", + "FileSearchFiltering.FrequencyFilter.desc=Past occurrences: {0}", "FileSearchFiltering.FrequencyFilter.or=, ",}) @Override String getDesc() { @@ -629,7 +629,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.HashSetFilter.desc=With hash set hits in set(s): {0}",}) + "FileSearchFiltering.HashSetFilter.desc=Hash set hits in set(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_HashSetFilter_desc(concatenateSetNamesForDisplay(setNames)); @@ -667,7 +667,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.InterestingItemSetFilter.desc=With interesting item hits in set(s): {0}",}) + "FileSearchFiltering.InterestingItemSetFilter.desc=Interesting item hits in set(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_InterestingItemSetFilter_desc(concatenateSetNamesForDisplay(setNames)); @@ -705,7 +705,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ObjectDetectionFilter.desc=With objects detected in set(s): {0}",}) + "FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_ObjectDetectionFilter_desc(concatenateSetNamesForDisplay(typeNames)); @@ -781,7 +781,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - filters", - "FileSearchFiltering.ScoreFilter.desc=With score(s) of : {0}",}) + "FileSearchFiltering.ScoreFilter.desc=Score(s) of : {0}",}) @Override String getDesc() { return Bundle.FileSearchFiltering_ScoreFilter_desc( @@ -823,7 +823,7 @@ class FileSearchFiltering { @NbBundle.Messages({ "# {0} - tag names", - "FileSearchFiltering.TagsFilter.desc=That have been tagged {0}", + "FileSearchFiltering.TagsFilter.desc=Tagged {0}", "FileSearchFiltering.TagsFilter.or=, ",}) @Override String getDesc() { @@ -859,7 +859,7 @@ class FileSearchFiltering { } @NbBundle.Messages({ - "FileSearchFiltering.UserCreatedFilter.desc=That contain EXIF data",}) + "FileSearchFiltering.UserCreatedFilter.desc=that contain EXIF data",}) @Override String getDesc() { return Bundle.FileSearchFiltering_UserCreatedFilter_desc(); @@ -928,7 +928,7 @@ class FileSearchFiltering { } @NbBundle.Messages({ - "FileSearchFiltering.PreviouslyNotableFilter.desc=That were previously marked as notable",}) + "FileSearchFiltering.PreviouslyNotableFilter.desc=that were previously marked as notable",}) @Override String getDesc() { return Bundle.FileSearchFiltering_PreviouslyNotableFilter_desc(); @@ -946,7 +946,7 @@ class FileSearchFiltering { } @NbBundle.Messages({ - "FileSearchFiltering.KnownFilter.desc=Which are not known"}) + "FileSearchFiltering.KnownFilter.desc=which are not known"}) @Override String getDesc() { return Bundle.FileSearchFiltering_KnownFilter_desc(); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form index 259a188967..1a853b425a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.form @@ -11,12 +11,17 @@ - + + + + + + @@ -32,7 +37,7 @@ - + @@ -45,7 +50,7 @@ - + @@ -54,7 +59,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java index 48522a9474..4f2684339b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/VideoFilterPanel.java @@ -66,7 +66,9 @@ final class VideoFilterPanel extends AbstractFiltersPanel { setLayout(new java.awt.BorderLayout()); - videoFiltersPanel.setPreferredSize(new java.awt.Dimension(223, 66)); + videoFiltersScrollPane.setPreferredSize(new java.awt.Dimension(312, 102)); + + videoFiltersPanel.setPreferredSize(new java.awt.Dimension(310, 100)); videoFiltersSplitPane.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(VideoFilterPanel.class, "VideoFilterPanel.videoFiltersSplitPane.border.title"))); // NOI18N videoFiltersSplitPane.setResizeWeight(0.5); @@ -77,14 +79,14 @@ final class VideoFilterPanel extends AbstractFiltersPanel { videoFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(videoFiltersPanelLayout.createSequentialGroup() .addGap(8, 8, 8) - .addComponent(videoFiltersSplitPane) + .addComponent(videoFiltersSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 294, Short.MAX_VALUE) .addGap(8, 8, 8)) ); videoFiltersPanelLayout.setVerticalGroup( videoFiltersPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(videoFiltersPanelLayout.createSequentialGroup() .addGap(8, 8, 8) - .addComponent(videoFiltersSplitPane) + .addComponent(videoFiltersSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 84, Short.MAX_VALUE) .addGap(8, 8, 8)) ); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png b/Core/src/org/sleuthkit/autopsy/discovery/arrow-down.png index aeafeeb91a62dde9b66608ca3ce2de73ff005f80..e934b25655144d2c427c793cd238d11769cd4114 100644 GIT binary patch literal 7271 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 B-9-QZ delta 1257 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 P00000NkvXXu0mjf_Xp(o delta 1291 zcmV+m1@!v$IFSmF7k?QD1^@s6z#LUx00001b5ch_0Itp)=>Px#1ZP1_K>z@;j|==^ z1poj532;bRa{vGmbN~PnbOGLGA9w%&00(qQO+^Re3Iq)*4S>{dyZ`_MlSxEDR7gve zRY@rRT@*gNW=fVz_Qp#9Z*bz1oDZ_%YAb%2tC_^li!opOBg$xl3 zWXL?;?>@(Sf4%SL@B90ndf$70_ndp4bI(2JToS*;%gYOoCnqPOva*s#;Q9HP$KT*r zWQyqY^i-s#rV0-a50Rdpt`REv-|$y5W$5tmP$VTKF;Q@EFptT}$-EA{zP^gj&rhEJ z1QYzxAAsezw|_UXu&|)Ly*(-@D4?^mGqSX_WSLHj3o}M1^^73MRGcz+X zF)`6wF@~vrG=d?~*47r~=H@bywY4>`%Ttg%G1=JIkPI!$x3{;++}xbr-{19CzT+Di zh_C@fYinzipPx^cmzQK~Ys)8r*NKUVe1gZvN3yfCV}E&GULNa%5Dxtb-^gU#dBgJZ zG8GmU()IN<8-!t;q^72Zy1Tonw6v74 z5gHn5lnfY0Mn+h!(A(Q90s;awIn24ZxbS{J5*j59lNl1t&dwSUU$$YcOKR3T9t{QUgH)YKHq6>4j1dA+W#PQUVn@$qquP@NEts?Z~P9LB-HK{lWi zFv_|S^Yinp2*A6FiVBt~r|_+!0w8qQ2bm)D_kZ^n0|Nsr*U1a5t*@`=WI-Jv>ztjP zsjI7t;^X6a9d%V+UQY6qToM3Me`jZh3qBQrtA|iOiw+eqwPL8;}z18m&Vsmqo z%Llr1b920=B?t&NHa2(;oS&bI%*;$J?!LahJTECJ5f>L1qPV!2zd;5$=2=-;yiZ|e zWkn+bOpqlA3686PJ}5n<hP09{j4*{t-WLdKUzyjk+X*;AAN(%I3`QOH)razN<<)z#Iki;$`;O-oDD-n#qy zdmaJqjmQ{W;?dC&H{SjIea<9!ic?)(U6H&`_7dOFRn4}ksfn_)v)OytK_qr}cYoQ= z!NCFB(fXu%9HoLtNJwDM;2}Ik%``MLupB_IGlbzc^gKO1d7o+uv9Ym2K0PdlE{Ab_ zeVsEA3Mgu9z^}QvnH2%U;x&ZfI`q|ERn%c&VPbW4mE}5FxV19FxCjvf)DSMStgMXd z3qXhr6UY$IMS|g-i;0QhVwYK{U4PBp-5rgNj*@hMbn?ixi;Ig)1O;ras;Z)*q9Qi- zUqlKZQiPF_k$g{h4`EN;y_=icS2nh_wegV=^Zx#RJ~HrA=zfBs{?O16UkPl=j>KzP z>bJJG3RxfeFQL6b{}&)c?E+}RL7ea`C0OBwsO$-xRj{pDw07*qoL Date: Wed, 24 Jun 2020 17:00:26 -0400 Subject: [PATCH 19/22] 6457 fix parent filter checkbox action, add included / excluded to desc --- .../autopsy/discovery/AbstractFiltersPanel.java | 2 +- .../sleuthkit/autopsy/discovery/Bundle.properties-MERGED | 2 ++ .../sleuthkit/autopsy/discovery/FileSearchFiltering.java | 9 ++++++++- .../autopsy/discovery/ParentFolderFilterPanel.java | 4 +++- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java index 7bcd1c8243..2f718c3aa5 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/AbstractFiltersPanel.java @@ -101,7 +101,7 @@ abstract class AbstractFiltersPanel extends JPanel implements ActionListener, Li constraints.weightx = LABEL_WEIGHT; constraints.weighty = LABEL_WEIGHT; constraints.gridwidth = LABEL_WIDTH; - addToGridBagLayout(filterPanel.getCheckbox(), null, column); + addToGridBagLayout(filterPanel.getCheckbox(), filterPanel.getAdditionalLabel(), column); if (filterPanel.hasPanel()) { constraints.gridx += constraints.gridwidth; constraints.fill = GridBagConstraints.BOTH; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED index a7855005dd..df1b6b8fd2 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/discovery/Bundle.properties-MERGED @@ -132,6 +132,8 @@ FileSearchFiltering.ObjectDetectionFilter.desc=Objects detected in set(s): {0} # {0} - filters FileSearchFiltering.ParentFilter.desc=Paths matching: {0} FileSearchFiltering.ParentFilter.exact=(exact match) +FileSearchFiltering.ParentFilter.excluded=(excluded) +FileSearchFiltering.ParentFilter.included=(included) FileSearchFiltering.ParentFilter.or=, FileSearchFiltering.ParentFilter.substring=(substring) FileSearchFiltering.ParentSearchTerm.excludeString=\ (exclude) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java index 2d8b776b90..adf301537a 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/FileSearchFiltering.java @@ -364,7 +364,9 @@ class FileSearchFiltering { "FileSearchFiltering.ParentFilter.desc=Paths matching: {0}", "FileSearchFiltering.ParentFilter.or=, ", "FileSearchFiltering.ParentFilter.exact=(exact match)", - "FileSearchFiltering.ParentFilter.substring=(substring)",}) + "FileSearchFiltering.ParentFilter.substring=(substring)", + "FileSearchFiltering.ParentFilter.included=(included)", + "FileSearchFiltering.ParentFilter.excluded=(excluded)"}) @Override String getDesc() { String desc = ""; // NON-NLS @@ -377,6 +379,11 @@ class FileSearchFiltering { } else { desc += searchTerm.getSearchStr() + Bundle.FileSearchFiltering_ParentFilter_substring(); } + if (searchTerm.isIncluded()) { + desc += Bundle.FileSearchFiltering_ParentFilter_included(); + } else { + desc += Bundle.FileSearchFiltering_ParentFilter_excluded(); + } } desc = Bundle.FileSearchFiltering_ParentFilter_desc(desc); return desc; diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java index 3ecb095868..aee8a64706 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java @@ -188,7 +188,7 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { }// //GEN-END:initComponents private void parentCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_parentCheckboxActionPerformed -// parentFilterSettings(true, true, parentCheckbox.isSelected(), null); + configurePanel(parentCheckbox.isSelected(), null); }//GEN-LAST:event_parentCheckboxActionPerformed private void parentListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_parentListValueChanged @@ -235,6 +235,7 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { parentCheckbox.setSelected(selected); if (parentCheckbox.isEnabled() && parentCheckbox.isSelected()) { parentScrollPane.setEnabled(true); + parentLabel.setEnabled(true); includeRadioButton.setEnabled(true); excludeRadioButton.setEnabled(true); fullRadioButton.setEnabled(true); @@ -248,6 +249,7 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { } } else { parentScrollPane.setEnabled(false); + parentLabel.setEnabled(false); parentList.setEnabled(false); includeRadioButton.setEnabled(false); excludeRadioButton.setEnabled(false); From 58fe4c8c2b224f11bfdd3d8be6fa12fd73e31449 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 24 Jun 2020 18:47:38 -0400 Subject: [PATCH 20/22] 6457 fix radio button groups for parent folder filter --- .../discovery/ParentFolderFilterPanel.form | 16 ++++++++++++++++ .../discovery/ParentFolderFilterPanel.java | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form index c35bc16cb4..2b7f43f36e 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form @@ -37,6 +37,10 @@ + + + + @@ -143,6 +147,9 @@ + + + @@ -152,6 +159,9 @@ + + + @@ -161,6 +171,9 @@ + + + @@ -169,6 +182,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java index aee8a64706..1ef705c66b 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java @@ -66,6 +66,8 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { parentCheckbox = new javax.swing.JCheckBox(); parentLabel = new javax.swing.JLabel(); + includeButtonGroup = new javax.swing.ButtonGroup(); + pathTypeButtonGroup = new javax.swing.ButtonGroup(); parentScrollPane = new javax.swing.JScrollPane(); parentList = new javax.swing.JList<>(); fullRadioButton = new javax.swing.JRadioButton(); @@ -106,17 +108,21 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { }); parentScrollPane.setViewportView(parentList); + pathTypeButtonGroup.add(fullRadioButton); fullRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(fullRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.fullRadioButton.text_1")); // NOI18N fullRadioButton.setEnabled(false); + includeButtonGroup.add(includeRadioButton); includeRadioButton.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(includeRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.includeRadioButton.text_1")); // NOI18N includeRadioButton.setEnabled(false); + pathTypeButtonGroup.add(substringRadioButton); org.openide.awt.Mnemonics.setLocalizedText(substringRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.substringRadioButton.text_1")); // NOI18N substringRadioButton.setEnabled(false); + includeButtonGroup.add(excludeRadioButton); org.openide.awt.Mnemonics.setLocalizedText(excludeRadioButton, org.openide.util.NbBundle.getMessage(ParentFolderFilterPanel.class, "ParentFolderFilterPanel.excludeRadioButton.text_1")); // NOI18N excludeRadioButton.setEnabled(false); @@ -221,12 +227,14 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { private javax.swing.JButton deleteButton; private javax.swing.JRadioButton excludeRadioButton; private javax.swing.JRadioButton fullRadioButton; + private javax.swing.ButtonGroup includeButtonGroup; private javax.swing.JRadioButton includeRadioButton; private javax.swing.JCheckBox parentCheckbox; private javax.swing.JLabel parentLabel; private javax.swing.JList parentList; private javax.swing.JScrollPane parentScrollPane; private javax.swing.JTextField parentTextField; + private javax.swing.ButtonGroup pathTypeButtonGroup; private javax.swing.JRadioButton substringRadioButton; // End of variables declaration//GEN-END:variables From 7b41f84b2c1014a645ab858b35c77f17b60a2bbc Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 24 Jun 2020 19:01:39 -0400 Subject: [PATCH 21/22] 6457 make button groups local variables to satisfy codacy --- .../autopsy/discovery/ParentFolderFilterPanel.form | 8 ++++++++ .../autopsy/discovery/ParentFolderFilterPanel.java | 6 ++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form index 2b7f43f36e..b350ab42b3 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.form @@ -38,8 +38,16 @@ + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java index 1ef705c66b..7f10b38692 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ParentFolderFilterPanel.java @@ -66,8 +66,8 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { parentCheckbox = new javax.swing.JCheckBox(); parentLabel = new javax.swing.JLabel(); - includeButtonGroup = new javax.swing.ButtonGroup(); - pathTypeButtonGroup = new javax.swing.ButtonGroup(); + javax.swing.ButtonGroup includeButtonGroup = new javax.swing.ButtonGroup(); + javax.swing.ButtonGroup pathTypeButtonGroup = new javax.swing.ButtonGroup(); parentScrollPane = new javax.swing.JScrollPane(); parentList = new javax.swing.JList<>(); fullRadioButton = new javax.swing.JRadioButton(); @@ -227,14 +227,12 @@ final class ParentFolderFilterPanel extends AbstractDiscoveryFilterPanel { private javax.swing.JButton deleteButton; private javax.swing.JRadioButton excludeRadioButton; private javax.swing.JRadioButton fullRadioButton; - private javax.swing.ButtonGroup includeButtonGroup; private javax.swing.JRadioButton includeRadioButton; private javax.swing.JCheckBox parentCheckbox; private javax.swing.JLabel parentLabel; private javax.swing.JList parentList; private javax.swing.JScrollPane parentScrollPane; private javax.swing.JTextField parentTextField; - private javax.swing.ButtonGroup pathTypeButtonGroup; private javax.swing.JRadioButton substringRadioButton; // End of variables declaration//GEN-END:variables From 43de228dc9519ef7071ff9a816e928401909eca1 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 25 Jun 2020 11:07:02 -0400 Subject: [PATCH 22/22] Revert "1485 - CentralRepository getInstance will throw exception when CR is disabled" --- .../datamodel/CentralRepository.java | 2 +- .../datamodel/PersonaAccount.java | 116 ++++++++++++------ 2 files changed, 79 insertions(+), 39 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index 9b4f610721..a6af74ad3c 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -53,7 +53,7 @@ public interface CentralRepository { case SQLITE: return SqliteCentralRepo.getInstance(); default: - throw new CentralRepoException("Failed to get CentralRepository instance, Central Repositiory is not enabled."); + return null; } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java index e0dcf11361..efd8b76152 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java @@ -121,18 +121,22 @@ public class PersonaAccount { /** * Creates an account for the specified Persona. * - * @param persona Persona for which the account is being added. - * @param account Account. + * @param persona Persona for which the account is being added. + * @param account Account. * @param justification Reason for assigning the alias, may be null. - * @param confidence Confidence level. + * @param confidence Confidence level. * * @return PersonaAccount - * * @throws CentralRepoException If there is an error in creating the - * account. + * account. */ static PersonaAccount addPersonaAccount(Persona persona, CentralRepoAccount account, String justification, Persona.Confidence confidence) throws CentralRepoException { CentralRepository cr = CentralRepository.getInstance(); + + if(cr == null) { + throw new CentralRepoException("Failed to add Persona, Central Repository is not enable"); + } + CentralRepoExaminer currentExaminer = cr.getOrInsertExaminer(System.getProperty("user.name")); Instant instant = Instant.now(); @@ -147,7 +151,7 @@ public class PersonaAccount { + currentExaminer.getId() + ")"; - cr.executeInsertSQL(insertClause); + CentralRepository.getInstance().executeInsertSQL(insertClause); String queryClause = PERSONA_ACCOUNTS_QUERY_CLAUSE + "WHERE persona_id = " + persona.getId() @@ -245,13 +249,19 @@ public class PersonaAccount { * persona_account. */ static Collection getPersonaAccountsForPersona(long personaId) throws CentralRepoException { - String queryClause = PERSONA_ACCOUNTS_QUERY_CLAUSE - + " WHERE persona_accounts.persona_id = " + personaId; + CentralRepository cr = CentralRepository.getInstance(); - PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); - CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); + if (cr != null) { + String queryClause = PERSONA_ACCOUNTS_QUERY_CLAUSE + + " WHERE persona_accounts.persona_id = " + personaId; - return queryCallback.getPersonaAccountsList(); + PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); + cr.executeSelectSQL(queryClause, queryCallback); + + return queryCallback.getPersonaAccountsList(); + } + + return new ArrayList<>(); } /** @@ -269,10 +279,16 @@ public class PersonaAccount { + " WHERE persona_accounts.account_id = " + accountId + " AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId(); - PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); - CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); + CentralRepository cr = CentralRepository.getInstance(); - return queryCallback.getPersonaAccountsList(); + if (cr != null) { + PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); + cr.executeSelectSQL(queryClause, queryCallback); + + return queryCallback.getPersonaAccountsList(); + } + + return new ArrayList<>(); } /** @@ -292,10 +308,15 @@ public class PersonaAccount { + " WHERE LOWER(accounts.account_unique_identifier) LIKE LOWER('%" + accountIdentifierSubstring + "%')" + " AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId(); - PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); - CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); + CentralRepository cr = CentralRepository.getInstance(); + if (cr != null) { + PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); + cr.executeSelectSQL(queryClause, queryCallback); - return queryCallback.getPersonaAccountsList(); + return queryCallback.getPersonaAccountsList(); + } + + return new ArrayList<>(); } /** @@ -314,10 +335,14 @@ public class PersonaAccount { + " AND type_name = '" + account.getAccountType().getTypeName() + "' " + " AND personas.status_id != " + Persona.PersonaStatus.DELETED.getStatusId(); - PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); - CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); - return queryCallback.getPersonaAccountsList(); + CentralRepository cr = CentralRepository.getInstance(); + if (cr != null) { + PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); + cr.executeSelectSQL(queryClause, queryCallback); + return queryCallback.getPersonaAccountsList(); + } + return new ArrayList<>(); } /** @@ -326,24 +351,36 @@ public class PersonaAccount { * @param id row id for the account to be removed * * @throws CentralRepoException If there is an error in removing the - * account. + * account. */ static void removePersonaAccount(long id) throws CentralRepoException { + CentralRepository cr = CentralRepository.getInstance(); + + if(cr == null) { + throw new CentralRepoException("Failed to remove persona account, Central Repo is not enabled"); + } + String deleteClause = " DELETE FROM persona_accounts WHERE id = " + id; - CentralRepository.getInstance().executeDeleteSQL(deleteClause); + cr.executeDeleteSQL(deleteClause); } - + /** * Modifies the PersonaAccount row by the given id * * @param id row id for the account to be removed * * @throws CentralRepoException If there is an error in removing the - * account. + * account. */ static void modifyPersonaAccount(long id, Persona.Confidence confidence, String justification) throws CentralRepoException { + CentralRepository cr = CentralRepository.getInstance(); + + if (cr == null) { + throw new CentralRepoException("Failed to modify persona account, Central Repo is not enabled"); + } + String updateClause = "UPDATE persona_accounts SET confidence_id = " + confidence.getLevelId() + ", justification = \"" + justification + "\" WHERE id = " + id; - CentralRepository.getInstance().executeUpdateSQL(updateClause); + cr.executeUpdateSQL(updateClause); } /** @@ -381,25 +418,28 @@ public class PersonaAccount { * @param personaId Id of the persona to look for. * * @return Collection of all accounts associated with the given persona, may - * be empty. - * + * be empty. * @throws CentralRepoException If there is an error in getting the - * accounts. + * accounts. */ static Collection getAccountsForPersona(long personaId) throws CentralRepoException { + CentralRepository cr = CentralRepository.getInstance(); - String queryClause = "SELECT account_id, " - + " accounts.account_type_id as account_type_id, accounts.account_unique_identifier as account_unique_identifier," - + " account_types.type_name as type_name " - + " FROM persona_accounts " - + " JOIN accounts as accounts on persona_accounts.account_id = accounts.id " - + " JOIN account_types as account_types on accounts.account_type_id = account_types.id " - + " WHERE persona_accounts.persona_id = " + personaId; + if (cr != null) { + String queryClause = "SELECT account_id, " + + " accounts.account_type_id as account_type_id, accounts.account_unique_identifier as account_unique_identifier," + + " account_types.type_name as type_name " + + " FROM persona_accounts " + + " JOIN accounts as accounts on persona_accounts.account_id = accounts.id " + + " JOIN account_types as account_types on accounts.account_type_id = account_types.id " + + " WHERE persona_accounts.persona_id = " + personaId; - AccountsForPersonaQueryCallback queryCallback = new AccountsForPersonaQueryCallback(); - CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); + AccountsForPersonaQueryCallback queryCallback = new AccountsForPersonaQueryCallback(); + cr.executeSelectSQL(queryClause, queryCallback); - return queryCallback.getAccountsList(); + return queryCallback.getAccountsList(); + } + return new ArrayList<>(); } }