mirror of
https://github.com/elisspace/autopsy.git
synced 2026-10-04 00:09:53 +00:00
Merge pull request #4221 from esaunders/develop
Merge release-4.9.0 into develop
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
||||
OpenIDE-Module: org.sleuthkit.autopsy.core/10
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
|
||||
OpenIDE-Module-Implementation-Version: 24
|
||||
OpenIDE-Module-Implementation-Version: 25
|
||||
OpenIDE-Module-Requires: org.openide.windows.WindowManager
|
||||
AutoUpdate-Show-In-Client: true
|
||||
AutoUpdate-Essential-Module: true
|
||||
|
||||
@@ -47,5 +47,5 @@ nbm.homepage=http://www.sleuthkit.org/
|
||||
nbm.module.author=Brian Carrier
|
||||
nbm.needs.restart=true
|
||||
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
|
||||
spec.version.base=10.12
|
||||
spec.version.base=10.13
|
||||
|
||||
|
||||
@@ -127,7 +127,10 @@ public class EamArtifactUtil {
|
||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() == artifactTypeID)) {
|
||||
|
||||
// Lower-case this to normalize domains
|
||||
value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN)).getValueString();
|
||||
BlackboardAttribute attribute = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN));
|
||||
if (attribute != null) {
|
||||
value = attribute.getValueString();
|
||||
}
|
||||
} else if (correlationType.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID
|
||||
&& (BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT.getTypeID() == artifactTypeID
|
||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG.getTypeID() == artifactTypeID
|
||||
@@ -171,7 +174,7 @@ public class EamArtifactUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (null != value) {
|
||||
if ((null != value) && (value.isEmpty() == false)) {
|
||||
return makeCorrelationAttributeInstanceUsingTypeValue(bbArtifact, correlationType, value);
|
||||
} else {
|
||||
return null;
|
||||
|
||||
+22
-22
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> 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.
|
||||
@@ -29,14 +29,13 @@ import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||
import org.sleuthkit.autopsy.corecomponents.DelayedLoadChildNodesOnTreeExpansion;
|
||||
|
||||
/**
|
||||
* <code>DataResultViewerTable</code> which overrides the default column
|
||||
* header width calculations. The <code>CommonAttributesSearchResultsViewerTable</code>
|
||||
* presents multiple tiers of data which are not always present and it may not
|
||||
* make sense to try to calculate the column widths for such tables by sampling
|
||||
* rows and looking for wide cells. Rather, we just pick some reasonable values.
|
||||
* <code>DataResultViewerTable</code> which overrides the default column header
|
||||
* width calculations. The <code>CommonAttributesSearchResultsViewerTable</code>
|
||||
* presents multiple tiers of data which are not always present and it may not
|
||||
* make sense to try to calculate the column widths for such tables by sampling
|
||||
* rows and looking for wide cells. Rather, we just pick some reasonable values.
|
||||
*/
|
||||
public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTable {
|
||||
|
||||
@@ -44,7 +43,7 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(CommonAttributesSearchResultsViewerTable.class.getName());
|
||||
|
||||
|
||||
private static final int DEFAULT_WIDTH = 100;
|
||||
|
||||
static {
|
||||
@@ -60,19 +59,20 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa
|
||||
|
||||
COLUMN_WIDTHS = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a DataResultViewerTable which constructs a tabular result viewer that
|
||||
* displays the children of the given root node using an OutlineView. The explorer
|
||||
* manager will be discovered at runtime.
|
||||
*
|
||||
* Adds a TreeExpansionsListener to the outlineView to receive tree expansion events
|
||||
* which dynamically loads children nodes when requested.
|
||||
* Implements a DataResultViewerTable which constructs a tabular result
|
||||
* viewer that displays the children of the given root node using an
|
||||
* OutlineView. The explorer manager will be discovered at runtime.
|
||||
*
|
||||
* Adds a TreeExpansionsListener to the outlineView to receive tree
|
||||
* expansion events which dynamically loads children nodes when requested.
|
||||
*/
|
||||
public CommonAttributesSearchResultsViewerTable() {
|
||||
super();
|
||||
outlineView.addTreeExpansionListener(new DelayedLoadChildNodesOnTreeExpansion());
|
||||
addTreeExpansionListener(new InstanceCountNodeTreeExpansionListener());
|
||||
}
|
||||
|
||||
|
||||
@NbBundle.Messages({
|
||||
"CommonFilesSearchResultsViewerTable.noDescText= ",
|
||||
"CommonFilesSearchResultsViewerTable.filesColLbl=Files",
|
||||
@@ -96,8 +96,8 @@ public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTa
|
||||
final String headerValue = column.getHeaderValue().toString();
|
||||
|
||||
final Integer defaultWidth = COLUMN_WIDTHS.get(headerValue);
|
||||
|
||||
if(defaultWidth == null){
|
||||
|
||||
if (defaultWidth == null) {
|
||||
column.setPreferredWidth(DEFAULT_WIDTH);
|
||||
LOGGER.log(Level.SEVERE, String.format("Tried to set width on a column not supported by the CommonFilesSearchResultsViewerTable: %s", headerValue));
|
||||
} else {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||
* Node used to indicate the number of matches found with the MD5 children of
|
||||
* this Node.
|
||||
*/
|
||||
final public class InstanceCountNode extends DisplayableItemNode {
|
||||
public final class InstanceCountNode extends DisplayableItemNode {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(InstanceCountNode.class.getName());
|
||||
|
||||
@@ -74,11 +74,10 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the node, by dynamically loading in the children when called, and
|
||||
* calling the CommonAttributeValueNodeFactory to generate nodes for the
|
||||
* children in attributeValues.
|
||||
* Creates the Children of this node. By doing this here instead of in the
|
||||
* constructor, lazy creation of the Children is made possible.
|
||||
*/
|
||||
public void refresh() {
|
||||
void createChildren() {
|
||||
attributeValues.displayDelayedMetadata();
|
||||
setChildren(Children.create(new CommonAttributeValueNodeFactory(attributeValues.getMetadataList()), true));
|
||||
}
|
||||
|
||||
+21
-21
@@ -1,54 +1,54 @@
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.corecomponents;
|
||||
package org.sleuthkit.autopsy.commonfilesearch;
|
||||
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeExpansionListener;
|
||||
import org.openide.explorer.view.Visualizer;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||
|
||||
/**
|
||||
* A tree expansion listener that will trigger a recreation of childs through
|
||||
* its child factory on re-expansion of a node (causes to recreate the
|
||||
* ChildFactory for this purpose.).
|
||||
* A tree expansion listener used to do lazy creation of the Childfren of an
|
||||
* InstanceCountNode when the node is expanded.
|
||||
*/
|
||||
public final class DelayedLoadChildNodesOnTreeExpansion implements TreeExpansionListener {
|
||||
|
||||
/**
|
||||
* A flag for avoiding endless recursion inside the expansion listener that
|
||||
* could trigger collapsing and (re-)expanding nodes again.
|
||||
* @param event
|
||||
*/
|
||||
final class InstanceCountNodeTreeExpansionListener implements TreeExpansionListener {
|
||||
|
||||
@Override
|
||||
public synchronized void treeCollapsed(final TreeExpansionEvent event) {
|
||||
// Do nothing on collapse. Netbeans should manage nodes falling out of scope and GC.
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void treeExpanded(final TreeExpansionEvent event) {
|
||||
Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent());
|
||||
final Node eventNode = Visualizer.findNode(event.getPath().getLastPathComponent());
|
||||
if (eventNode instanceof TableFilterNode) {
|
||||
final TableFilterNode node = (TableFilterNode) eventNode;
|
||||
node.refresh();
|
||||
final TableFilterNode tableFilterNode = (TableFilterNode) eventNode;
|
||||
final DataResultFilterNode dataResultFilterNode = tableFilterNode.getLookup().lookup(DataResultFilterNode.class);
|
||||
if (dataResultFilterNode != null) {
|
||||
final InstanceCountNode instanceCountNode = dataResultFilterNode.getLookup().lookup(InstanceCountNode.class);
|
||||
if (instanceCountNode != null) {
|
||||
instanceCountNode.createChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,7 +53,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.SqliteUtil;
|
||||
|
||||
/**
|
||||
* A file content viewer for SQLite database files.
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.coreutils;
|
||||
package org.sleuthkit.autopsy.contentviewers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -34,7 +34,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
* Sqlite utility class. Find and copy metafiles, write sqlite abstract files to
|
||||
* temp directory, and generate unique temp directory paths.
|
||||
*/
|
||||
public final class SqliteUtil {
|
||||
final class SqliteUtil {
|
||||
|
||||
private SqliteUtil() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2017 Basis Technology Corp.
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -190,3 +190,5 @@ ViewPreferencesPanel.hideRejectedResultsCheckbox.text=Hide rejected results
|
||||
ViewPreferencesPanel.hideOtherUsersTagsLabel.text=Hide other users' tags in the:
|
||||
ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for:
|
||||
ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns to reduce loading times
|
||||
ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000
|
||||
ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed:
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
<Container class="org.openide.explorer.view.OutlineView" name="outlineView">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new OutlineView(DataResultViewerTable.FIRST_COLUMN_LABEL);"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
|
||||
@@ -46,6 +46,7 @@ import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.TableColumnModelEvent;
|
||||
import javax.swing.event.TableColumnModelListener;
|
||||
import javax.swing.event.TreeExpansionListener;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
@@ -265,6 +266,16 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tree expansion listener to the OutlineView of this tabular results
|
||||
* viewer.
|
||||
*
|
||||
* @param listener The listener
|
||||
*/
|
||||
protected void addTreeExpansionListener(TreeExpansionListener listener) {
|
||||
outlineView.addTreeExpansionListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the Outline view of this tabular result viewer by creating column
|
||||
* headers based on the children of the current root node. The persisted
|
||||
@@ -1036,7 +1047,7 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
protected org.openide.explorer.view.OutlineView outlineView;
|
||||
private org.openide.explorer.view.OutlineView outlineView;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
}
|
||||
|
||||
@@ -128,16 +128,6 @@ public class TableFilterNode extends FilterNode {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the inner node, which depending on the actual node type that was wrapped
|
||||
* could trigger a dynamic refresh of the children, if supported.
|
||||
*/
|
||||
void refresh() {
|
||||
DataResultFilterNode innerNode = getLookup().lookup(DataResultFilterNode.class);
|
||||
innerNode.refresh();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the column order key, which allows custom column ordering to be
|
||||
|
||||
@@ -79,65 +79,72 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
|
||||
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="dataSourcesHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="viewsHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="hideSlackFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="dataSourcesHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="viewsHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="keepCurrentViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useGMTTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="centralRepoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="deletedFilesLimitCheckbox" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
|
||||
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="dataSourcesHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="viewsHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="hideSlackFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="dataSourcesHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="viewsHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="keepCurrentViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useGMTTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="centralRepoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="10" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace pref="16" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="hideKnownFilesLabel" min="-2" max="-2" attributes="0"/>
|
||||
@@ -174,6 +181,11 @@
|
||||
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="deletedFilesLimitLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="deletedFilesLimitCheckbox" min="-2" pref="33" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -327,6 +339,23 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="deletedFilesLimitCheckbox">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.deletedFilesLimitCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="deletedFilesLimitCheckboxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="deletedFilesLimitLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.deletedFilesLimitLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel">
|
||||
@@ -388,7 +417,7 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="hideRejectedResultsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="hideRejectedResultsCheckbox" min="-2" pref="259" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
|
||||
/**
|
||||
@@ -61,10 +62,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
|
||||
dataSourcesHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInDataSourcesTree());
|
||||
viewsHideSlackCheckbox.setSelected(UserPreferences.hideSlackFilesInViewsTree());
|
||||
|
||||
|
||||
commentsOccurencesColumnsCheckbox.setEnabled(EamDbUtil.useCentralRepo());
|
||||
commentsOccurencesColumnsCheckbox.setSelected(UserPreferences.hideCentralRepoCommentsAndOccurrences());
|
||||
|
||||
deletedFilesLimitCheckbox.setSelected(DeletedFilePreferences.getDefault().getShouldLimitDeletedFiles());
|
||||
|
||||
// Current Case Settings
|
||||
boolean caseIsOpen = Case.isCaseOpen();
|
||||
currentCaseSettingsPanel.setEnabled(caseIsOpen);
|
||||
@@ -91,6 +94,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
storeGroupItemsInTreeByDataSource();
|
||||
|
||||
DirectoryTreeTopComponent.getDefault().setShowRejectedResults(hideRejectedResultsCheckbox.isSelected() == false);
|
||||
|
||||
DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,6 +140,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
hideOtherUsersTagsLabel = new javax.swing.JLabel();
|
||||
commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox();
|
||||
centralRepoLabel = new javax.swing.JLabel();
|
||||
deletedFilesLimitCheckbox = new javax.swing.JCheckBox();
|
||||
deletedFilesLimitLabel = new javax.swing.JLabel();
|
||||
currentCaseSettingsPanel = new javax.swing.JPanel();
|
||||
groupByDataSourceCheckbox = new javax.swing.JCheckBox();
|
||||
currentSessionSettingsPanel = new javax.swing.JPanel();
|
||||
@@ -228,6 +235,15 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(centralRepoLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.centralRepoLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitCheckbox, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitCheckbox.text")); // NOI18N
|
||||
deletedFilesLimitCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
deletedFilesLimitCheckboxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel);
|
||||
globalSettingsPanel.setLayout(globalSettingsPanelLayout);
|
||||
globalSettingsPanelLayout.setHorizontalGroup(
|
||||
@@ -235,46 +251,51 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(hideKnownFilesLabel)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(dataSourcesHideSlackCheckbox)
|
||||
.addComponent(viewsHideSlackCheckbox)))
|
||||
.addComponent(hideSlackFilesLabel))
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(dataSourcesHideKnownCheckbox)
|
||||
.addComponent(viewsHideKnownCheckbox)))))
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(displayTimeLabel)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(keepCurrentViewerRadioButton)
|
||||
.addComponent(useBestViewerRadioButton)
|
||||
.addComponent(useGMTTimeRadioButton)
|
||||
.addComponent(useLocalTimeRadioButton)))
|
||||
.addComponent(selectFileLabel)))
|
||||
.addComponent(hideOtherUsersTagsLabel)
|
||||
.addComponent(centralRepoLabel)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(commentsOccurencesColumnsCheckbox)
|
||||
.addComponent(hideOtherUsersTagsCheckbox))))
|
||||
.addContainerGap(16, Short.MAX_VALUE))
|
||||
.addComponent(hideOtherUsersTagsCheckbox)
|
||||
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(hideKnownFilesLabel)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(dataSourcesHideSlackCheckbox)
|
||||
.addComponent(viewsHideSlackCheckbox)))
|
||||
.addComponent(hideSlackFilesLabel))
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(dataSourcesHideKnownCheckbox)
|
||||
.addComponent(viewsHideKnownCheckbox)))))
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(displayTimeLabel)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(keepCurrentViewerRadioButton)
|
||||
.addComponent(useBestViewerRadioButton)
|
||||
.addComponent(useGMTTimeRadioButton)
|
||||
.addComponent(useLocalTimeRadioButton)))
|
||||
.addComponent(selectFileLabel)))
|
||||
.addComponent(hideOtherUsersTagsLabel)
|
||||
.addComponent(centralRepoLabel)
|
||||
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(0, 10, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
globalSettingsPanelLayout.setVerticalGroup(
|
||||
globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addContainerGap()
|
||||
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
|
||||
.addComponent(hideKnownFilesLabel)
|
||||
@@ -307,7 +328,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(centralRepoLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(commentsOccurencesColumnsCheckbox))
|
||||
.addComponent(commentsOccurencesColumnsCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(deletedFilesLimitLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
|
||||
currentCaseSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.currentCaseSettingsPanel.border.title"))); // NOI18N
|
||||
@@ -350,7 +376,7 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
currentSessionSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(currentSessionSettingsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(hideRejectedResultsCheckbox)
|
||||
.addComponent(hideRejectedResultsCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
currentSessionSettingsPanelLayout.setVerticalGroup(
|
||||
@@ -501,6 +527,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
}
|
||||
}//GEN-LAST:event_commentsOccurencesColumnsCheckboxActionPerformed
|
||||
|
||||
private void deletedFilesLimitCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deletedFilesLimitCheckboxActionPerformed
|
||||
if (immediateUpdates) {
|
||||
DeletedFilePreferences.getDefault().setShouldLimitDeletedFiles(deletedFilesLimitCheckbox.isSelected());
|
||||
} else {
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}
|
||||
}//GEN-LAST:event_deletedFilesLimitCheckboxActionPerformed
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel centralRepoLabel;
|
||||
@@ -509,6 +543,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
private javax.swing.JPanel currentSessionSettingsPanel;
|
||||
private javax.swing.JCheckBox dataSourcesHideKnownCheckbox;
|
||||
private javax.swing.JCheckBox dataSourcesHideSlackCheckbox;
|
||||
private javax.swing.JCheckBox deletedFilesLimitCheckbox;
|
||||
private javax.swing.JLabel deletedFilesLimitLabel;
|
||||
private javax.swing.JLabel displayTimeLabel;
|
||||
private javax.swing.JPanel globalSettingsPanel;
|
||||
private javax.swing.JCheckBox groupByDataSourceCheckbox;
|
||||
@@ -527,4 +563,4 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
|
||||
private javax.swing.JCheckBox viewsHideKnownCheckbox;
|
||||
private javax.swing.JCheckBox viewsHideSlackCheckbox;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,18 +43,23 @@ import javax.annotation.concurrent.ThreadSafe;
|
||||
@ThreadSafe
|
||||
public class History<T> {
|
||||
|
||||
// Stack of things that were previously shown before an 'advance' was done
|
||||
@GuardedBy("this")
|
||||
private final ObservableStack<T> historyStack = new ObservableStack<>();
|
||||
|
||||
// stack of things that were previously shown before a 'retreat' (i.e. a back) was done
|
||||
@GuardedBy("this")
|
||||
private final ObservableStack<T> forwardStack = new ObservableStack<>();
|
||||
|
||||
// what is currently being shown
|
||||
@GuardedBy("this")
|
||||
private final ReadOnlyObjectWrapper<T> currentState = new ReadOnlyObjectWrapper<>();
|
||||
|
||||
// Is the forward stack empty?
|
||||
@GuardedBy("this")
|
||||
private final ReadOnlyBooleanWrapper canAdvance = new ReadOnlyBooleanWrapper();
|
||||
|
||||
// is the historyStack empty?
|
||||
@GuardedBy("this")
|
||||
private final ReadOnlyBooleanWrapper canRetreat = new ReadOnlyBooleanWrapper();
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
||||
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
@@ -111,11 +112,11 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
this.skCase = skCase;
|
||||
this.datasourceObjId = dsObjId;
|
||||
}
|
||||
|
||||
|
||||
long filteringDataSourceObjId() {
|
||||
return this.datasourceObjId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||
return visitor.visit(this);
|
||||
@@ -191,9 +192,10 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
* fired. Other nodes are listening to this for changes.
|
||||
*/
|
||||
private static final class DeletedContentsChildrenObservable extends Observable {
|
||||
|
||||
private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(
|
||||
Case.Events.DATA_SOURCE_ADDED,
|
||||
Case.Events.CURRENT_CASE
|
||||
Case.Events.DATA_SOURCE_ADDED,
|
||||
Case.Events.CURRENT_CASE
|
||||
);
|
||||
|
||||
DeletedContentsChildrenObservable() {
|
||||
@@ -213,12 +215,11 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
|
||||
/**
|
||||
* + // @@@ COULD CHECK If the new file is deleted
|
||||
* before notifying... Checking for a current case is a
|
||||
* stop gap measure + update(); until a different way of
|
||||
* handling the closing of cases is worked out.
|
||||
* Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
* + // @@@ COULD CHECK If the new file is deleted before
|
||||
* notifying... Checking for a current case is a stop gap
|
||||
* measure + update(); until a different way of handling the
|
||||
* closing of cases is worked out. Currently, remote events
|
||||
* may be received for a case that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
@@ -234,10 +235,10 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
|| eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
|
||||
|| eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
|
||||
/**
|
||||
* Checking for a current case is a stop gap measure
|
||||
* until a different way of handling the closing of
|
||||
* cases is worked out. Currently, remote events may be
|
||||
* received for a case that is already closed.
|
||||
* Checking for a current case is a stop gap measure until a
|
||||
* different way of handling the closing of cases is worked
|
||||
* out. Currently, remote events may be received for a case
|
||||
* that is already closed.
|
||||
*/
|
||||
try {
|
||||
Case.getCurrentCaseThrows();
|
||||
@@ -282,7 +283,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
// Use version that has observer for updates
|
||||
@Deprecated
|
||||
DeletedContentNode(SleuthkitCase skCase, DeletedContent.DeletedContentFilter filter, long dsObjId) {
|
||||
super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId ), true), Lookups.singleton(filter.getDisplayName()));
|
||||
super(Children.create(new DeletedContentChildren(filter, skCase, null, dsObjId), true), Lookups.singleton(filter.getDisplayName()));
|
||||
this.filter = filter;
|
||||
this.datasourceObjId = dsObjId;
|
||||
init();
|
||||
@@ -366,7 +367,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
private final SleuthkitCase skCase;
|
||||
private final DeletedContent.DeletedContentFilter filter;
|
||||
private static final Logger logger = Logger.getLogger(DeletedContentChildren.class.getName());
|
||||
private static final int MAX_OBJECTS = 10001;
|
||||
|
||||
private final Observable notifier;
|
||||
private final long datasourceObjId;
|
||||
|
||||
@@ -385,7 +386,7 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
@Override
|
||||
public void update(Observable o, Object arg) {
|
||||
refresh(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -408,18 +409,19 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
+ "There are more Deleted Files than can be displayed."
|
||||
+ " Only the first {0} Deleted Files will be shown."})
|
||||
protected boolean createKeys(List<AbstractFile> list) {
|
||||
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault();
|
||||
List<AbstractFile> queryList = runFsQuery();
|
||||
if (queryList.size() == MAX_OBJECTS) {
|
||||
if (deletedPreferences.getShouldLimitDeletedFiles() && queryList.size() == deletedPreferences.getDeletedFilesLimit()) {
|
||||
queryList.remove(queryList.size() - 1);
|
||||
// only show the dialog once - not each time we refresh
|
||||
if (maxFilesDialogShown == false) {
|
||||
maxFilesDialogShown = true;
|
||||
SwingUtilities.invokeLater(()
|
||||
-> JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
DeletedContent_createKeys_maxObjects_msg(MAX_OBJECTS - 1))
|
||||
DeletedContent_createKeys_maxObjects_msg(deletedPreferences.getDeletedFilesLimit() - 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
list.addAll(queryList);
|
||||
return true;
|
||||
}
|
||||
@@ -463,10 +465,12 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
if (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)) {
|
||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||
query += " AND data_source_obj_id = " + filteringDSObjId;
|
||||
}
|
||||
DeletedFilePreferences deletedPreferences = DeletedFilePreferences.getDefault();
|
||||
if (deletedPreferences.getShouldLimitDeletedFiles()) {
|
||||
query += " LIMIT " + deletedPreferences.getDeletedFilesLimit(); //NON-NLS
|
||||
}
|
||||
|
||||
query += " LIMIT " + MAX_OBJECTS; //NON-NLS
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
@@ -476,11 +475,13 @@ public class InterestingHits implements AutopsyVisitableItem {
|
||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
||||
artifactHits.put(id, art);
|
||||
}
|
||||
list.add(id);
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "TSK Exception occurred", ex); //NON-NLS
|
||||
}
|
||||
});
|
||||
|
||||
list.addAll(artifactHits.keySet());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.openide.util.NbBundle;
|
||||
@@ -27,6 +28,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.FileSearchAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.SpecialDirectory;
|
||||
|
||||
/**
|
||||
@@ -60,7 +62,11 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode<Spec
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(new FileSearchAction(Bundle.ImageNode_getActions_openFileSearchByAttr_text()));
|
||||
actions.add(new RunIngestModulesAction(content));
|
||||
if (content.isDataSource()) {
|
||||
actions.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
|
||||
} else {
|
||||
actions.add(new RunIngestModulesAction(content));
|
||||
}
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.deletedFiles;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.CasePreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
|
||||
/**
|
||||
* Class to store settings related to the display of deleted files.
|
||||
*/
|
||||
public class DeletedFilePreferences {
|
||||
|
||||
private static final String SETTINGS_FILE = "DeletedFilePreferences.properties"; //NON-NLS
|
||||
private static final String KEY_LIMIT_DELETED_FILES = "limitDeletedFiles"; //NON-NLS
|
||||
private static final String KEY_LIMIT_VALUE = "limitValue";
|
||||
private static final String VALUE_TRUE = "true"; //NON-NLS
|
||||
private static final String VALUE_FALSE = "false"; //NON-NLS
|
||||
private static final int DEFAULT_MAX_OBJECTS = 10001;
|
||||
private static final Logger logger = Logger.getLogger(CasePreferences.class.getName());
|
||||
private static DeletedFilePreferences defaultInstance;
|
||||
private static boolean limitDeletedFiles = true;
|
||||
private static int deletedFilesLimit = DEFAULT_MAX_OBJECTS;
|
||||
|
||||
/**
|
||||
* Get the settings for the display of deleted files.
|
||||
*
|
||||
* @return defaultInstance with freshly loaded
|
||||
*/
|
||||
public static synchronized DeletedFilePreferences getDefault() {
|
||||
if (defaultInstance == null) {
|
||||
defaultInstance = new DeletedFilePreferences();
|
||||
}
|
||||
defaultInstance.loadFromStorage();
|
||||
return defaultInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private DeletedFilePreferences() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'limitDeletedFiles' value. This can be true or false. It will
|
||||
* default to true if it was not saved correctly previously.s
|
||||
*
|
||||
* @return true if the number of deleted files displayed should be limied,
|
||||
* false if it should not be limited.
|
||||
*/
|
||||
public boolean getShouldLimitDeletedFiles() {
|
||||
return limitDeletedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'limitDeletedFiles' value to true or false.
|
||||
*
|
||||
* @param value true if the number of deleted files displayed should be
|
||||
* limied, false if it should not be limited.
|
||||
*/
|
||||
public void setShouldLimitDeletedFiles(boolean value) {
|
||||
limitDeletedFiles = value;
|
||||
saveToStorage();
|
||||
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the 'limitValue' value. This is an interger value and will default to
|
||||
* DEFAULT_MAX_OBJECTS if it was not previously saved correctly.
|
||||
*
|
||||
* @return an integer representing the max number of deleted files to display.
|
||||
*/
|
||||
public int getDeletedFilesLimit() {
|
||||
return deletedFilesLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 'limitValue' for max number of deleted files to display.
|
||||
*
|
||||
* @param value an integer representing the max number of deleted files to display.
|
||||
*/
|
||||
public void setDeletedFilesLimit(int value) {
|
||||
deletedFilesLimit = value;
|
||||
saveToStorage();
|
||||
DirectoryTreeTopComponent.getDefault().refreshContentTreeSafe();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load deleted file preferences from the settings file.
|
||||
*/
|
||||
private void loadFromStorage() {
|
||||
Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS
|
||||
if (settingsFile.toFile().exists()) {
|
||||
// Read the settings
|
||||
try (InputStream inputStream = Files.newInputStream(settingsFile)) {
|
||||
Properties props = new Properties();
|
||||
props.load(inputStream);
|
||||
String limitDeletedFilesValue = props.getProperty(KEY_LIMIT_DELETED_FILES);
|
||||
if (limitDeletedFilesValue != null) {
|
||||
switch (limitDeletedFilesValue) {
|
||||
case VALUE_TRUE:
|
||||
limitDeletedFiles = true;
|
||||
break;
|
||||
case VALUE_FALSE:
|
||||
limitDeletedFiles = false;
|
||||
break;
|
||||
default:
|
||||
logger.log(Level.WARNING, String.format("Unexpected value '%s' for limit deleted files using value of true instead",
|
||||
limitDeletedFilesValue));
|
||||
limitDeletedFiles = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
String limitValue = props.getProperty(KEY_LIMIT_VALUE);
|
||||
try {
|
||||
if (limitValue != null) {
|
||||
deletedFilesLimit = Integer.valueOf(limitValue);
|
||||
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
logger.log(Level.INFO, String.format("Unexpected value '%s' for limit, expected an integer using default of 10,001 instead",
|
||||
limitValue));
|
||||
deletedFilesLimit = DEFAULT_MAX_OBJECTS;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Error reading deletedFilesPreferences file", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store deleted file preferences in the settings file.
|
||||
*/
|
||||
private void saveToStorage() {
|
||||
Path settingsFile = Paths.get(PlatformUtil.getUserConfigDirectory(), SETTINGS_FILE); //NON-NLS
|
||||
Properties props = new Properties();
|
||||
props.setProperty(KEY_LIMIT_DELETED_FILES, (limitDeletedFiles ? VALUE_TRUE : VALUE_FALSE));
|
||||
props.setProperty(KEY_LIMIT_VALUE, String.valueOf(deletedFilesLimit));
|
||||
try (OutputStream fos = Files.newOutputStream(settingsFile)) {
|
||||
props.store(fos, ""); //NON-NLS
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Error writing deletedFilesPreferences file", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,18 +140,6 @@ public class DataResultFilterNode extends FilterNode {
|
||||
this.sourceEm = em;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the inner node. If the actual underlying node is an InstanceCountNode,
|
||||
* refresh() that node, which refreshes the children.
|
||||
*
|
||||
*/
|
||||
public void refresh() {
|
||||
if (getOriginal() instanceof InstanceCountNode) {
|
||||
InstanceCountNode innerNode = getLookup().lookup(InstanceCountNode.class);
|
||||
innerNode.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a node used to wrap another node before passing it to the
|
||||
* result viewers. The wrapper node defines the actions associated with the
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
<compile-dependency/>
|
||||
<run-dependency>
|
||||
<release-version>10</release-version>
|
||||
<specification-version>10.12</specification-version>
|
||||
<specification-version>10.13</specification-version>
|
||||
</run-dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Manifest-Version: 1.0
|
||||
OpenIDE-Module: org.sleuthkit.autopsy.imagegallery/2
|
||||
OpenIDE-Module-Implementation-Version: 3
|
||||
OpenIDE-Module-Implementation-Version: 4
|
||||
OpenIDE-Module-Layer: org/sleuthkit/autopsy/imagegallery/layer.xml
|
||||
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/imagegallery/Bundle.properties
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
<compile-dependency/>
|
||||
<run-dependency>
|
||||
<release-version>10</release-version>
|
||||
<specification-version>10.12</specification-version>
|
||||
<specification-version>10.13</specification-version>
|
||||
</run-dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -136,18 +136,10 @@ public final class ImageGalleryController {
|
||||
return thumbnailSizeProp;
|
||||
}
|
||||
|
||||
public GroupViewState getViewState() {
|
||||
return historyManager.getCurrentState();
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty regroupDisabledProperty() {
|
||||
return regroupDisabled.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
public ReadOnlyObjectProperty<GroupViewState> viewStateProperty() {
|
||||
return historyManager.currentState();
|
||||
}
|
||||
|
||||
public FileIDSelectionModel getSelectionModel() {
|
||||
return selectionModel;
|
||||
}
|
||||
@@ -240,24 +232,66 @@ public final class ImageGalleryController {
|
||||
dbTaskQueueSize.addListener(obs -> this.updateRegroupDisabled());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Currently displayed group or null if nothing is being displayed
|
||||
*/
|
||||
public GroupViewState getViewState() {
|
||||
return historyManager.getCurrentState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get observable property of the current group. The UI currently changes
|
||||
* based on this property changing, which happens when other actions and
|
||||
* threads call advance().
|
||||
*
|
||||
* @return Currently displayed group (as a property that can be observed)
|
||||
*/
|
||||
public ReadOnlyObjectProperty<GroupViewState> viewStateProperty() {
|
||||
return historyManager.currentState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the "forward" button on the history be enabled?
|
||||
* @return
|
||||
*/
|
||||
public ReadOnlyBooleanProperty getCanAdvance() {
|
||||
return historyManager.getCanAdvance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the "Back" button on the history be enabled?
|
||||
* @return
|
||||
*/
|
||||
public ReadOnlyBooleanProperty getCanRetreat() {
|
||||
return historyManager.getCanRetreat();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the passed in group. Causes this group to
|
||||
* get recorded in the history queue and observers of the
|
||||
* current state will be notified and update their panels/widgets
|
||||
* appropriately.
|
||||
*
|
||||
* @param newState
|
||||
*/
|
||||
@ThreadConfined(type = ThreadConfined.ThreadType.ANY)
|
||||
public void advance(GroupViewState newState) {
|
||||
historyManager.advance(newState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the next group in the "forward" history stack
|
||||
* @return
|
||||
*/
|
||||
public GroupViewState advance() {
|
||||
return historyManager.advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the previous group in the "back" history stack
|
||||
* @return
|
||||
*/
|
||||
public GroupViewState retreat() {
|
||||
return historyManager.retreat();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.imagegallery.actions;
|
||||
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import java.util.Optional;
|
||||
import javafx.application.Platform;
|
||||
@@ -32,6 +33,7 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
|
||||
import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils;
|
||||
|
||||
/**
|
||||
* Marks the currently displayed group as "seen" and advances to the next unseen
|
||||
@@ -56,6 +58,11 @@ public class NextUnseenGroup extends Action {
|
||||
private final ImageGalleryController controller;
|
||||
private final ObservableList<DrawableGroup> unSeenGroups;
|
||||
private final GroupManager groupManager;
|
||||
|
||||
private boolean isLoading = false; // set to true when we are marking current group as seen and loading new
|
||||
|
||||
private final ListeningExecutorService exec = TaskUtils.getExecutorForClass(NextUnseenGroup.class);
|
||||
|
||||
|
||||
public NextUnseenGroup(ImageGalleryController controller) {
|
||||
super(NEXT_UNSEEN_GROUP);
|
||||
@@ -63,56 +70,98 @@ public class NextUnseenGroup extends Action {
|
||||
|
||||
this.controller = controller;
|
||||
groupManager = controller.getGroupManager();
|
||||
|
||||
// Get reference to the list of unseen groups, that GroupManager will continue to manage
|
||||
unSeenGroups = groupManager.getUnSeenGroups();
|
||||
unSeenGroups.addListener((Observable observable) -> updateButton());
|
||||
unSeenGroups.addListener((Observable observable) -> unSeenGroupListener());
|
||||
controller.viewStateProperty().addListener((Observable observable) -> updateButton());
|
||||
|
||||
setEventHandler(event -> { //on fx-thread
|
||||
//if there is a group assigned to the view, mark it as seen
|
||||
Optional.ofNullable(controller.getViewState())
|
||||
.flatMap(GroupViewState::getGroup)
|
||||
.ifPresent(group -> {
|
||||
setDisabled(true);
|
||||
groupManager.markGroupSeen(group, true)
|
||||
.addListener(this::advanceToNextUnseenGroup, MoreExecutors.newDirectExecutorService());
|
||||
});
|
||||
isLoading = true; // make sure button stays disabled until we are done loading
|
||||
setDisabled(true);
|
||||
|
||||
//if there is a group assigned to the view, mark it as seen and move on to the next one
|
||||
GroupViewState viewState = controller.getViewState();
|
||||
if (viewState != null) {
|
||||
Optional<DrawableGroup> group = viewState.getGroup();
|
||||
|
||||
if (group.isPresent()) {
|
||||
// NOTE: We need to wait for current group to be marked as seen because the 'advance'
|
||||
// method grabs the top of the unseen list
|
||||
groupManager.markGroupSeen(group.get(), true)
|
||||
.addListener(this::advanceToNextUnseenGroup, MoreExecutors.newDirectExecutorService());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, just move on to the next one
|
||||
exec.submit(this::advanceToNextUnseenGroup);
|
||||
});
|
||||
|
||||
// initial button state
|
||||
updateButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener that updates UI based on changes to the unseen group list
|
||||
*/
|
||||
private void unSeenGroupListener() {
|
||||
// set the group if there is no visible group.
|
||||
// NOTE: it could be argued that this should be done in another listner
|
||||
if (controller.getViewState() == null) {
|
||||
advanceToNextUnseenGroup();
|
||||
// do not update the button if it is supposed to be disabled during loading of the next group
|
||||
} else if (isLoading == false) {
|
||||
// NOTE: should we get a lock on groupManager here like advanceToNextUnseenGroup does?
|
||||
updateButton();
|
||||
}
|
||||
}
|
||||
|
||||
// update UI based on button being pressed
|
||||
private void advanceToNextUnseenGroup() {
|
||||
synchronized (groupManager) {
|
||||
if (CollectionUtils.isNotEmpty(unSeenGroups)) {
|
||||
controller.advance(GroupViewState.tile(unSeenGroups.get(0)));
|
||||
// NOTE: We keep the group in the unSeenGroup list until the user presses the
|
||||
// button again mark it as seen
|
||||
controller.advance(GroupViewState.createTile(unSeenGroups.get(0)));
|
||||
}
|
||||
|
||||
|
||||
updateButton();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update button based on currently displayed group and queues.
|
||||
*/
|
||||
private void updateButton() {
|
||||
int size = unSeenGroups.size();
|
||||
|
||||
if (size < 1) {
|
||||
//there are no unseen groups.
|
||||
isLoading = false;
|
||||
|
||||
int unSeenSize = unSeenGroups.size();
|
||||
|
||||
// NOTE: The currently displayed group is still in the unSeenGroups list until the user presses
|
||||
// the button again and then we'll mark it as seen.
|
||||
|
||||
// disable button if no unseen groups
|
||||
if (unSeenSize < 1) {
|
||||
Platform.runLater(() -> {
|
||||
setDisabled(true);
|
||||
setText(ALL_GROUPS_SEEN);
|
||||
setGraphic(null);
|
||||
});
|
||||
} else {
|
||||
DrawableGroup get = unSeenGroups.get(0);
|
||||
DrawableGroup orElse = Optional.ofNullable(controller.getViewState()).flatMap(GroupViewState::getGroup).orElse(null);
|
||||
boolean equals = get.equals(orElse);
|
||||
if (size == 1 & equals) {
|
||||
//The only unseen group is the one that is being viewed.
|
||||
DrawableGroup groupOnList = unSeenGroups.get(0);
|
||||
DrawableGroup groupInView = Optional.ofNullable(controller.getViewState()).flatMap(GroupViewState::getGroup).orElse(null);
|
||||
|
||||
//The only unseen group is the one that is being viewed.
|
||||
if (unSeenSize == 1 & groupOnList.equals(groupInView)) {
|
||||
Platform.runLater(() -> {
|
||||
setDisabled(false);
|
||||
setDisabled(true);
|
||||
setText(MARK_GROUP_SEEN);
|
||||
setGraphic(new ImageView(END_IMAGE));
|
||||
});
|
||||
} else {
|
||||
//there are more unseen groups.
|
||||
//there are more unseen groups after this one
|
||||
Platform.runLater(() -> {
|
||||
setDisabled(false);
|
||||
setText(NEXT_UNSEEN_GROUP);
|
||||
|
||||
@@ -110,6 +110,8 @@ public final class DrawableDB {
|
||||
|
||||
private final PreparedStatement insertHashHitStmt;
|
||||
|
||||
private final PreparedStatement removeHashHitStmt;
|
||||
|
||||
private final PreparedStatement updateDataSourceStmt;
|
||||
|
||||
private final PreparedStatement updateFileStmt;
|
||||
@@ -263,6 +265,7 @@ public final class DrawableDB {
|
||||
selectHashSetStmt = prepareStatement("SELECT hash_set_id FROM hash_sets WHERE hash_set_name = ?"); //NON-NLS
|
||||
|
||||
insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, obj_id) VALUES (?,?)"); //NON-NLS
|
||||
removeHashHitStmt = prepareStatement("DELETE FROM hash_set_hits WHERE obj_id = ?"); //NON-NLS
|
||||
|
||||
CaseDbTransaction caseDbTransaction = null;
|
||||
try {
|
||||
@@ -1408,7 +1411,7 @@ public final class DrawableDB {
|
||||
ds_obj_id, value, groupBy.attrName.toString());
|
||||
|
||||
if (DbType.POSTGRESQL == tskCase.getDatabaseType()) {
|
||||
insertSQL += "ON CONFLICT DO NOTHING";
|
||||
insertSQL += " ON CONFLICT DO NOTHING";
|
||||
}
|
||||
tskCase.getCaseDbAccessManager().insert(GROUPS_TABLENAME, insertSQL, caseDbTransaction);
|
||||
groupCache.put(cacheKey, Boolean.TRUE);
|
||||
@@ -1517,12 +1520,15 @@ public final class DrawableDB {
|
||||
// Update the list of file IDs in memory
|
||||
removeImageFileFromList(id);
|
||||
|
||||
//"delete from hash_set_hits where (obj_id = " + id + ")"
|
||||
removeHashHitStmt.setLong(1, id);
|
||||
removeHashHitStmt.executeUpdate();
|
||||
|
||||
//"delete from drawable_files where (obj_id = " + id + ")"
|
||||
removeFileStmt.setLong(1, id);
|
||||
removeFileStmt.executeUpdate();
|
||||
tr.addRemovedFile(id);
|
||||
|
||||
//TODO: delete from hash_set_hits table also...
|
||||
} catch (SQLException ex) {
|
||||
logger.log(Level.WARNING, "failed to delete row for obj_id = " + id, ex); //NON-NLS
|
||||
} finally {
|
||||
|
||||
+11
-1
@@ -99,7 +99,17 @@ public class GroupKey<T extends Comparable<T>> implements Comparable<GroupKey<T>
|
||||
if (!Objects.equals(this.attr, other.attr)) {
|
||||
return false;
|
||||
}
|
||||
return this.dataSource.getId() == other.dataSource.getId();
|
||||
// Check datasource, if available
|
||||
if (this.dataSource != null && other.dataSource != null) {
|
||||
return this.dataSource.getId() == other.dataSource.getId();
|
||||
} else if (this.dataSource == null && other.dataSource == null) {
|
||||
// neither group has a datasource
|
||||
return true;
|
||||
} else {
|
||||
// one group has a datasource, other doesn't
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -449,7 +449,7 @@ public class GroupManager {
|
||||
*
|
||||
* @param dataSource Data source to display or null to display all of them
|
||||
*/
|
||||
synchronized void setDataSource(DataSource dataSource) {
|
||||
public synchronized void setDataSource(DataSource dataSource) {
|
||||
dataSourceProp.set(dataSource);
|
||||
}
|
||||
|
||||
@@ -785,12 +785,12 @@ public class GroupManager {
|
||||
//the current group should not be visible so ...
|
||||
if (isNotEmpty(unSeenGroups)) {
|
||||
// show then next unseen group
|
||||
controller.advance(GroupViewState.tile(unSeenGroups.get(0)));
|
||||
controller.advance(GroupViewState.createTile(unSeenGroups.get(0)));
|
||||
} else if (isNotEmpty(analyzedGroups)) {
|
||||
//show the first analyzed group.
|
||||
controller.advance(GroupViewState.tile(analyzedGroups.get(0)));
|
||||
controller.advance(GroupViewState.createTile(analyzedGroups.get(0)));
|
||||
} else { //there are no groups, clear the group area.
|
||||
controller.advance(GroupViewState.tile(null));
|
||||
controller.advance(GroupViewState.createTile(null));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
+17
-13
@@ -26,12 +26,28 @@ import java.util.Optional;
|
||||
*/
|
||||
public final class GroupViewState {
|
||||
|
||||
// what group is being represented
|
||||
private final DrawableGroup group;
|
||||
|
||||
// Tile, Slide show, etc.
|
||||
private final GroupViewMode mode;
|
||||
|
||||
private final Optional<Long> slideShowfileID;
|
||||
|
||||
private GroupViewState(DrawableGroup group, GroupViewMode mode, Long slideShowfileID) {
|
||||
this.group = group;
|
||||
this.mode = mode;
|
||||
this.slideShowfileID = Optional.ofNullable(slideShowfileID);
|
||||
}
|
||||
|
||||
public static GroupViewState createTile(DrawableGroup group) {
|
||||
return new GroupViewState(group, GroupViewMode.TILE, null);
|
||||
}
|
||||
|
||||
public static GroupViewState createSlideShow(DrawableGroup group, Long fileID) {
|
||||
return new GroupViewState(group, GroupViewMode.SLIDE_SHOW, fileID);
|
||||
}
|
||||
|
||||
public Optional<DrawableGroup> getGroup() {
|
||||
return Optional.ofNullable(group);
|
||||
}
|
||||
@@ -44,19 +60,7 @@ public final class GroupViewState {
|
||||
return slideShowfileID;
|
||||
}
|
||||
|
||||
private GroupViewState(DrawableGroup group, GroupViewMode mode, Long slideShowfileID) {
|
||||
this.group = group;
|
||||
this.mode = mode;
|
||||
this.slideShowfileID = Optional.ofNullable(slideShowfileID);
|
||||
}
|
||||
|
||||
public static GroupViewState tile(DrawableGroup group) {
|
||||
return new GroupViewState(group, GroupViewMode.TILE, null);
|
||||
}
|
||||
|
||||
public static GroupViewState slideShow(DrawableGroup group, Long fileID) {
|
||||
return new GroupViewState(group, GroupViewMode.SLIDE_SHOW, fileID);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
@@ -185,6 +185,9 @@ public class Toolbar extends ToolBar {
|
||||
alert.initOwner(getScene().getWindow());
|
||||
GuiUtils.setDialogIcons(alert);
|
||||
if (alert.showAndWait().orElse(ButtonType.CANCEL) == ButtonType.OK) {
|
||||
// Set the datasource selection to 'All', before switching group
|
||||
controller.getGroupManager().setDataSource(null);
|
||||
|
||||
queryInvalidationListener.invalidated(observable);
|
||||
} else {
|
||||
Platform.runLater(() -> groupByBox.getSelectionModel().select(DrawableAttribute.PATH));
|
||||
|
||||
@@ -107,7 +107,7 @@ abstract class NavPanel<X> extends Tab {
|
||||
.addListener((observable, oldItem, newSelectedItem) -> {
|
||||
Optional.ofNullable(newSelectedItem)
|
||||
.map(getDataItemMapper())
|
||||
.ifPresent(group -> controller.advance(GroupViewState.tile(group)));
|
||||
.ifPresent(group -> controller.advance(GroupViewState.createTile(group)));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
<compile-dependency/>
|
||||
<run-dependency>
|
||||
<release-version>10</release-version>
|
||||
<specification-version>10.12</specification-version>
|
||||
<specification-version>10.13</specification-version>
|
||||
</run-dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -33,7 +33,6 @@ import java.util.LinkedList;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.SqliteUtil;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2018-2018 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.keywordsearch;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Services;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Sqlite utility class. Find and copy metafiles, write sqlite abstract files to
|
||||
* temp directory, and generate unique temp directory paths.
|
||||
*/
|
||||
final class SqliteUtil {
|
||||
|
||||
private SqliteUtil() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloaded implementation of
|
||||
* {@link #findAndCopySQLiteMetaFile(AbstractFile, String) findAndCopySQLiteMetaFile}
|
||||
* , automatically tries to copy -wal and -shm files without needing to know
|
||||
* their existence.
|
||||
*
|
||||
* @param sqliteFile file which has -wal and -shm meta files
|
||||
*
|
||||
* @throws NoCurrentCaseException Case has been closed.
|
||||
* @throws TskCoreException fileManager cannot find AbstractFile
|
||||
* files.
|
||||
* @throws IOException Issue during writing to file.
|
||||
*/
|
||||
public static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile)
|
||||
throws NoCurrentCaseException, TskCoreException, IOException {
|
||||
|
||||
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-wal");
|
||||
findAndCopySQLiteMetaFile(sqliteFile, sqliteFile.getName() + "-shm");
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for a meta file associated with the give SQLite database. If
|
||||
* found, it copies this file into the temp directory of the current case.
|
||||
*
|
||||
* @param sqliteFile file being processed
|
||||
* @param metaFileName name of meta file to look for
|
||||
*
|
||||
* @throws NoCurrentCaseException Case has been closed.
|
||||
* @throws TskCoreException fileManager cannot find AbstractFile
|
||||
* files.
|
||||
* @throws IOException Issue during writing to file.
|
||||
*/
|
||||
public static void findAndCopySQLiteMetaFile(AbstractFile sqliteFile,
|
||||
String metaFileName) throws NoCurrentCaseException, TskCoreException, IOException {
|
||||
|
||||
Case openCase = Case.getCurrentCaseThrows();
|
||||
SleuthkitCase sleuthkitCase = openCase.getSleuthkitCase();
|
||||
Services services = new Services(sleuthkitCase);
|
||||
FileManager fileManager = services.getFileManager();
|
||||
|
||||
List<AbstractFile> metaFiles = fileManager.findFiles(
|
||||
sqliteFile.getDataSource(), metaFileName,
|
||||
sqliteFile.getParent().getName());
|
||||
|
||||
if (metaFiles != null) {
|
||||
for (AbstractFile metaFile : metaFiles) {
|
||||
writeAbstractFileToLocalDisk(metaFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the file contents into a unique path in the current case temp
|
||||
* directory.
|
||||
*
|
||||
* @param file AbstractFile from the data source
|
||||
*
|
||||
* @return The path of the file on disk
|
||||
*
|
||||
* @throws IOException Exception writing file contents
|
||||
* @throws NoCurrentCaseException Current case closed during file copying
|
||||
*/
|
||||
public static String writeAbstractFileToLocalDisk(AbstractFile file)
|
||||
throws IOException, NoCurrentCaseException {
|
||||
|
||||
String localDiskPath = getUniqueTempDirectoryPath(file);
|
||||
File localDatabaseFile = new File(localDiskPath);
|
||||
if (!localDatabaseFile.exists()) {
|
||||
ContentUtils.writeToFile(file, localDatabaseFile);
|
||||
}
|
||||
return localDiskPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique local disk path that resides in the temp directory of
|
||||
* the current case.
|
||||
*
|
||||
* @param file The database abstract file
|
||||
*
|
||||
* @return Unique local disk path living in the temp directory of the case
|
||||
*
|
||||
* @throws org.sleuthkit.autopsy.casemodule.NoCurrentCaseException
|
||||
*/
|
||||
public static String getUniqueTempDirectoryPath(AbstractFile file) throws NoCurrentCaseException {
|
||||
return Case.getCurrentCaseThrows().getTempDirectory()
|
||||
+ File.separator + file.getId() + file.getName();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,39 @@
|
||||
---------------- VERSION 4.9.0 --------------
|
||||
|
||||
New Features:
|
||||
- Removed data from table that are time intensive and can be found in content viewers (such as hash set hits)
|
||||
- Added ability to find common items (files, emails, etc.) between current case and past cases using the Central Repository.
|
||||
- Added ability to ignore common items that exist in a large number of cases by using Central Repository data.
|
||||
- Data is validated and normalized before being entered into the Central Repository.
|
||||
- Allow users to specify that an ad-hoc keyword search should not be saved to database
|
||||
- New “Annotations” content viewer that shows all tags and comments associated with an item
|
||||
- Added 2 icons to the table to show the item’s score (if it is notable or suspicious) and if it has a comment.
|
||||
- Added column to the table to show previous number of occurrences.
|
||||
- Tags are now associated with the user (in a multi-user environment) and you can hide other people’s tags
|
||||
- New Display options area that unifies various new settings.
|
||||
- Hash sets can be copied into the user’s config folder (AppData), which makes it easier to run Autopsy from a Live Triage USB and not care about what drive letter it gets.
|
||||
- Image Gallery stores its groups and seen status in Case DB instead of its own.
|
||||
- Image Gallery works better in multi-user setups and reloads the database when other nodes add data sources.
|
||||
- Image Gallery saves which user saw a group and gives user option of seeing only their unseen groups or all unseen groups.
|
||||
- Saves last export location and pre-populates that in the file picker
|
||||
- Provide feedback about why some right click options are disabled (ingest is running, not file content, etc.)
|
||||
|
||||
Bug Fixes:
|
||||
- Substring keyword search is more accurate (now uses regular expression)
|
||||
- New text extractor for SQLite that better deals with full text search tables
|
||||
- Better deal with Unicode text files that do not have Byte Order Marker
|
||||
- Embedded file extractor module is now faster because it uses a different 7ZIP API.
|
||||
- Fixed various HTML report bugs
|
||||
- Duplicate hash set hits are not created when you run the Hash Ingest Module twice.
|
||||
- Auto ingest (in Experimental) scan times of input folders is faster.
|
||||
|
||||
|
||||
---------------- VERSION 4.8.0 --------------
|
||||
New Features:
|
||||
- Data Source Grouping:
|
||||
-- The case tree view can now be grouped by data source.
|
||||
-- Keyword and file search can now be restricted to a data source.
|
||||
- Central Repository / Corrrelation:
|
||||
- Central Repository / Correlation:
|
||||
-- New common files search feature that finds files that exist in multiple devices in the same case.
|
||||
-- The Other Occurrences content viewer now shows matches in the current case (in addition to central repository).
|
||||
-- Central repository options panel now shows cases that are in repo.
|
||||
@@ -31,7 +61,7 @@ New Features:
|
||||
- A graph visualization was added to the Communications tool to make it easier to find messages and relationships.
|
||||
- A new "Application" content viewer (lower right) that will contain file-type specific viewers (to reduce number of tabs).
|
||||
- New viewer for SQLite databases (in Application content viewer)
|
||||
- New viewer for binary PLists (in Appilcation content viewer)
|
||||
- New viewer for binary PLists (in Application content viewer)
|
||||
- L01 files can be imported as data sources.
|
||||
- Ingest filters can now use date range conditions for triage.
|
||||
- Passwords to open password protected archive files can be entered (by right clicking on the file).
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<compile-dependency/>
|
||||
<run-dependency>
|
||||
<release-version>10</release-version>
|
||||
<specification-version>10.12</specification-version>
|
||||
<specification-version>10.13</specification-version>
|
||||
</run-dependency>
|
||||
</dependency>
|
||||
</module-dependencies>
|
||||
|
||||
@@ -69,6 +69,7 @@ class ExtractIE extends Extract {
|
||||
private final String moduleTempResultsDir;
|
||||
private String PASCO_LIB_PATH;
|
||||
private final String JAVA_PATH;
|
||||
private static final String RESOURCE_URL_PREFIX = "res://";
|
||||
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
private Content dataSource;
|
||||
private IngestJobContext context;
|
||||
@@ -473,8 +474,8 @@ class ExtractIE extends Extract {
|
||||
|
||||
String actime = lineBuff[3];
|
||||
Long ftime = (long) 0;
|
||||
String user;
|
||||
String realurl;
|
||||
String user = null;
|
||||
String realurl = null;
|
||||
String domain;
|
||||
|
||||
/*
|
||||
@@ -494,6 +495,9 @@ class ExtractIE extends Extract {
|
||||
realurl = realurl.replace(":Host:", ""); //NON-NLS
|
||||
realurl = realurl.trim();
|
||||
} else {
|
||||
/*
|
||||
* Use the entire input for the URL.
|
||||
*/
|
||||
user = "";
|
||||
realurl = lineBuff[1].trim();
|
||||
}
|
||||
@@ -532,9 +536,12 @@ class ExtractIE extends Extract {
|
||||
"ExtractIE.parentModuleName.noSpace"),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"ExtractIE.moduleName.text")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"ExtractIE.parentModuleName.noSpace"), domain));
|
||||
|
||||
if (isIgnoredUrl(lineBuff[1]) == false) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"ExtractIE.parentModuleName.noSpace"), domain));
|
||||
}
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"ExtractIE.parentModuleName.noSpace"), user));
|
||||
@@ -562,4 +569,26 @@ class ExtractIE extends Extract {
|
||||
fileScanner.close();
|
||||
return bbartifacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the URL should be ignored.
|
||||
*
|
||||
* @param url The URL to test.
|
||||
*
|
||||
* @return True if the URL should be ignored; otherwise false.
|
||||
*/
|
||||
private boolean isIgnoredUrl(String url) {
|
||||
if (url == null || url.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.toLowerCase().startsWith(RESOURCE_URL_PREFIX)) {
|
||||
/*
|
||||
* Ignore URLs that begin with the matched text.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
class Firefox extends Extract {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Firefox.class.getName());
|
||||
private static final String PLACE_URL_PREFIX = "place:";
|
||||
private static final String HISTORY_QUERY = "SELECT moz_historyvisits.id,url,title,visit_count,(visit_date/1000000) AS visit_date,from_visit,(SELECT url FROM moz_places WHERE id=moz_historyvisits.from_visit) as ref FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id AND hidden = 0"; //NON-NLS
|
||||
private static final String COOKIE_QUERY = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed,(creationTime/1000000) AS creationTime FROM moz_cookies"; //NON-NLS
|
||||
private static final String COOKIE_QUERY_V3 = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed FROM moz_cookies"; //NON-NLS
|
||||
@@ -132,11 +133,13 @@ class Firefox extends Extract {
|
||||
List<HashMap<String, Object>> tempList = this.dbConnect(temps, HISTORY_QUERY);
|
||||
logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
String url = result.get("url").toString();
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
|
||||
((url != null) ? url : ""))); //NON-NLS
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
@@ -154,10 +157,12 @@ class Firefox extends Extract {
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"), (Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
|
||||
if (isIgnoredUrl(url) == false) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"), Util.extractDomain(url))); //NON-NLS
|
||||
|
||||
}
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
bbartifacts.add(bbart);
|
||||
@@ -226,12 +231,13 @@ class Firefox extends Extract {
|
||||
List<HashMap<String, Object>> tempList = this.dbConnect(temps, BOOKMARK_QUERY);
|
||||
logger.log(Level.INFO, "{0} - Now getting bookmarks from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
String url = result.get("url").toString();
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
|
||||
((url != null) ? url : ""))); //NON-NLS
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TITLE,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
@@ -246,10 +252,12 @@ class Firefox extends Extract {
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
(Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
|
||||
if (isIgnoredUrl(url) == false) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
Util.extractDomain(url))); //NON-NLS
|
||||
}
|
||||
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK, bookmarkFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
@@ -327,12 +335,13 @@ class Firefox extends Extract {
|
||||
List<HashMap<String, Object>> tempList = this.dbConnect(temps, query);
|
||||
logger.log(Level.INFO, "{0} - Now getting cookies from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
String host = result.get("host").toString();
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
((result.get("host").toString() != null) ? result.get("host").toString() : ""))); //NON-NLS
|
||||
((host != null) ? host : ""))); //NON-NLS
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
@@ -356,11 +365,13 @@ class Firefox extends Extract {
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
(Long.valueOf(result.get("creationTime").toString())))); //NON-NLS
|
||||
}
|
||||
String domain = Util.extractDomain(result.get("host").toString()); //NON-NLS
|
||||
domain = domain.replaceFirst("^\\.+(?!$)", "");
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"), domain));
|
||||
if (isIgnoredUrl(host) == false) {
|
||||
String domain = Util.extractDomain(host); //NON-NLS
|
||||
domain = domain.replaceFirst("^\\.+(?!$)", "");
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"), domain));
|
||||
}
|
||||
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_COOKIE, cookiesFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
@@ -442,13 +453,14 @@ class Firefox extends Extract {
|
||||
List<HashMap<String, Object>> tempList = this.dbConnect(temps, DOWNLOAD_QUERY);
|
||||
logger.log(Level.INFO, "{0}- Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
String source = result.get("source").toString();
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
((result.get("source").toString() != null) ? result.get("source").toString() : ""))); //NON-NLS
|
||||
source)); //NON-NLS
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
@@ -481,10 +493,12 @@ class Firefox extends Extract {
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
(Util.extractDomain((result.get("source").toString() != null) ? result.get("source").toString() : "")))); //NON-NLS
|
||||
if (isIgnoredUrl(source) == false) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
Util.extractDomain(source))); //NON-NLS
|
||||
}
|
||||
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
@@ -565,13 +579,14 @@ class Firefox extends Extract {
|
||||
|
||||
logger.log(Level.INFO, "{0} - Now getting downloads from {1} with {2} artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
|
||||
String url = result.get("url").toString();
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
((result.get("url").toString() != null) ? result.get("url").toString() : ""))); //NON-NLS
|
||||
url)); //NON-NLS
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
|
||||
//TODO Revisit usage of deprecated constructor as per TSK-583
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString()))));
|
||||
@@ -604,10 +619,12 @@ class Firefox extends Extract {
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.moduleName")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
(Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
|
||||
if (isIgnoredUrl(url) == false) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
"Firefox.parentModuleName.noSpace"),
|
||||
Util.extractDomain(url))); //NON-NLS
|
||||
}
|
||||
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, downloadsFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
@@ -627,4 +644,26 @@ class Firefox extends Extract {
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the URL should be ignored.
|
||||
*
|
||||
* @param url The URL to test.
|
||||
*
|
||||
* @return True if the URL should be ignored; otherwise false.
|
||||
*/
|
||||
private boolean isIgnoredUrl(String url) {
|
||||
if (url == null || url.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (url.toLowerCase().startsWith(PLACE_URL_PREFIX)) {
|
||||
/*
|
||||
* Ignore URLs that begin with the matched text.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,12 @@ class Util {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getBaseDomain(String url) {
|
||||
/**
|
||||
*
|
||||
* @param url
|
||||
* @return empty string if no domain could be found
|
||||
*/
|
||||
private static String getBaseDomain(String url) {
|
||||
String host = null;
|
||||
|
||||
//strip protocol
|
||||
@@ -113,10 +118,21 @@ class Util {
|
||||
hostB.append(".");
|
||||
}
|
||||
}
|
||||
|
||||
return hostB.toString();
|
||||
|
||||
|
||||
String base = hostB.toString();
|
||||
// verify there are no special characters in there
|
||||
if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) {
|
||||
return "";
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param value
|
||||
* @return empty string if no domain name was found
|
||||
*/
|
||||
public static String extractDomain(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Updated by build script
|
||||
#Fri, 05 Oct 2018 09:58:28 -0400
|
||||
#Sat, 13 Oct 2018 21:02:18 -0400
|
||||
LBL_splash_window_title=Starting Autopsy
|
||||
SPLASH_HEIGHT=314
|
||||
SPLASH_WIDTH=538
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#Updated by build script
|
||||
#Fri, 05 Oct 2018 09:58:28 -0400
|
||||
#Sat, 13 Oct 2018 21:02:18 -0400
|
||||
CTL_MainWindow_Title=Autopsy 4.9.0
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.9.0
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<compile-dependency/>
|
||||
<run-dependency>
|
||||
<release-version>10</release-version>
|
||||
<specification-version>10.12</specification-version>
|
||||
<specification-version>10.13</specification-version>
|
||||
</run-dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
Reference in New Issue
Block a user