mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
commit
cc83c9dedd
@ -97,6 +97,12 @@
|
|||||||
<get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
|
<get src="https://drive.google.com/uc?id=1-vmbmAAb2HBLbf58GpAA97ozGUFiYHbN" dest="${test-input}/CommonFiles_img2_v1.vhd" skipexisting="true"/>
|
||||||
<get src="https://drive.google.com/uc?id=1ghDjm0NhI3ShMQ38E-4o7XrGeexpjdJb" dest="${test-input}/CommonFiles_img3_v1.vhd" skipexisting="true"/>
|
<get src="https://drive.google.com/uc?id=1ghDjm0NhI3ShMQ38E-4o7XrGeexpjdJb" dest="${test-input}/CommonFiles_img3_v1.vhd" skipexisting="true"/>
|
||||||
<get src="https://drive.google.com/uc?id=1SJYJFjiumKEtQmeMPsQ6G3xmABarbKm_" dest="${test-input}/CommonFiles_img4_v1.vhd" skipexisting="true"/>
|
<get src="https://drive.google.com/uc?id=1SJYJFjiumKEtQmeMPsQ6G3xmABarbKm_" dest="${test-input}/CommonFiles_img4_v1.vhd" skipexisting="true"/>
|
||||||
|
<get src="https://drive.google.com/uc?id=1HwpDlMa1J7h9AmEd1JhLYGnzihslZJUj" dest="${test-input}/c1ds1_v1.vhd" skipexisting="true"/>
|
||||||
|
<get src="https://drive.google.com/uc?id=1Z7mWChlLIpIlScD-DVNGFik5A_rnwS_9" dest="${test-input}/c1ds2_v1.vhd" skipexisting="true"/>
|
||||||
|
<get src="https://drive.google.com/uc?id=14ZxYGyng_eKPe2yaiKDkJLoNcKHIHhW5" dest="${test-input}/c2ds1_v1.vhd" skipexisting="true"/>
|
||||||
|
<get src="https://drive.google.com/uc?id=1xv3Lz9m2QLq35ofDfHQNe9aHVtVzHUsj" dest="${test-input}/c2ds2_v1.vhd" skipexisting="true"/>
|
||||||
|
<get src="https://drive.google.com/uc?id=1sg-znklB9yJAWq8i1cF2W-QLOM4FjZyv" dest="${test-input}/c3ds1_v1.vhd" skipexisting="true"/>
|
||||||
|
<get src="https://drive.google.com/uc?id=1qXyaSlm3hMhv0jl6JkZEficknKjYNOlt" dest="${test-input}/c3ds2_v1.vhd" skipexisting="true"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="get-deps" depends="init-ivy,getTSKJars,get-thirdparty-dependencies,get-InternalPythonModules, download-binlist,getTestDataFiles">
|
<target name="get-deps" depends="init-ivy,getTSKJars,get-thirdparty-dependencies,get-InternalPythonModules, download-binlist,getTestDataFiles">
|
||||||
|
@ -387,6 +387,46 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
|
|
||||||
return eamCaseResult;
|
return eamCaseResult;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Retrieves Case details based on Case ID
|
||||||
|
*
|
||||||
|
* @param caseID unique identifier for a case
|
||||||
|
*
|
||||||
|
* @return The retrieved case
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CorrelationCase getCaseById(int caseId) throws EamDbException {
|
||||||
|
// @@@ We should have a cache here...
|
||||||
|
|
||||||
|
Connection conn = connect();
|
||||||
|
|
||||||
|
CorrelationCase eamCaseResult = null;
|
||||||
|
PreparedStatement preparedStatement = null;
|
||||||
|
ResultSet resultSet = null;
|
||||||
|
|
||||||
|
String sql = "SELECT cases.id as case_id, case_uid, case_name, creation_date, case_number, examiner_name, "
|
||||||
|
+ "examiner_email, examiner_phone, notes, organizations.id as org_id, org_name, poc_name, poc_email, poc_phone "
|
||||||
|
+ "FROM cases "
|
||||||
|
+ "LEFT JOIN organizations ON cases.org_id=organizations.id "
|
||||||
|
+ "WHERE cases.id=?";
|
||||||
|
|
||||||
|
try {
|
||||||
|
preparedStatement = conn.prepareStatement(sql);
|
||||||
|
preparedStatement.setInt(1, caseId);
|
||||||
|
resultSet = preparedStatement.executeQuery();
|
||||||
|
if (resultSet.next()) {
|
||||||
|
eamCaseResult = getEamCaseFromResultSet(resultSet);
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw new EamDbException("Error getting case details.", ex); // NON-NLS
|
||||||
|
} finally {
|
||||||
|
EamDbUtil.closeStatement(preparedStatement);
|
||||||
|
EamDbUtil.closeResultSet(resultSet);
|
||||||
|
EamDbUtil.closeConnection(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eamCaseResult;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves cases that are in DB.
|
* Retrieves cases that are in DB.
|
||||||
@ -502,6 +542,48 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
|
|
||||||
return eamDataSourceResult;
|
return eamDataSourceResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Data Source details based on data source ID
|
||||||
|
*
|
||||||
|
* @param correlationCase the current CorrelationCase used for ensuring
|
||||||
|
* uniqueness of DataSource
|
||||||
|
* @param dataSourceId the data source ID number
|
||||||
|
*
|
||||||
|
* @return The data source
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws EamDbException {
|
||||||
|
if (correlationCase == null) {
|
||||||
|
throw new EamDbException("Correlation case is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection conn = connect();
|
||||||
|
|
||||||
|
CorrelationDataSource eamDataSourceResult = null;
|
||||||
|
PreparedStatement preparedStatement = null;
|
||||||
|
ResultSet resultSet = null;
|
||||||
|
|
||||||
|
String sql = "SELECT * FROM data_sources WHERE id=? AND case_id=?"; // NON-NLS
|
||||||
|
|
||||||
|
try {
|
||||||
|
preparedStatement = conn.prepareStatement(sql);
|
||||||
|
preparedStatement.setInt(1, dataSourceId);
|
||||||
|
preparedStatement.setInt(2, correlationCase.getID());
|
||||||
|
resultSet = preparedStatement.executeQuery();
|
||||||
|
if (resultSet.next()) {
|
||||||
|
eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw new EamDbException("Error getting data source.", ex); // NON-NLS
|
||||||
|
} finally {
|
||||||
|
EamDbUtil.closeStatement(preparedStatement);
|
||||||
|
EamDbUtil.closeResultSet(resultSet);
|
||||||
|
EamDbUtil.closeConnection(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eamDataSourceResult;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of data sources in the DB
|
* Return a list of data sources in the DB
|
||||||
@ -670,7 +752,7 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
|
|
||||||
return artifactInstances;
|
return artifactInstances;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves eamArtifact instances from the database that are associated
|
* Retrieves eamArtifact instances from the database that are associated
|
||||||
* with the aType and filePath
|
* with the aType and filePath
|
||||||
@ -1814,6 +1896,52 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the Artifact instance in the EamDb give a where clause
|
||||||
|
*
|
||||||
|
* @param type EamArtifact.Type to search for
|
||||||
|
* @param instanceTableCallback callback to process the instance
|
||||||
|
* @param whereClause query string to execute
|
||||||
|
* @throws EamDbException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void processInstanceTableWhere(CorrelationAttribute.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws EamDbException {
|
||||||
|
if (type == null) {
|
||||||
|
throw new EamDbException("Correlation type is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instanceTableCallback == null) {
|
||||||
|
throw new EamDbException("Callback interface is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(whereClause == null) {
|
||||||
|
throw new EamDbException("Where clause is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection conn = connect();
|
||||||
|
PreparedStatement preparedStatement = null;
|
||||||
|
ResultSet resultSet = null;
|
||||||
|
String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
|
||||||
|
StringBuilder sql = new StringBuilder(300);
|
||||||
|
sql.append("select * from ")
|
||||||
|
.append(tableName)
|
||||||
|
.append(" WHERE ")
|
||||||
|
.append(whereClause);
|
||||||
|
|
||||||
|
try {
|
||||||
|
preparedStatement = conn.prepareStatement(sql.toString());
|
||||||
|
resultSet = preparedStatement.executeQuery();
|
||||||
|
instanceTableCallback.process(resultSet);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
throw new EamDbException("Error getting all artifact instances from instances table", ex);
|
||||||
|
} finally {
|
||||||
|
EamDbUtil.closeStatement(preparedStatement);
|
||||||
|
EamDbUtil.closeResultSet(resultSet);
|
||||||
|
EamDbUtil.closeConnection(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
|
public EamOrganization newOrganization(EamOrganization eamOrg) throws EamDbException {
|
||||||
if (eamOrg == null) {
|
if (eamOrg == null) {
|
||||||
|
@ -175,13 +175,21 @@ public interface EamDb {
|
|||||||
*/
|
*/
|
||||||
CorrelationCase getCaseByUUID(String caseUUID) throws EamDbException;
|
CorrelationCase getCaseByUUID(String caseUUID) throws EamDbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Case details based on Case ID
|
||||||
|
*
|
||||||
|
* @param caseID unique identifier for a case
|
||||||
|
*
|
||||||
|
* @return The retrieved case
|
||||||
|
*/
|
||||||
|
CorrelationCase getCaseById(int caseId) throws EamDbException;
|
||||||
/**
|
/**
|
||||||
* Retrieves cases that are in DB.
|
* Retrieves cases that are in DB.
|
||||||
*
|
*
|
||||||
* @return List of cases
|
* @return List of cases
|
||||||
*/
|
*/
|
||||||
List<CorrelationCase> getCases() throws EamDbException;
|
List<CorrelationCase> getCases() throws EamDbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new Data Source in the database
|
* Creates new Data Source in the database
|
||||||
*
|
*
|
||||||
@ -200,6 +208,18 @@ public interface EamDb {
|
|||||||
*/
|
*/
|
||||||
CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException;
|
CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Data Source details based on data source ID
|
||||||
|
*
|
||||||
|
* @param correlationCase the current CorrelationCase used for ensuring
|
||||||
|
* uniqueness of DataSource
|
||||||
|
* @param dataSourceId the data source ID number
|
||||||
|
*
|
||||||
|
* @return The data source
|
||||||
|
*/
|
||||||
|
CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws EamDbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves data sources that are in DB
|
* Retrieves data sources that are in DB
|
||||||
*
|
*
|
||||||
@ -225,7 +245,7 @@ public interface EamDb {
|
|||||||
* @return List of artifact instances for a given type/value
|
* @return List of artifact instances for a given type/value
|
||||||
*/
|
*/
|
||||||
List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException;
|
List<CorrelationAttributeInstance> getArtifactInstancesByTypeValue(CorrelationAttribute.Type aType, String value) throws EamDbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves eamArtifact instances from the database that are associated
|
* Retrieves eamArtifact instances from the database that are associated
|
||||||
* with the aType and filePath
|
* with the aType and filePath
|
||||||
@ -685,4 +705,15 @@ public interface EamDb {
|
|||||||
* @throws EamDbException
|
* @throws EamDbException
|
||||||
*/
|
*/
|
||||||
void processInstanceTable(CorrelationAttribute.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException;
|
void processInstanceTable(CorrelationAttribute.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the Artifact instance in the EamDb
|
||||||
|
*
|
||||||
|
* @param type EamArtifact.Type to search for
|
||||||
|
* @param instanceTableCallback callback to process the instance
|
||||||
|
* @param whereClause query string to execute
|
||||||
|
* @throws EamDbException
|
||||||
|
*/
|
||||||
|
void processInstanceTableWhere(CorrelationAttribute.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws EamDbException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an instance in either the CaseDB or CR that had a common match.
|
||||||
|
* Different implementations know how to get the instance details from either
|
||||||
|
* CaseDB or CR.
|
||||||
|
*
|
||||||
|
* Defines leaf-type nodes used in the Common Files Search results tree. Leaf
|
||||||
|
* nodes, may describe common attributes which exist in the current case DB or
|
||||||
|
* in the Central Repo. When a reference to the AbstractFile is lacking (such as
|
||||||
|
* in the case that a common attribute is found in the Central Repo) not all
|
||||||
|
* features of the Content Viewer, and context menu can be supported. Thus,
|
||||||
|
* multiple types of leaf nodes are required to represent Common Attribute
|
||||||
|
* Instance nodes.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractCommonAttributeInstance {
|
||||||
|
|
||||||
|
private final Long abstractFileObjectId;
|
||||||
|
private final String caseName;
|
||||||
|
private final String dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a leaf node for attributes found in files in the current case db.
|
||||||
|
*
|
||||||
|
* @param abstractFileReference file from which the common attribute was
|
||||||
|
* found
|
||||||
|
* @param cachedFiles storage for abstract files which have been used
|
||||||
|
* already so we can avoid extra roundtrips to the case db
|
||||||
|
* @param dataSource datasource where this attribute appears
|
||||||
|
* @param caseName case where this attribute appears
|
||||||
|
*/
|
||||||
|
AbstractCommonAttributeInstance(Long abstractFileReference, String dataSource, String caseName) {
|
||||||
|
this.abstractFileObjectId = abstractFileReference;
|
||||||
|
this.caseName = caseName;
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a leaf node for attributes found in the central repo and not
|
||||||
|
* available in the current data case.
|
||||||
|
*
|
||||||
|
* @param cachedFiles storage for abstract files which have been used
|
||||||
|
* already so we can avoid extra roundtrips to the case db
|
||||||
|
*/
|
||||||
|
AbstractCommonAttributeInstance() {
|
||||||
|
this.abstractFileObjectId = -1L;
|
||||||
|
this.caseName = "";
|
||||||
|
this.dataSource = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an AbstractFile for this instance if it can be retrieved from the
|
||||||
|
* CaseDB.
|
||||||
|
*
|
||||||
|
* @return AbstractFile corresponding to this common attribute or null if it
|
||||||
|
* cannot be found (for example, in the event that this is a central repo
|
||||||
|
* file)
|
||||||
|
*/
|
||||||
|
abstract AbstractFile getAbstractFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a list of leaf nodes, to be used to display a row in the tree
|
||||||
|
* table
|
||||||
|
*
|
||||||
|
* @return leaf nodes for tree
|
||||||
|
*/
|
||||||
|
abstract DisplayableItemNode[] generateNodes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the case where this common attribute is found.
|
||||||
|
*
|
||||||
|
* @return case name
|
||||||
|
*/
|
||||||
|
String getCaseName() {
|
||||||
|
return this.caseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get string name of the data source where this common attribute appears.
|
||||||
|
*
|
||||||
|
* @return data source name
|
||||||
|
*/
|
||||||
|
public String getDataSource() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Even though we could get this from the CR record or the AbstractFile,
|
||||||
|
* we want to avoid getting it from the AbstractFile because it would be
|
||||||
|
* an extra database roundtrip.
|
||||||
|
*/
|
||||||
|
return this.dataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ObjectId of the AbstractFile that is equivalent to the file from which
|
||||||
|
* this common attribute instance
|
||||||
|
*
|
||||||
|
* @return the abstractFileObjectId
|
||||||
|
*/
|
||||||
|
public Long getAbstractFileObjectId() {
|
||||||
|
return abstractFileObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this to create an AbstractCommonAttributeInstanceNode of the
|
||||||
|
* appropriate type. In any case, we'll get something which extends
|
||||||
|
* DisplayableItemNode which can be used to populate the tree.
|
||||||
|
*
|
||||||
|
* If the common attribute in question could be derived from an AbstractFile
|
||||||
|
* in the present SleuthkitCase, we can use an
|
||||||
|
* IntraCaseCommonAttributeInstanceNode which enables extended functionality
|
||||||
|
* in the context menu and in the content viewer.
|
||||||
|
*
|
||||||
|
* Otherwise, we will get an InterCaseCommonAttributeInstanceNode which
|
||||||
|
* supports only baseline functionality.
|
||||||
|
*
|
||||||
|
* @param attributeInstance common file attribute instance form the central
|
||||||
|
* repo
|
||||||
|
* @param abstractFile an AbstractFile from which the attribute instance was
|
||||||
|
* found - applies to CaseDbCommonAttributeInstance only
|
||||||
|
* @param currentCaseName
|
||||||
|
* @return the appropriate leaf node for the results tree
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
static DisplayableItemNode createNode(CorrelationAttribute attribute, AbstractFile abstractFile, String currentCaseName) throws TskCoreException {
|
||||||
|
|
||||||
|
DisplayableItemNode leafNode;
|
||||||
|
CorrelationAttributeInstance attributeInstance = attribute.getInstances().get(0);
|
||||||
|
|
||||||
|
if (abstractFile == null) {
|
||||||
|
leafNode = new CentralRepoCommonAttributeInstanceNode(attributeInstance);
|
||||||
|
} else {
|
||||||
|
final String abstractFileDataSourceName = abstractFile.getDataSource().getName();
|
||||||
|
leafNode = new CaseDBCommonAttributeInstanceNode(abstractFile, currentCaseName, abstractFileDataSourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return leafNode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prototype for an object which finds files with common attributes.
|
||||||
|
* Subclass this and implement findFiles in order
|
||||||
|
*/
|
||||||
|
public abstract class AbstractCommonAttributeSearcher {
|
||||||
|
|
||||||
|
private final Map<Long, String> dataSourceIdToNameMap;
|
||||||
|
private boolean filterByMedia;
|
||||||
|
private boolean filterByDoc;
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMedia, boolean filterByDoc){
|
||||||
|
this.filterByDoc = filterByDoc;
|
||||||
|
this.filterByMedia = filterByMedia;
|
||||||
|
this.dataSourceIdToNameMap = dataSourceIdMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, String> getDataSourceIdToNameMap(){
|
||||||
|
return Collections.unmodifiableMap(this.dataSourceIdToNameMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this to search for files with common attributes. Creates an
|
||||||
|
* object (CommonAttributeSearchResults) which contains all of the information
|
||||||
|
* required to display a tree view in the UI. The view will contain 3 layers:
|
||||||
|
* a top level node, indicating the number matches each of it's children possess,
|
||||||
|
* a mid level node indicating the matched attribute,
|
||||||
|
* @return
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws NoCurrentCaseException
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws EamDbException
|
||||||
|
*/
|
||||||
|
public abstract CommonAttributeSearchResults findFiles() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this to create a descriptive string for the tab which will display
|
||||||
|
* this data.
|
||||||
|
* @return an informative string
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleIntraAll=Common Files (All Data Sources, %s)",
|
||||||
|
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleIntraSingle=Common Files (Data Source: %s, %s)",
|
||||||
|
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleInterAll=Common Files (All Central Repository Cases, %s)",
|
||||||
|
"AbstractCommonFilesMetadataBuilder.buildTabTitle.titleInterSingle=Common Files (Central Repository Case: %s, %s)",
|
||||||
|
})
|
||||||
|
abstract String buildTabTitle();
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.doc=Documents",
|
||||||
|
"AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.media=Media",
|
||||||
|
"AbstractCommonFilesMetadataBuilder.buildCategorySelectionString.all=All File Categories"
|
||||||
|
})
|
||||||
|
String buildCategorySelectionString() {
|
||||||
|
if (!this.isFilterByDoc() && !this.isFilterByMedia()) {
|
||||||
|
return Bundle.AbstractCommonFilesMetadataBuilder_buildCategorySelectionString_all();
|
||||||
|
} else {
|
||||||
|
List<String> filters = new ArrayList<>();
|
||||||
|
if (this.isFilterByDoc()) {
|
||||||
|
filters.add(Bundle.AbstractCommonFilesMetadataBuilder_buildCategorySelectionString_doc());
|
||||||
|
}
|
||||||
|
if (this.isFilterByMedia()) {
|
||||||
|
filters.add(Bundle.AbstractCommonFilesMetadataBuilder_buildCategorySelectionString_media());
|
||||||
|
}
|
||||||
|
return String.join(", ", filters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<Integer, List<CommonAttributeValue>> collateMatchesByNumberOfInstances(Map<String, CommonAttributeValue> commonFiles) {
|
||||||
|
//collate matches by number of matching instances - doing this in sql doesnt seem efficient
|
||||||
|
Map<Integer, List<CommonAttributeValue>> instanceCollatedCommonFiles = new TreeMap<>();
|
||||||
|
for(CommonAttributeValue md5Metadata : commonFiles.values()){
|
||||||
|
Integer size = md5Metadata.getInstanceCount();
|
||||||
|
|
||||||
|
if(instanceCollatedCommonFiles.containsKey(size)){
|
||||||
|
instanceCollatedCommonFiles.get(size).add(md5Metadata);
|
||||||
|
} else {
|
||||||
|
ArrayList<CommonAttributeValue> value = new ArrayList<>();
|
||||||
|
value.add(md5Metadata);
|
||||||
|
instanceCollatedCommonFiles.put(size, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instanceCollatedCommonFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The set of the MIME types that will be checked for extension mismatches
|
||||||
|
* when checkType is ONLY_MEDIA.
|
||||||
|
* ".jpg", ".jpeg", ".png", ".psd", ".nef", ".tiff", ".bmp", ".tec"
|
||||||
|
* ".aaf", ".3gp", ".asf", ".avi", ".m1v", ".m2v", //NON-NLS
|
||||||
|
* ".m4v", ".mp4", ".mov", ".mpeg", ".mpg", ".mpe", ".mp4", ".rm", ".wmv", ".mpv", ".flv", ".swf"
|
||||||
|
*/
|
||||||
|
static final Set<String> MEDIA_PICS_VIDEO_MIME_TYPES = Stream.of(
|
||||||
|
"image/bmp", //NON-NLS
|
||||||
|
"image/gif", //NON-NLS
|
||||||
|
"image/jpeg", //NON-NLS
|
||||||
|
"image/png", //NON-NLS
|
||||||
|
"image/tiff", //NON-NLS
|
||||||
|
"image/vnd.adobe.photoshop", //NON-NLS
|
||||||
|
"image/x-raw-nikon", //NON-NLS
|
||||||
|
"image/x-ms-bmp", //NON-NLS
|
||||||
|
"image/x-icon", //NON-NLS
|
||||||
|
"video/webm", //NON-NLS
|
||||||
|
"video/3gpp", //NON-NLS
|
||||||
|
"video/3gpp2", //NON-NLS
|
||||||
|
"video/ogg", //NON-NLS
|
||||||
|
"video/mpeg", //NON-NLS
|
||||||
|
"video/mp4", //NON-NLS
|
||||||
|
"video/quicktime", //NON-NLS
|
||||||
|
"video/x-msvideo", //NON-NLS
|
||||||
|
"video/x-flv", //NON-NLS
|
||||||
|
"video/x-m4v", //NON-NLS
|
||||||
|
"video/x-ms-wmv", //NON-NLS
|
||||||
|
"application/vnd.ms-asf", //NON-NLS
|
||||||
|
"application/vnd.rn-realmedia", //NON-NLS
|
||||||
|
"application/x-shockwave-flash" //NON-NLS
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The set of the MIME types that will be checked for extension mismatches
|
||||||
|
* when checkType is ONLY_TEXT_FILES.
|
||||||
|
* ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx"
|
||||||
|
* ".txt", ".rtf", ".log", ".text", ".xml"
|
||||||
|
* ".html", ".htm", ".css", ".js", ".php", ".aspx"
|
||||||
|
* ".pdf"
|
||||||
|
*/
|
||||||
|
static final Set<String> TEXT_FILES_MIME_TYPES = Stream.of(
|
||||||
|
"text/plain", //NON-NLS
|
||||||
|
"application/rtf", //NON-NLS
|
||||||
|
"application/pdf", //NON-NLS
|
||||||
|
"text/css", //NON-NLS
|
||||||
|
"text/html", //NON-NLS
|
||||||
|
"text/csv", //NON-NLS
|
||||||
|
"application/json", //NON-NLS
|
||||||
|
"application/javascript", //NON-NLS
|
||||||
|
"application/xml", //NON-NLS
|
||||||
|
"text/calendar", //NON-NLS
|
||||||
|
"application/x-msoffice", //NON-NLS
|
||||||
|
"application/x-ooxml", //NON-NLS
|
||||||
|
"application/msword", //NON-NLS
|
||||||
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS
|
||||||
|
"application/vnd.ms-powerpoint", //NON-NLS
|
||||||
|
"application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS
|
||||||
|
"application/vnd.ms-excel", //NON-NLS
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS
|
||||||
|
"application/vnd.oasis.opendocument.presentation", //NON-NLS
|
||||||
|
"application/vnd.oasis.opendocument.spreadsheet", //NON-NLS
|
||||||
|
"application/vnd.oasis.opendocument.text" //NON-NLS
|
||||||
|
).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the filterByMedia
|
||||||
|
*/
|
||||||
|
boolean isFilterByMedia() {
|
||||||
|
return filterByMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param filterByMedia the filterByMedia to set
|
||||||
|
*/
|
||||||
|
void setFilterByMedia(boolean filterByMedia) {
|
||||||
|
this.filterByMedia = filterByMedia;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the filterByDoc
|
||||||
|
*/
|
||||||
|
boolean isFilterByDoc() {
|
||||||
|
return filterByDoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param filterByDoc the filterByDoc to set
|
||||||
|
*/
|
||||||
|
void setFilterByDoc(boolean filterByDoc) {
|
||||||
|
this.filterByDoc = filterByDoc;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Algorithm which finds files anywhere in the Central Repo which also occur in
|
||||||
|
* present case.
|
||||||
|
*/
|
||||||
|
public class AllInterCaseCommonAttributeSearcher extends InterCaseCommonAttributeSearcher {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param filterByMediaMimeType match only on files whose mime types can be
|
||||||
|
* broadly categorized as media types
|
||||||
|
* @param filterByDocMimeType match only on files whose mime types can be
|
||||||
|
* broadly categorized as document types
|
||||||
|
* @throws EamDbException
|
||||||
|
*/
|
||||||
|
public AllInterCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) throws EamDbException {
|
||||||
|
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommonAttributeSearchResults findFiles() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
|
||||||
|
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap());
|
||||||
|
Map<Integer, List<CommonAttributeValue>> interCaseCommonFiles = eamDbAttrInst.findInterCaseCommonAttributeValues(Case.getCurrentCase());
|
||||||
|
return new CommonAttributeSearchResults(interCaseCommonFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String buildTabTitle() {
|
||||||
|
final String buildCategorySelectionString = this.buildCategorySelectionString();
|
||||||
|
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleInterAll();
|
||||||
|
return String.format(titleTemplate, new Object[]{buildCategorySelectionString});
|
||||||
|
}
|
||||||
|
}
|
@ -25,9 +25,9 @@ import org.sleuthkit.datamodel.TskData.FileKnown;
|
|||||||
/**
|
/**
|
||||||
* Provides logic for selecting common files from all data sources.
|
* Provides logic for selecting common files from all data sources.
|
||||||
*/
|
*/
|
||||||
final public class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadataBuilder {
|
final public class AllIntraCaseCommonAttributeSearcher extends IntraCaseCommonAttributeSearcher {
|
||||||
|
|
||||||
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL)%s GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
|
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL)%s GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements the algorithm for getting common files across all data
|
* Implements the algorithm for getting common files across all data
|
||||||
@ -37,7 +37,7 @@ final public class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadat
|
|||||||
* @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types
|
* @param filterByMediaMimeType match only on files whose mime types can be broadly categorized as media types
|
||||||
* @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types
|
* @param filterByDocMimeType match only on files whose mime types can be broadly categorized as document types
|
||||||
*/
|
*/
|
||||||
public AllDataSourcesCommonFilesAlgorithm(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
|
public AllIntraCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
|
||||||
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
|
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -49,9 +49,9 @@ final public class AllDataSourcesCommonFilesAlgorithm extends CommonFilesMetadat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String buildTabTitle() {
|
String buildTabTitle() {
|
||||||
final String buildCategorySelectionString = this.buildCategorySelectionString();
|
final String buildCategorySelectionString = this.buildCategorySelectionString();
|
||||||
final String titleTemplate = Bundle.CommonFilesMetadataBuilder_buildTabTitle_titleAll();
|
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleIntraAll();
|
||||||
return String.format(titleTemplate, new Object[]{buildCategorySelectionString});
|
return String.format(titleTemplate, new Object[]{buildCategorySelectionString});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,15 +1,25 @@
|
|||||||
CommonFilesPanel.searchButton.text=Search
|
|
||||||
CommonFilesPanel.withinDataSourceRadioButton.text=At least one instance of a given MD5 must appear in the data source selected below:
|
|
||||||
CommonFilesPanel.allDataSourcesRadioButton.text=Files can be in any data source
|
|
||||||
CommonFilesPanel.cancelButton.text=Cancel
|
|
||||||
CommonFilesPanel.cancelButton.actionCommand=Cancel
|
|
||||||
CommonFilesPanel.selectedFileCategoriesButton.text=Match on the following file categories:
|
|
||||||
CommonFilesPanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
|
|
||||||
CommonFilesPanel.pictureVideoCheckbox.text=Pictures and Videos
|
|
||||||
CommonFilesPanel.documentsCheckbox.text=Documents
|
|
||||||
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find files in multiple data sources in the current case.</html>
|
CommonFilesPanel.commonFilesSearchLabel.text=<html>Find files in multiple data sources in the current case.</html>
|
||||||
CommonFilesPanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
|
|
||||||
CommonFilesPanel.allFileCategoriesRadioButton.text=Match on all file types
|
|
||||||
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:
|
CommonFilesPanel.text=Indicate which data sources to consider while searching for duplicates:
|
||||||
CommonFilesPanel.categoriesLabel.text=Indicate which file types to include in results:
|
CommonFilesPanel.jRadioButton1.text=jRadioButton1
|
||||||
CommonFilesPanel.errorText.text=In order to search, you must select a file category.
|
CommonFilesPanel.jRadioButton2.text=With previous cases in the Central Repository
|
||||||
|
CommonFilesPanel.intraCaseRadio.label=Correlate within current case only
|
||||||
|
CommonFilesPanel.interCaseRadio.label=Correlate amongst all known cases (uses Central Repo)
|
||||||
|
IntraCasePanel.allDataSourcesRadioButton.text=Matches may be from any data source
|
||||||
|
IntraCasePanel.withinDataSourceRadioButton.text=At least one match must appear in the data source selected below:
|
||||||
|
IntraCasePanel.selectDataSourceComboBox.actionCommand=
|
||||||
|
InterCasePanel.specificCentralRepoCaseRadio.text=Matches must be from the following Central Repo case:
|
||||||
|
InterCasePanel.anyCentralRepoCaseRadio.text=Matches may be from any Central Repo case
|
||||||
|
CommonAttributePanel.selectedFileCategoriesButton.toolTipText=Select from the options below...
|
||||||
|
CommonAttributePanel.selectedFileCategoriesButton.text=Only the selected file types:
|
||||||
|
CommonAttributePanel.allFileCategoriesRadioButton.toolTipText=No filtering applied to results...
|
||||||
|
CommonAttributePanel.allFileCategoriesRadioButton.text=All file types
|
||||||
|
CommonAttributePanel.cancelButton.actionCommand=Cancel
|
||||||
|
CommonAttributePanel.cancelButton.text=Cancel
|
||||||
|
CommonAttributePanel.searchButton.text=Search
|
||||||
|
CommonAttributePanel.commonFilesSearchLabel2.text=Scope of Search
|
||||||
|
CommonAttributePanel.intraCaseRadio.text=Within current case
|
||||||
|
CommonAttributePanel.commonFilesSearchLabel1.text=<html>Find common files to correlate data soures or cases.</html>
|
||||||
|
CommonAttributePanel.errorText.text=In order to search, you must select a file category.
|
||||||
|
CommonAttributePanel.categoriesLabel.text=File Types To Include:
|
||||||
|
CommonAttributePanel.documentsCheckbox.text=Documents
|
||||||
|
CommonAttributePanel.pictureVideoCheckbox.text=Pictures and Videos
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates data required to instantiate a <code>FileInstanceNode</code> for an instance in the CaseDB
|
||||||
|
*/
|
||||||
|
final public class CaseDBCommonAttributeInstance extends AbstractCommonAttributeInstance {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CaseDBCommonAttributeInstance.class.getName());
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create meta data required to find an abstract file and build a
|
||||||
|
* FileInstanceNode.
|
||||||
|
*
|
||||||
|
* @param objectId id of abstract file to find
|
||||||
|
* @param dataSourceName name of datasource where the object is found
|
||||||
|
*/
|
||||||
|
CaseDBCommonAttributeInstance(Long abstractFileReference, String dataSource, String caseName) {
|
||||||
|
super(abstractFileReference, dataSource, caseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisplayableItemNode[] generateNodes() {
|
||||||
|
final CaseDBCommonAttributeInstanceNode intraCaseCommonAttributeInstanceNode = new CaseDBCommonAttributeInstanceNode(this.getAbstractFile(), this.getCaseName(), this.getDataSource());
|
||||||
|
return Arrays.asList(intraCaseCommonAttributeInstanceNode).toArray(new DisplayableItemNode[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AbstractFile getAbstractFile() {
|
||||||
|
|
||||||
|
Case currentCase;
|
||||||
|
try {
|
||||||
|
currentCase = Case.getCurrentCaseThrows();
|
||||||
|
|
||||||
|
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
|
||||||
|
|
||||||
|
return tskDb.findAllFilesWhere(String.format("obj_id in (%s)", this.getAbstractFileObjectId())).get(0);
|
||||||
|
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Unable to find AbstractFile for record with obj_id: %s. Node not created.", new Object[]{this.getAbstractFileObjectId()}), ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,18 +20,18 @@ package org.sleuthkit.autopsy.commonfilesearch;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by the Common Files search feature to encapsulate instances of a given
|
* Node that wraps CaseDBCommonAttributeInstance to represent a file instance stored
|
||||||
MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
|
* in the CaseDB.
|
||||||
*/
|
*/
|
||||||
public class FileInstanceNode extends FileNode {
|
public class CaseDBCommonAttributeInstanceNode extends FileNode {
|
||||||
|
|
||||||
|
private final String caseName;
|
||||||
private final String dataSource;
|
private final String dataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,11 +41,10 @@ public class FileInstanceNode extends FileNode {
|
|||||||
* @param fsContent
|
* @param fsContent
|
||||||
* @param dataSource
|
* @param dataSource
|
||||||
*/
|
*/
|
||||||
public FileInstanceNode(AbstractFile fsContent, String dataSource) {
|
public CaseDBCommonAttributeInstanceNode(AbstractFile fsContent, String caseName, String dataSource) {
|
||||||
super(fsContent);
|
super(fsContent);
|
||||||
|
this.caseName = caseName;
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
|
|
||||||
this.setDisplayName(fsContent.getName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -59,11 +58,14 @@ public class FileInstanceNode extends FileNode {
|
|||||||
return visitor.visit(this);
|
return visitor.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getDataSource() {
|
public String getCase(){
|
||||||
|
return this.caseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataSource() {
|
||||||
return this.dataSource;
|
return this.dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"FileInstanceNode.createSheet.noDescription= "})
|
|
||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet sheet = new Sheet();
|
Sheet sheet = new Sheet();
|
||||||
@ -73,13 +75,14 @@ public class FileInstanceNode extends FileNode {
|
|||||||
sheet.put(sheetSet);
|
sheet.put(sheetSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String NO_DESCR = Bundle.FileInstanceNode_createSheet_noDescription();
|
final String NO_DESCR = Bundle.CommonFilesSearchResultsViewerTable_noDescText();
|
||||||
|
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsCsvList(this.getContent())));
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, getHashSetHitsCsvList(this.getContent())));
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
|
||||||
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
|
||||||
|
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), NO_DESCR, caseName));
|
||||||
|
|
||||||
this.addTagProperty(sheetSet);
|
this.addTagProperty(sheetSet);
|
||||||
|
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents that a row in the CR was found in multiple cases.
|
||||||
|
*
|
||||||
|
* Generates a DisplayableItmeNode using a CentralRepositoryFile.
|
||||||
|
*/
|
||||||
|
final public class CentralRepoCommonAttributeInstance extends AbstractCommonAttributeInstance {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CentralRepoCommonAttributeInstance.class.getName());
|
||||||
|
private final Integer crFileId;
|
||||||
|
private CorrelationAttribute currentAttribute;
|
||||||
|
private final Map<String, Long> dataSourceNameToIdMap;
|
||||||
|
|
||||||
|
CentralRepoCommonAttributeInstance(Integer attrInstId, Map<Long, String> dataSourceIdToNameMap) {
|
||||||
|
super();
|
||||||
|
this.crFileId = attrInstId;
|
||||||
|
this.dataSourceNameToIdMap = invertMap(dataSourceIdToNameMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCurrentAttributeInst(CorrelationAttribute attribute) {
|
||||||
|
this.currentAttribute = attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AbstractFile getAbstractFile() {
|
||||||
|
|
||||||
|
Case currentCase;
|
||||||
|
if (this.currentAttribute != null) {
|
||||||
|
|
||||||
|
final CorrelationAttributeInstance currentAttributeInstance = this.currentAttribute.getInstances().get(0);
|
||||||
|
|
||||||
|
String currentFullPath = currentAttributeInstance.getFilePath();
|
||||||
|
String currentDataSource = currentAttributeInstance.getCorrelationDataSource().getName();
|
||||||
|
|
||||||
|
|
||||||
|
if(this.dataSourceNameToIdMap.containsKey(currentDataSource)){
|
||||||
|
Long dataSourceObjectId = this.dataSourceNameToIdMap.get(currentDataSource);
|
||||||
|
|
||||||
|
try {
|
||||||
|
currentCase = Case.getCurrentCaseThrows();
|
||||||
|
|
||||||
|
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
|
||||||
|
|
||||||
|
File fileFromPath = new File(currentFullPath);
|
||||||
|
String fileName = fileFromPath.getName();
|
||||||
|
String parentPath = (fileFromPath.getParent() + File.separator).replace("\\", "/");
|
||||||
|
|
||||||
|
final String whereClause = String.format("lower(name) = '%s' AND md5 = '%s' AND lower(parent_path) = '%s' AND data_source_obj_id = %s", fileName, currentAttribute.getCorrelationValue(), parentPath, dataSourceObjectId);
|
||||||
|
List<AbstractFile> potentialAbstractFiles = tskDb.findAllFilesWhere(whereClause);
|
||||||
|
|
||||||
|
if(potentialAbstractFiles.isEmpty()){
|
||||||
|
return null;
|
||||||
|
} else if(potentialAbstractFiles.size() > 1){
|
||||||
|
LOGGER.log(Level.WARNING, String.format("Unable to find an exact match for AbstractFile for record with filePath: %s. May have returned the wrong file.", new Object[]{currentFullPath}));
|
||||||
|
return potentialAbstractFiles.get(0);
|
||||||
|
} else {
|
||||||
|
return potentialAbstractFiles.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Unable to find AbstractFile for record with filePath: %s. Node not created.", new Object[]{currentFullPath}), ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DisplayableItemNode[] generateNodes() {
|
||||||
|
|
||||||
|
// @@@ We should be doing more of this work in teh generateKeys method. We want to do as little as possible in generateNodes
|
||||||
|
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor();
|
||||||
|
CorrelationAttribute corrAttr = eamDbAttrInst.findSingleCorrelationAttribute(crFileId);
|
||||||
|
List<DisplayableItemNode> attrInstNodeList = new ArrayList<>(0);
|
||||||
|
String currCaseDbName = Case.getCurrentCase().getDisplayName();
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.setCurrentAttributeInst(corrAttr);
|
||||||
|
|
||||||
|
AbstractFile abstractFileForAttributeInstance = this.getAbstractFile();
|
||||||
|
DisplayableItemNode generatedInstNode = AbstractCommonAttributeInstance.createNode(corrAttr, abstractFileForAttributeInstance, currCaseDbName);
|
||||||
|
attrInstNodeList.add(generatedInstNode);
|
||||||
|
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Unable to get DataSource for record with md5: %s. Node not created.", new Object[]{corrAttr.getCorrelationValue()}), ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrInstNodeList.toArray(new DisplayableItemNode[attrInstNodeList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Long> invertMap(Map<Long, String> dataSourceIdToNameMap) {
|
||||||
|
HashMap<String, Long> invertedMap = new HashMap<>();
|
||||||
|
for (Map.Entry<Long, String> entry : dataSourceIdToNameMap.entrySet()){
|
||||||
|
invertedMap.put(entry.getValue(), entry.getKey());
|
||||||
|
}
|
||||||
|
return invertedMap;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.swing.Action;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by the Common Files search feature to encapsulate instances of a given
|
||||||
|
* MD5s matched in the search. These nodes will be children of <code>Md5Node</code>s.
|
||||||
|
*
|
||||||
|
* Use this type for files which are not in the current case, but from the
|
||||||
|
* Central Repo. Contrast with <code>SleuthkitCase</code> which should be used
|
||||||
|
* when the FileInstance was found in the case presently open in Autopsy.
|
||||||
|
*/
|
||||||
|
public class CentralRepoCommonAttributeInstanceNode extends DisplayableItemNode {
|
||||||
|
|
||||||
|
private final CorrelationAttributeInstance crFile;
|
||||||
|
|
||||||
|
CentralRepoCommonAttributeInstanceNode(CorrelationAttributeInstance content) {
|
||||||
|
super(Children.LEAF, Lookups.fixed(content));
|
||||||
|
this.crFile = content;
|
||||||
|
this.setDisplayName(new File(this.crFile.getFilePath()).getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CorrelationAttributeInstance getCorrelationAttributeInstance(){
|
||||||
|
return this.crFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action[] getActions(boolean context){
|
||||||
|
List<Action> actionsList = new ArrayList<>();
|
||||||
|
|
||||||
|
actionsList.addAll(Arrays.asList(super.getActions(true)));
|
||||||
|
|
||||||
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getItemType() {
|
||||||
|
//objects of type FileNode will co-occur in the treetable with objects
|
||||||
|
// of this type and they will need to provide the same key
|
||||||
|
return CaseDBCommonAttributeInstanceNode.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet(){
|
||||||
|
Sheet sheet = new Sheet();
|
||||||
|
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
||||||
|
|
||||||
|
if(sheetSet == null){
|
||||||
|
sheetSet = Sheet.createPropertiesSet();
|
||||||
|
sheet.put(sheetSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
final CorrelationAttributeInstance centralRepoFile = this.getCorrelationAttributeInstance();
|
||||||
|
|
||||||
|
final String fullPath = centralRepoFile.getFilePath();
|
||||||
|
final File file = new File(fullPath);
|
||||||
|
|
||||||
|
final String caseName = centralRepoFile.getCorrelationCase().getDisplayName();
|
||||||
|
|
||||||
|
final String name = file.getName();
|
||||||
|
final String parent = file.getParent();
|
||||||
|
|
||||||
|
final String dataSourceName = centralRepoFile.getCorrelationDataSource().getName();
|
||||||
|
|
||||||
|
final String NO_DESCR = Bundle.CommonFilesSearchResultsViewerTable_noDescText();
|
||||||
|
|
||||||
|
sheetSet.put(new NodeProperty<>(org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, name));
|
||||||
|
sheetSet.put(new NodeProperty<>(org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, parent));
|
||||||
|
sheetSet.put(new NodeProperty<>(org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), NO_DESCR, ""));
|
||||||
|
sheetSet.put(new NodeProperty<>(org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, dataSourceName));
|
||||||
|
sheetSet.put(new NodeProperty<>(org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, ""));
|
||||||
|
sheetSet.put(new NodeProperty<>(org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), org.sleuthkit.autopsy.commonfilesearch.Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), NO_DESCR, caseName));
|
||||||
|
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,301 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
|
||||||
|
<NonVisualComponents>
|
||||||
|
<Component class="javax.swing.ButtonGroup" name="fileTypeFilterButtonGroup">
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.ButtonGroup" name="interIntraButtonGroup">
|
||||||
|
</Component>
|
||||||
|
</NonVisualComponents>
|
||||||
|
<Properties>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[412, 350]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="resizable" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
<SyntheticProperties>
|
||||||
|
<SyntheticProperty name="formSizePolicy" type="int" value="2"/>
|
||||||
|
</SyntheticProperties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="windowClosed" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosed"/>
|
||||||
|
</Events>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,123,0,0,1,-57"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Container class="javax.swing.JPanel" name="jPanel1">
|
||||||
|
<Properties>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[412, 350]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
|
<BorderConstraints direction="Center"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="errorText" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="commonFilesSearchLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="intraCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="interCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="commonFilesSearchLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="categoriesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="selectedFileCategoriesButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="-2" pref="35" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="allFileCategoriesRadioButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="-2" pref="20" max="-2" attributes="0"/>
|
||||||
|
<Component id="layoutPanel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="commonFilesSearchLabel1" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="commonFilesSearchLabel2" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="intraCaseRadio" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="interCaseRadio" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="-2" pref="79" max="-2" attributes="0"/>
|
||||||
|
<Component id="categoriesLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="selectedFileCategoriesButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="allFileCategoriesRadioButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="searchButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="errorText" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="1" attributes="0">
|
||||||
|
<EmptySpace min="-2" pref="98" max="-2" attributes="0"/>
|
||||||
|
<Component id="layoutPanel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="-2" pref="180" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JLabel" name="commonFilesSearchLabel2">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.commonFilesSearchLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="searchButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.searchButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
|
<Property name="horizontalTextPosition" type="int" value="10"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="cancelButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.cancelButton.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="horizontalTextPosition" type="int" value="10"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="allFileCategoriesRadioButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="fileTypeFilterButtonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.allFileCategoriesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.allFileCategoriesRadioButton.toolTipText" 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="allFileCategoriesRadioButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="selectedFileCategoriesButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="fileTypeFilterButtonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.selectedFileCategoriesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.selectedFileCategoriesButton.toolTipText" 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="selectedFileCategoriesButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JCheckBox" name="pictureVideoCheckbox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.pictureVideoCheckbox.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="pictureVideoCheckboxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JCheckBox" name="documentsCheckbox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.documentsCheckbox.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="documentsCheckboxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="categoriesLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.categoriesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="errorText">
|
||||||
|
<Properties>
|
||||||
|
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||||
|
<Color blue="0" green="0" red="ff" type="rgb"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.errorText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="commonFilesSearchLabel1">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.commonFilesSearchLabel1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="intraCaseRadio">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="interIntraButtonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonAttributePanel.intraCaseRadio.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="intraCaseRadioActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="interCaseRadio">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="interIntraButtonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.jRadioButton2.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="interCaseRadioActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Container class="java.awt.Panel" name="layoutPanel">
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignCardLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel" name="intraCasePanel">
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||||
|
<CardConstraints cardName="card3"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="org.sleuthkit.autopsy.commonfilesearch.InterCasePanel" name="interCasePanel">
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignCardLayout" value="org.netbeans.modules.form.compat2.layouts.DesignCardLayout$CardConstraintsDescription">
|
||||||
|
<CardConstraints cardName="card2"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -0,0 +1,720 @@
|
|||||||
|
/*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
|
import org.openide.explorer.ExplorerManager;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Panel used for common files search configuration and configuration business
|
||||||
|
* logic. Nested within CommonFilesDialog.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
|
public final class CommonAttributePanel extends javax.swing.JDialog {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private static final Long NO_DATA_SOURCE_SELECTED = -1L;
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CommonAttributePanel.class.getName());
|
||||||
|
private boolean pictureViewCheckboxState;
|
||||||
|
private boolean documentsCheckboxState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form CommonFilesPanel
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"CommonFilesPanel.title=Common Files Panel",
|
||||||
|
"CommonFilesPanel.exception=Unexpected Exception loading DataSources.",
|
||||||
|
"CommonFilesPanel.frame.title=Find Common Files",
|
||||||
|
"CommonFilesPanel.frame.msg=Find Common Files"})
|
||||||
|
public CommonAttributePanel() {
|
||||||
|
super(new JFrame(Bundle.CommonFilesPanel_frame_title()),
|
||||||
|
Bundle.CommonFilesPanel_frame_msg(), true);
|
||||||
|
initComponents();
|
||||||
|
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||||
|
this.errorText.setVisible(false);
|
||||||
|
this.setupDataSources();
|
||||||
|
|
||||||
|
if (CommonAttributePanel.isEamDbAvailable()) {
|
||||||
|
this.setupCases();
|
||||||
|
} else {
|
||||||
|
this.disableIntercaseSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isEamDbAvailable() {
|
||||||
|
try {
|
||||||
|
return EamDb.isEnabled() &&
|
||||||
|
EamDb.getInstance() != null &&
|
||||||
|
EamDb.getInstance().getCases().size() > 1 &&
|
||||||
|
Case.isCaseOpen() &&
|
||||||
|
Case.getCurrentCase() != null &&
|
||||||
|
EamDb.getInstance().getCase(Case.getCurrentCase()) != null;
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception while checking for EamDB enabled.", ex);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableIntercaseSearch() {
|
||||||
|
this.intraCaseRadio.setSelected(true);
|
||||||
|
this.interCaseRadio.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"CommonFilesPanel.search.results.titleAll=Common Files (All Data Sources)",
|
||||||
|
"CommonFilesPanel.search.results.titleSingle=Common Files (Match Within Data Source: %s)",
|
||||||
|
"CommonFilesPanel.search.results.pathText=Common Files Search Results",
|
||||||
|
"CommonFilesPanel.search.done.searchProgressGathering=Gathering Common Files Search Results.",
|
||||||
|
"CommonFilesPanel.search.done.searchProgressDisplay=Displaying Common Files Search Results.",
|
||||||
|
"CommonFilesPanel.search.done.tskCoreException=Unable to run query against DB.",
|
||||||
|
"CommonFilesPanel.search.done.noCurrentCaseException=Unable to open case file.",
|
||||||
|
"CommonFilesPanel.search.done.exception=Unexpected exception running Common Files Search.",
|
||||||
|
"CommonFilesPanel.search.done.interupted=Something went wrong finding common files.",
|
||||||
|
"CommonFilesPanel.search.done.sqlException=Unable to query db for files or data sources."})
|
||||||
|
private void search() {
|
||||||
|
String pathText = Bundle.CommonFilesPanel_search_results_pathText();
|
||||||
|
|
||||||
|
new SwingWorker<CommonAttributeSearchResults, Void>() {
|
||||||
|
|
||||||
|
private String tabTitle;
|
||||||
|
private ProgressHandle progress;
|
||||||
|
|
||||||
|
private void setTitleForAllDataSources() {
|
||||||
|
this.tabTitle = Bundle.CommonFilesPanel_search_results_titleAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTitleForSingleSource(Long dataSourceId) {
|
||||||
|
final String CommonFilesPanel_search_results_titleSingle = Bundle.CommonFilesPanel_search_results_titleSingle();
|
||||||
|
final Object[] dataSourceName = new Object[]{intraCasePanel.getDataSourceMap().get(dataSourceId)};
|
||||||
|
|
||||||
|
this.tabTitle = String.format(CommonFilesPanel_search_results_titleSingle, dataSourceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings({"BoxedValueEquality", "NumberEquality"})
|
||||||
|
protected CommonAttributeSearchResults doInBackground() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
|
||||||
|
progress = ProgressHandle.createHandle(Bundle.CommonFilesPanel_search_done_searchProgressGathering());
|
||||||
|
progress.start();
|
||||||
|
progress.switchToIndeterminate();
|
||||||
|
|
||||||
|
Long dataSourceId = intraCasePanel.getSelectedDataSourceId();
|
||||||
|
Integer caseId = interCasePanel.getSelectedCaseId();
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher builder;
|
||||||
|
CommonAttributeSearchResults metadata;
|
||||||
|
|
||||||
|
boolean filterByMedia = false;
|
||||||
|
boolean filterByDocuments = false;
|
||||||
|
if (selectedFileCategoriesButton.isSelected()) {
|
||||||
|
if (pictureVideoCheckbox.isSelected()) {
|
||||||
|
filterByMedia = true;
|
||||||
|
}
|
||||||
|
if (documentsCheckbox.isSelected()) {
|
||||||
|
filterByDocuments = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CommonAttributePanel.this.interCaseRadio.isSelected()) {
|
||||||
|
|
||||||
|
if (caseId == InterCasePanel.NO_CASE_SELECTED) {
|
||||||
|
builder = new AllInterCaseCommonAttributeSearcher(intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments);
|
||||||
|
} else {
|
||||||
|
builder = new SingleInterCaseCommonAttributeSearcher(caseId, intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dataSourceId == CommonAttributePanel.NO_DATA_SOURCE_SELECTED) {
|
||||||
|
builder = new AllIntraCaseCommonAttributeSearcher(intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments);
|
||||||
|
|
||||||
|
setTitleForAllDataSources();
|
||||||
|
} else {
|
||||||
|
builder = new SingleIntraCaseCommonAttributeSearcher(dataSourceId, intraCasePanel.getDataSourceMap(), filterByMedia, filterByDocuments);
|
||||||
|
|
||||||
|
setTitleForSingleSource(dataSourceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
metadata = builder.findFiles();
|
||||||
|
this.tabTitle = builder.buildTabTitle();
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
try {
|
||||||
|
super.done();
|
||||||
|
|
||||||
|
CommonAttributeSearchResults metadata = this.get();
|
||||||
|
|
||||||
|
CommonAttributeSearchResultRootNode commonFilesNode = new CommonAttributeSearchResultRootNode(metadata);
|
||||||
|
|
||||||
|
// -3969
|
||||||
|
DataResultFilterNode dataResultFilterNode = new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonAttributePanel.this));
|
||||||
|
|
||||||
|
TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode, 3);
|
||||||
|
|
||||||
|
DataResultViewerTable table = new CommonAttributesSearchResultsViewerTable();
|
||||||
|
|
||||||
|
Collection<DataResultViewer> viewers = new ArrayList<>(1);
|
||||||
|
viewers.add(table);
|
||||||
|
|
||||||
|
progress.setDisplayName(Bundle.CommonFilesPanel_search_done_searchProgressDisplay());
|
||||||
|
DataResultTopComponent.createInstance(tabTitle, pathText, tableFilterWithDescendantsNode, metadata.size(), viewers);
|
||||||
|
progress.finish();
|
||||||
|
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Interrupted while loading Common Files", ex);
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_search_done_interupted());
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
String errorMessage;
|
||||||
|
Throwable inner = ex.getCause();
|
||||||
|
if (inner instanceof TskCoreException) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to load files from database.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_search_done_tskCoreException();
|
||||||
|
} else if (inner instanceof NoCurrentCaseException) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Current case has been closed.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_search_done_noCurrentCaseException();
|
||||||
|
} else if (inner instanceof SQLException) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to query db for files.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_search_done_sqlException();
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception while running Common Files Search.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_search_done_exception();
|
||||||
|
}
|
||||||
|
MessageNotifyUtil.Message.error(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the data sources dropdown and returns the data sources map for
|
||||||
|
* future usage.
|
||||||
|
*
|
||||||
|
* @return a mapping of data correlationCase ids to data correlationCase
|
||||||
|
* names
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"CommonFilesPanel.setupDataSources.done.tskCoreException=Unable to run query against DB.",
|
||||||
|
"CommonFilesPanel.setupDataSources.done.noCurrentCaseException=Unable to open case file.",
|
||||||
|
"CommonFilesPanel.setupDataSources.done.exception=Unexpected exception loading data sources.",
|
||||||
|
"CommonFilesPanel.setupDataSources.done.interupted=Something went wrong building the Common Files Search dialog box.",
|
||||||
|
"CommonFilesPanel.setupDataSources.done.sqlException=Unable to query db for data sources.",
|
||||||
|
"CommonFilesPanel.setupDataSources.updateUi.noDataSources=No data sources were found."})
|
||||||
|
private void setupDataSources() {
|
||||||
|
|
||||||
|
new SwingWorker<Map<Long, String>, Void>() {
|
||||||
|
|
||||||
|
private void updateUi() {
|
||||||
|
|
||||||
|
final Map<Long, String> dataSourceMap = CommonAttributePanel.this.intraCasePanel.getDataSourceMap();
|
||||||
|
|
||||||
|
String[] dataSourcesNames = new String[dataSourceMap.size()];
|
||||||
|
|
||||||
|
//only enable all this stuff if we actually have datasources
|
||||||
|
if (dataSourcesNames.length > 0) {
|
||||||
|
dataSourcesNames = dataSourceMap.values().toArray(dataSourcesNames);
|
||||||
|
CommonAttributePanel.this.intraCasePanel.setDataModel(new DataSourceComboBoxModel(dataSourcesNames));
|
||||||
|
|
||||||
|
boolean multipleDataSources = this.caseHasMultipleSources();
|
||||||
|
CommonAttributePanel.this.intraCasePanel.rigForMultipleDataSources(multipleDataSources);
|
||||||
|
|
||||||
|
//TODO this should be attached to the intra/inter radio buttons
|
||||||
|
CommonAttributePanel.this.setSearchButtonEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean caseHasMultipleSources() {
|
||||||
|
return CommonAttributePanel.this.intraCasePanel.getDataSourceMap().size() > 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<Long, String> doInBackground() throws NoCurrentCaseException, TskCoreException, SQLException {
|
||||||
|
DataSourceLoader loader = new DataSourceLoader();
|
||||||
|
return loader.getDataSourceMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
CommonAttributePanel.this.intraCasePanel.setDataSourceMap(this.get());
|
||||||
|
updateUi();
|
||||||
|
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Interrupted while building Common Files Search dialog.", ex);
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_setupDataSources_done_interupted());
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
String errorMessage;
|
||||||
|
Throwable inner = ex.getCause();
|
||||||
|
if (inner instanceof TskCoreException) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Failed to load data sources from database.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_setupDataSources_done_tskCoreException();
|
||||||
|
} else if (inner instanceof NoCurrentCaseException) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Current case has been closed.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_setupDataSources_done_noCurrentCaseException();
|
||||||
|
} else if (inner instanceof SQLException) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unable to query db for data sources.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_setupDataSources_done_sqlException();
|
||||||
|
} else {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception while building Common Files Search dialog panel.", ex);
|
||||||
|
errorMessage = Bundle.CommonFilesPanel_setupDataSources_done_exception();
|
||||||
|
}
|
||||||
|
MessageNotifyUtil.Message.error(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"CommonFilesPanel.setupCases.done.interruptedException=Something went wrong building the Common Files Search dialog box.",
|
||||||
|
"CommonFilesPanel.setupCases.done.exeutionException=Unexpected exception loading cases."})
|
||||||
|
private void setupCases() {
|
||||||
|
|
||||||
|
new SwingWorker<Map<Integer, String>, Void>() {
|
||||||
|
|
||||||
|
private void updateUi() {
|
||||||
|
|
||||||
|
final Map<Integer, String> caseMap = CommonAttributePanel.this.interCasePanel.getCaseMap();
|
||||||
|
|
||||||
|
String[] caseNames = new String[caseMap.size()];
|
||||||
|
|
||||||
|
if (caseNames.length > 0) {
|
||||||
|
caseNames = caseMap.values().toArray(caseNames);
|
||||||
|
CommonAttributePanel.this.interCasePanel.setCaseList(new DataSourceComboBoxModel(caseNames));
|
||||||
|
|
||||||
|
boolean multipleCases = this.centralRepoHasMultipleCases();
|
||||||
|
CommonAttributePanel.this.interCasePanel.rigForMultipleCases(multipleCases);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
CommonAttributePanel.this.disableIntercaseSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Integer, String> mapDataSources(List<CorrelationCase> cases) throws EamDbException {
|
||||||
|
Map<Integer, String> casemap = new HashMap<>();
|
||||||
|
CorrelationCase currentCorCase = EamDb.getInstance().getCase(Case.getCurrentCase());
|
||||||
|
for (CorrelationCase correlationCase : cases) {
|
||||||
|
if (currentCorCase.getID() != correlationCase.getID()) { // if not the current Case
|
||||||
|
casemap.put(correlationCase.getID(), correlationCase.getDisplayName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return casemap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Map<Integer, String> doInBackground() throws EamDbException {
|
||||||
|
|
||||||
|
List<CorrelationCase> dataSources = EamDb.getInstance().getCases();
|
||||||
|
Map<Integer, String> caseMap = mapDataSources(dataSources);
|
||||||
|
|
||||||
|
return caseMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
try {
|
||||||
|
Map<Integer, String> cases = this.get();
|
||||||
|
CommonAttributePanel.this.interCasePanel.setCaseMap(cases);
|
||||||
|
this.updateUi();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Interrupted while building Common Files Search dialog.", ex);
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_setupCases_done_interruptedException());
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception while building Common Files Search dialog.", ex);
|
||||||
|
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_setupCases_done_exeutionException());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean centralRepoHasMultipleCases() {
|
||||||
|
return CommonAttributePanel.this.interCasePanel.centralRepoHasMultipleCases();
|
||||||
|
}
|
||||||
|
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
fileTypeFilterButtonGroup = new javax.swing.ButtonGroup();
|
||||||
|
interIntraButtonGroup = new javax.swing.ButtonGroup();
|
||||||
|
jPanel1 = new javax.swing.JPanel();
|
||||||
|
commonFilesSearchLabel2 = new javax.swing.JLabel();
|
||||||
|
searchButton = new javax.swing.JButton();
|
||||||
|
cancelButton = new javax.swing.JButton();
|
||||||
|
allFileCategoriesRadioButton = new javax.swing.JRadioButton();
|
||||||
|
selectedFileCategoriesButton = new javax.swing.JRadioButton();
|
||||||
|
pictureVideoCheckbox = new javax.swing.JCheckBox();
|
||||||
|
documentsCheckbox = new javax.swing.JCheckBox();
|
||||||
|
categoriesLabel = new javax.swing.JLabel();
|
||||||
|
errorText = new javax.swing.JLabel();
|
||||||
|
commonFilesSearchLabel1 = new javax.swing.JLabel();
|
||||||
|
intraCaseRadio = new javax.swing.JRadioButton();
|
||||||
|
interCaseRadio = new javax.swing.JRadioButton();
|
||||||
|
layoutPanel = new java.awt.Panel();
|
||||||
|
intraCasePanel = new org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel();
|
||||||
|
interCasePanel = new org.sleuthkit.autopsy.commonfilesearch.InterCasePanel();
|
||||||
|
|
||||||
|
setMinimumSize(new java.awt.Dimension(412, 350));
|
||||||
|
setPreferredSize(new java.awt.Dimension(412, 350));
|
||||||
|
setResizable(false);
|
||||||
|
addWindowListener(new java.awt.event.WindowAdapter() {
|
||||||
|
public void windowClosed(java.awt.event.WindowEvent evt) {
|
||||||
|
formWindowClosed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
jPanel1.setPreferredSize(new java.awt.Dimension(412, 350));
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel2, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.commonFilesSearchLabel2.text")); // NOI18N
|
||||||
|
commonFilesSearchLabel2.setFocusable(false);
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.searchButton.text")); // NOI18N
|
||||||
|
searchButton.setEnabled(false);
|
||||||
|
searchButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
||||||
|
searchButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
searchButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.cancelButton.text")); // NOI18N
|
||||||
|
cancelButton.setActionCommand(org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.cancelButton.actionCommand")); // NOI18N
|
||||||
|
cancelButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
||||||
|
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
cancelButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fileTypeFilterButtonGroup.add(allFileCategoriesRadioButton);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(allFileCategoriesRadioButton, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.allFileCategoriesRadioButton.text")); // NOI18N
|
||||||
|
allFileCategoriesRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.allFileCategoriesRadioButton.toolTipText")); // NOI18N
|
||||||
|
allFileCategoriesRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
allFileCategoriesRadioButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fileTypeFilterButtonGroup.add(selectedFileCategoriesButton);
|
||||||
|
selectedFileCategoriesButton.setSelected(true);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(selectedFileCategoriesButton, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.selectedFileCategoriesButton.text")); // NOI18N
|
||||||
|
selectedFileCategoriesButton.setToolTipText(org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.selectedFileCategoriesButton.toolTipText")); // NOI18N
|
||||||
|
selectedFileCategoriesButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
selectedFileCategoriesButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pictureVideoCheckbox.setSelected(true);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(pictureVideoCheckbox, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.pictureVideoCheckbox.text")); // NOI18N
|
||||||
|
pictureVideoCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
pictureVideoCheckboxActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
documentsCheckbox.setSelected(true);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(documentsCheckbox, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.documentsCheckbox.text")); // NOI18N
|
||||||
|
documentsCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
documentsCheckboxActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(categoriesLabel, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.categoriesLabel.text")); // NOI18N
|
||||||
|
categoriesLabel.setName(""); // NOI18N
|
||||||
|
|
||||||
|
errorText.setForeground(new java.awt.Color(255, 0, 0));
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(errorText, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.errorText.text")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel1, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.commonFilesSearchLabel1.text")); // NOI18N
|
||||||
|
commonFilesSearchLabel1.setFocusable(false);
|
||||||
|
|
||||||
|
interIntraButtonGroup.add(intraCaseRadio);
|
||||||
|
intraCaseRadio.setSelected(true);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(intraCaseRadio, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonAttributePanel.intraCaseRadio.text")); // NOI18N
|
||||||
|
intraCaseRadio.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
intraCaseRadioActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
interIntraButtonGroup.add(interCaseRadio);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(interCaseRadio, org.openide.util.NbBundle.getMessage(CommonAttributePanel.class, "CommonFilesPanel.jRadioButton2.text")); // NOI18N
|
||||||
|
interCaseRadio.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
interCaseRadioActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
layoutPanel.setLayout(new java.awt.CardLayout());
|
||||||
|
layoutPanel.add(intraCasePanel, "card3");
|
||||||
|
layoutPanel.add(interCasePanel, "card2");
|
||||||
|
|
||||||
|
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||||
|
jPanel1.setLayout(jPanel1Layout);
|
||||||
|
jPanel1Layout.setHorizontalGroup(
|
||||||
|
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(searchButton)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(cancelButton)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(errorText))
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(commonFilesSearchLabel2)
|
||||||
|
.addComponent(intraCaseRadio)
|
||||||
|
.addComponent(interCaseRadio)
|
||||||
|
.addComponent(commonFilesSearchLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addComponent(categoriesLabel)
|
||||||
|
.addComponent(selectedFileCategoriesButton)))
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addGap(35, 35, 35)
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(documentsCheckbox)
|
||||||
|
.addComponent(pictureVideoCheckbox)))
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(allFileCategoriesRadioButton)))
|
||||||
|
.addContainerGap())
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addGap(20, 20, 20)
|
||||||
|
.addComponent(layoutPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGap(10, 10, 10)))
|
||||||
|
);
|
||||||
|
jPanel1Layout.setVerticalGroup(
|
||||||
|
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addComponent(commonFilesSearchLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(commonFilesSearchLabel2)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(intraCaseRadio)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(interCaseRadio)
|
||||||
|
.addGap(79, 79, 79)
|
||||||
|
.addComponent(categoriesLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(selectedFileCategoriesButton)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(pictureVideoCheckbox)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(documentsCheckbox)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(allFileCategoriesRadioButton)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(searchButton)
|
||||||
|
.addComponent(cancelButton)
|
||||||
|
.addComponent(errorText))
|
||||||
|
.addContainerGap())
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
|
||||||
|
.addGap(98, 98, 98)
|
||||||
|
.addComponent(layoutPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addGap(180, 180, 180)))
|
||||||
|
);
|
||||||
|
|
||||||
|
getContentPane().add(jPanel1, java.awt.BorderLayout.CENTER);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
|
||||||
|
search();
|
||||||
|
SwingUtilities.windowForComponent(this).dispose();
|
||||||
|
}//GEN-LAST:event_searchButtonActionPerformed
|
||||||
|
|
||||||
|
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||||
|
SwingUtilities.windowForComponent(this).dispose();
|
||||||
|
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||||
|
|
||||||
|
private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed
|
||||||
|
this.manageCheckBoxState();
|
||||||
|
this.toggleErrorTextAndSearchBox();
|
||||||
|
}//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed
|
||||||
|
|
||||||
|
private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed
|
||||||
|
this.manageCheckBoxState();
|
||||||
|
}//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed
|
||||||
|
|
||||||
|
private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed
|
||||||
|
this.toggleErrorTextAndSearchBox();
|
||||||
|
}//GEN-LAST:event_pictureVideoCheckboxActionPerformed
|
||||||
|
|
||||||
|
private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed
|
||||||
|
this.toggleErrorTextAndSearchBox();
|
||||||
|
}//GEN-LAST:event_documentsCheckboxActionPerformed
|
||||||
|
|
||||||
|
private void intraCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_intraCaseRadioActionPerformed
|
||||||
|
((java.awt.CardLayout) this.layoutPanel.getLayout()).first(this.layoutPanel);
|
||||||
|
handleIntraCaseSearchCriteriaChanged();
|
||||||
|
}//GEN-LAST:event_intraCaseRadioActionPerformed
|
||||||
|
|
||||||
|
public void handleIntraCaseSearchCriteriaChanged() {
|
||||||
|
if (this.areIntraCaseSearchCriteriaMet()) {
|
||||||
|
this.searchButton.setEnabled(true);
|
||||||
|
this.hideErrorMessages();
|
||||||
|
} else {
|
||||||
|
this.searchButton.setEnabled(false);
|
||||||
|
this.hideErrorMessages();
|
||||||
|
this.showIntraCaseErrorMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void interCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interCaseRadioActionPerformed
|
||||||
|
((java.awt.CardLayout) this.layoutPanel.getLayout()).last(this.layoutPanel);
|
||||||
|
handleInterCaseSearchCriteriaChanged();
|
||||||
|
}//GEN-LAST:event_interCaseRadioActionPerformed
|
||||||
|
|
||||||
|
private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
|
||||||
|
SwingUtilities.windowForComponent(this).dispose();
|
||||||
|
}//GEN-LAST:event_formWindowClosed
|
||||||
|
|
||||||
|
public void handleInterCaseSearchCriteriaChanged() {
|
||||||
|
if (this.areInterCaseSearchCriteriaMet()) {
|
||||||
|
this.searchButton.setEnabled(true);
|
||||||
|
this.hideErrorMessages();
|
||||||
|
} else {
|
||||||
|
this.searchButton.setEnabled(false);
|
||||||
|
this.hideErrorMessages();
|
||||||
|
this.showInterCaseErrorMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void toggleErrorTextAndSearchBox() {
|
||||||
|
if (!this.pictureVideoCheckbox.isSelected() && !this.documentsCheckbox.isSelected() && !this.allFileCategoriesRadioButton.isSelected()) {
|
||||||
|
this.searchButton.setEnabled(false);
|
||||||
|
this.errorText.setVisible(true);
|
||||||
|
} else {
|
||||||
|
this.searchButton.setEnabled(true);
|
||||||
|
this.errorText.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void manageCheckBoxState() {
|
||||||
|
|
||||||
|
this.pictureViewCheckboxState = this.pictureVideoCheckbox.isSelected();
|
||||||
|
this.documentsCheckboxState = this.documentsCheckbox.isSelected();
|
||||||
|
|
||||||
|
if (this.allFileCategoriesRadioButton.isSelected()) {
|
||||||
|
this.pictureVideoCheckbox.setEnabled(false);
|
||||||
|
this.documentsCheckbox.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selectedFileCategoriesButton.isSelected()) {
|
||||||
|
|
||||||
|
this.pictureVideoCheckbox.setSelected(this.pictureViewCheckboxState);
|
||||||
|
this.documentsCheckbox.setSelected(this.documentsCheckboxState);
|
||||||
|
|
||||||
|
this.pictureVideoCheckbox.setEnabled(true);
|
||||||
|
this.documentsCheckbox.setEnabled(true);
|
||||||
|
|
||||||
|
this.toggleErrorTextAndSearchBox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JRadioButton allFileCategoriesRadioButton;
|
||||||
|
private javax.swing.JButton cancelButton;
|
||||||
|
private javax.swing.JLabel categoriesLabel;
|
||||||
|
private javax.swing.JLabel commonFilesSearchLabel1;
|
||||||
|
private javax.swing.JLabel commonFilesSearchLabel2;
|
||||||
|
private javax.swing.JCheckBox documentsCheckbox;
|
||||||
|
private javax.swing.JLabel errorText;
|
||||||
|
private javax.swing.ButtonGroup fileTypeFilterButtonGroup;
|
||||||
|
private org.sleuthkit.autopsy.commonfilesearch.InterCasePanel interCasePanel;
|
||||||
|
private javax.swing.JRadioButton interCaseRadio;
|
||||||
|
private javax.swing.ButtonGroup interIntraButtonGroup;
|
||||||
|
private org.sleuthkit.autopsy.commonfilesearch.IntraCasePanel intraCasePanel;
|
||||||
|
private javax.swing.JRadioButton intraCaseRadio;
|
||||||
|
private javax.swing.JPanel jPanel1;
|
||||||
|
private java.awt.Panel layoutPanel;
|
||||||
|
private javax.swing.JCheckBox pictureVideoCheckbox;
|
||||||
|
private javax.swing.JButton searchButton;
|
||||||
|
private javax.swing.JRadioButton selectedFileCategoriesButton;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
void setSearchButtonEnabled(boolean enabled) {
|
||||||
|
this.searchButton.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areIntraCaseSearchCriteriaMet() {
|
||||||
|
return this.intraCasePanel.areSearchCriteriaMet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean areInterCaseSearchCriteriaMet() {
|
||||||
|
return this.interCasePanel.areSearchCriteriaMet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideErrorMessages() {
|
||||||
|
this.errorText.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showIntraCaseErrorMessage() {
|
||||||
|
this.errorText.setText(this.intraCasePanel.getErrorMessage());
|
||||||
|
this.errorText.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showInterCaseErrorMessage() {
|
||||||
|
this.errorText.setText(this.interCasePanel.getErrorMessage());
|
||||||
|
this.errorText.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
@ -27,13 +27,14 @@ import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
|||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper node for <code>Md5Node</code> used to display common files search
|
* Top-level node to store common file search results. Current structure is:
|
||||||
* results in the top right pane. Calls <code>InstanceCountNodeFactory</code>.
|
* - node for number of matches
|
||||||
|
* -- node for MD5/commmon attribute
|
||||||
|
* --- node for instance.
|
||||||
*/
|
*/
|
||||||
final public class CommonFilesNode extends DisplayableItemNode {
|
final public class CommonAttributeSearchResultRootNode extends DisplayableItemNode {
|
||||||
|
|
||||||
|
|
||||||
CommonFilesNode(CommonFilesMetadata metadataList) {
|
CommonAttributeSearchResultRootNode(CommonAttributeSearchResults metadataList) {
|
||||||
super(Children.create(new InstanceCountNodeFactory(metadataList), true));
|
super(Children.create(new InstanceCountNodeFactory(metadataList), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,27 +65,27 @@ final public class CommonFilesNode extends DisplayableItemNode {
|
|||||||
*/
|
*/
|
||||||
static class InstanceCountNodeFactory extends ChildFactory<Integer>{
|
static class InstanceCountNodeFactory extends ChildFactory<Integer>{
|
||||||
|
|
||||||
private final CommonFilesMetadata metadata;
|
private final CommonAttributeSearchResults searchResults;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a factory which converts a <code>CommonFilesMetadata</code>
|
* Build a factory which converts a <code>CommonAttributeSearchResults</code>
|
||||||
* object into <code>DisplayableItemNode</code>s.
|
* object into <code>DisplayableItemNode</code>s.
|
||||||
* @param metadata
|
* @param searchResults
|
||||||
*/
|
*/
|
||||||
InstanceCountNodeFactory(CommonFilesMetadata metadata){
|
InstanceCountNodeFactory(CommonAttributeSearchResults searchResults){
|
||||||
this.metadata = metadata;
|
this.searchResults = searchResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Integer> list) {
|
protected boolean createKeys(List<Integer> list) {
|
||||||
list.addAll(this.metadata.getMetadata().keySet());
|
list.addAll(this.searchResults.getMetadata().keySet());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(Integer instanceCount){
|
protected Node createNodeForKey(Integer instanceCount){
|
||||||
List<Md5Metadata> md5Metadata = this.metadata.getMetadataForMd5(instanceCount);
|
List<CommonAttributeValue> attributeValues = this.searchResults.getAttributeValuesForInstanceCount(instanceCount);
|
||||||
return new InstanceCountNode(instanceCount, md5Metadata);
|
return new InstanceCountNode(instanceCount, attributeValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the results from the various types of common attribute searching
|
||||||
|
* Stores results based on how they are currently displayed in the UI
|
||||||
|
*/
|
||||||
|
final public class CommonAttributeSearchResults {
|
||||||
|
|
||||||
|
// maps instance count to list of attribute values.
|
||||||
|
private final Map<Integer, List<CommonAttributeValue>> instanceCountToAttributeValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a values object which can be handed off to the node factories.
|
||||||
|
*
|
||||||
|
* @param values list of CommonAttributeValue indexed by size of
|
||||||
|
* CommonAttributeValue
|
||||||
|
*/
|
||||||
|
CommonAttributeSearchResults(Map<Integer, List<CommonAttributeValue>> metadata){
|
||||||
|
this.instanceCountToAttributeValues = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the child node whose children have the specified number of children.
|
||||||
|
*
|
||||||
|
* This is a convenience method - you can also iterate over
|
||||||
|
* <code>getValues()</code>.
|
||||||
|
*
|
||||||
|
* @param isntanceCound key
|
||||||
|
* @return list of values which represent matches
|
||||||
|
*/
|
||||||
|
List<CommonAttributeValue> getAttributeValuesForInstanceCount(Integer instanceCount) {
|
||||||
|
return this.instanceCountToAttributeValues.get(instanceCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an unmodifiable collection of values, indexed by number of
|
||||||
|
* grandchildren, which represents the common attributes found in the
|
||||||
|
* search.
|
||||||
|
* @return map of sizes of children to list of matches
|
||||||
|
*/
|
||||||
|
public Map<Integer, List<CommonAttributeValue>> getMetadata() {
|
||||||
|
return Collections.unmodifiableMap(this.instanceCountToAttributeValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many distinct common files exist for this search results?
|
||||||
|
* @return number of common files
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (List<CommonAttributeValue> data : this.instanceCountToAttributeValues.values()) {
|
||||||
|
for(CommonAttributeValue md5 : data){
|
||||||
|
count += md5.getInstanceCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
@ -19,50 +19,70 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.commonfilesearch;
|
package org.sleuthkit.autopsy.commonfilesearch;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates data required to instantiate an <code>Md5Node</code>.
|
* Defines a value that was in the common file search results
|
||||||
|
* as well as information about its instances.
|
||||||
*/
|
*/
|
||||||
final public class Md5Metadata {
|
final public class CommonAttributeValue {
|
||||||
|
|
||||||
private final String md5;
|
private final String md5;
|
||||||
private final List<FileInstanceMetadata> fileInstances;
|
private final List<AbstractCommonAttributeInstance> fileInstances;
|
||||||
|
|
||||||
Md5Metadata(String md5, List<FileInstanceMetadata> fileInstances){
|
CommonAttributeValue(String md5, List<AbstractCommonAttributeInstance> fileInstances) {
|
||||||
this.md5 = md5;
|
this.md5 = md5;
|
||||||
this.fileInstances = fileInstances;
|
this.fileInstances = fileInstances;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMd5(){
|
CommonAttributeValue(String md5) {
|
||||||
|
this.md5 = md5;
|
||||||
|
this.fileInstances = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
return this.md5;
|
return this.md5;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFileInstanceMetadata(FileInstanceMetadata metadata){
|
|
||||||
this.fileInstances.add(metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<FileInstanceMetadata> getMetadata(){
|
|
||||||
return Collections.unmodifiableCollection(this.fileInstances);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many distinct file instances exist for the MD5 represented by this object?
|
* concatenate cases this value was seen into a single string
|
||||||
* @return number of instances
|
*
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public int size(){
|
public String getCases() {
|
||||||
return this.fileInstances.size();
|
return this.fileInstances.stream().map(AbstractCommonAttributeInstance::getCaseName).collect(Collectors.joining(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDataSources() {
|
public String getDataSources() {
|
||||||
Set<String> sources = new HashSet<> ();
|
Set<String> sources = new HashSet<>();
|
||||||
for(FileInstanceMetadata data : this.fileInstances){
|
for (AbstractCommonAttributeInstance data : this.fileInstances) {
|
||||||
sources.add(data.getDataSourceName());
|
sources.add(data.getDataSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
return String.join(", ", sources);
|
return String.join(", ", sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addInstance(AbstractCommonAttributeInstance metadata) {
|
||||||
|
this.fileInstances.add(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<AbstractCommonAttributeInstance> getInstances() {
|
||||||
|
return Collections.unmodifiableCollection(this.fileInstances);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many distinct file instances exist for the MD5 represented by this
|
||||||
|
* object?
|
||||||
|
*
|
||||||
|
* @return number of instances
|
||||||
|
*/
|
||||||
|
public int getInstanceCount() {
|
||||||
|
return this.fileInstances.size();
|
||||||
|
}
|
||||||
}
|
}
|
@ -20,34 +20,24 @@
|
|||||||
package org.sleuthkit.autopsy.commonfilesearch;
|
package org.sleuthkit.autopsy.commonfilesearch;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a common files match - two or more files which appear to be the
|
* Represents the layer in the tree for the value (such as MD5) that was in multiple places.
|
||||||
* same file and appear as children of this node. This node will simply contain
|
* Children are instances of that value.
|
||||||
* the MD5 of the matched files, the data sources those files were found within,
|
|
||||||
* and a count of the instances represented by the md5.
|
|
||||||
*/
|
*/
|
||||||
public class Md5Node extends DisplayableItemNode {
|
public class CommonAttributeValueNode extends DisplayableItemNode {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(Md5Node.class.getName());
|
private final String value;
|
||||||
|
|
||||||
private final String md5Hash;
|
|
||||||
private final int commonFileCount;
|
private final int commonFileCount;
|
||||||
|
private final String cases;
|
||||||
private final String dataSources;
|
private final String dataSources;
|
||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
@ -57,15 +47,17 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
* Create a Match node whose children will all have this object in common.
|
* Create a Match node whose children will all have this object in common.
|
||||||
* @param data the common feature, and the children
|
* @param data the common feature, and the children
|
||||||
*/
|
*/
|
||||||
public Md5Node(Md5Metadata data) {
|
public CommonAttributeValueNode(CommonAttributeValue data) {
|
||||||
super(Children.create(
|
super(Children.create(
|
||||||
new FileInstanceNodeFactory(data), true));
|
new FileInstanceNodeFactory(data), true));
|
||||||
|
|
||||||
this.commonFileCount = data.size();
|
this.commonFileCount = data.getInstanceCount();
|
||||||
|
this.cases = data.getCases();
|
||||||
|
// @@ We seem to be doing this string concat twice. We also do it in getDataSources()
|
||||||
this.dataSources = String.join(", ", data.getDataSources());
|
this.dataSources = String.join(", ", data.getDataSources());
|
||||||
this.md5Hash = data.getMd5();
|
this.value = data.getValue();
|
||||||
|
|
||||||
this.setDisplayName(String.format(Bundle.Md5Node_Md5Node_format(), this.md5Hash));
|
this.setDisplayName(String.format(Bundle.Md5Node_Md5Node_format(), this.value));
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +68,10 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
int getCommonFileCount() {
|
int getCommonFileCount() {
|
||||||
return this.commonFileCount;
|
return this.commonFileCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getCases(){
|
||||||
|
return this.cases;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Datasources where these matches occur.
|
* Datasources where these matches occur.
|
||||||
@ -89,8 +85,8 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
* MD5 which is common to these matches
|
* MD5 which is common to these matches
|
||||||
* @return string md5 hash
|
* @return string md5 hash
|
||||||
*/
|
*/
|
||||||
public String getMd5() {
|
public String getValue() {
|
||||||
return this.md5Hash;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"Md5Node.createSheet.noDescription= "})
|
@NbBundle.Messages({"Md5Node.createSheet.noDescription= "})
|
||||||
@ -129,35 +125,28 @@ public class Md5Node extends DisplayableItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Child generator for <code>FileInstanceNode</code> of <code>Md5Node</code>.
|
* Child generator for <code>SleuthkitCaseFileInstanceNode</code> of
|
||||||
|
* <code>CommonAttributeValueNode</code>.
|
||||||
*/
|
*/
|
||||||
static class FileInstanceNodeFactory extends ChildFactory<FileInstanceMetadata> {
|
static class FileInstanceNodeFactory extends ChildFactory<AbstractCommonAttributeInstance> {
|
||||||
|
|
||||||
private final Md5Metadata descendants;
|
private final CommonAttributeValue descendants;
|
||||||
|
|
||||||
FileInstanceNodeFactory(Md5Metadata descendants) {
|
FileInstanceNodeFactory(CommonAttributeValue descendants) {
|
||||||
this.descendants = descendants;
|
this.descendants = descendants;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(FileInstanceMetadata file) {
|
protected boolean createKeys(List<AbstractCommonAttributeInstance> list) {
|
||||||
try {
|
list.addAll(this.descendants.getInstances());
|
||||||
Case currentCase = Case.getCurrentCaseThrows();
|
|
||||||
SleuthkitCase tskDb = currentCase.getSleuthkitCase();
|
|
||||||
AbstractFile abstractFile = tskDb.findAllFilesWhere(String.format("obj_id in (%s)", file.getObjectId())).get(0);
|
|
||||||
|
|
||||||
return new FileInstanceNode(abstractFile, file.getDataSourceName());
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, String.format("Unable to create node for file with obj_id: %s.", new Object[]{file.getObjectId()}), ex);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<FileInstanceMetadata> list) {
|
|
||||||
list.addAll(this.descendants.getMetadata());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
protected Node[] createNodesForKey(AbstractCommonAttributeInstance searchResult) {
|
||||||
|
return searchResult.generateNodes();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
}
|
||||||
|
}
|
@ -31,18 +31,18 @@ import org.openide.util.NbBundle;
|
|||||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>DataResultViewerTable</code> which overrides the default column header
|
* <code>DataResultViewerTable</code> which overrides the default column
|
||||||
* width calculations. The <code>CommonFilesSearchResultsViewerTable</code>
|
* header width calculations. The <code>CommonAttributesSearchResultsViewerTable</code>
|
||||||
* presents multiple tiers of data which are not always present and it may not
|
* 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
|
* 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.
|
* rows and looking for wide cells. Rather, we just pick some reasonable values.
|
||||||
*/
|
*/
|
||||||
public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
public class CommonAttributesSearchResultsViewerTable extends DataResultViewerTable {
|
||||||
|
|
||||||
private static final Map<String, Integer> COLUMN_WIDTHS;
|
private static final Map<String, Integer> COLUMN_WIDTHS;
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CommonFilesSearchResultsViewerTable.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(CommonAttributesSearchResultsViewerTable.class.getName());
|
||||||
|
|
||||||
private static final int DEFAULT_WIDTH = 100;
|
private static final int DEFAULT_WIDTH = 100;
|
||||||
|
|
||||||
@ -51,6 +51,7 @@ public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
|||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), 260);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), 65);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_instancesColLbl(), 65);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), 300);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), 300);
|
||||||
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), 200);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), 200);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), 200);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), 100);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_hashsetHitsColLbl(), 100);
|
||||||
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 130);
|
map.put(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), 130);
|
||||||
@ -60,11 +61,13 @@ public class CommonFilesSearchResultsViewerTable extends DataResultViewerTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
|
"CommonFilesSearchResultsViewerTable.noDescText= ",
|
||||||
"CommonFilesSearchResultsViewerTable.filesColLbl=Files",
|
"CommonFilesSearchResultsViewerTable.filesColLbl=Files",
|
||||||
"CommonFilesSearchResultsViewerTable.instancesColLbl=Instances",
|
"CommonFilesSearchResultsViewerTable.instancesColLbl=Instances",
|
||||||
"CommonFilesSearchResultsViewerTable.pathColLbl=Parent Path",
|
"CommonFilesSearchResultsViewerTable.pathColLbl=Parent Path",
|
||||||
"CommonFilesSearchResultsViewerTable.hashsetHitsColLbl=Hash Set Hits",
|
"CommonFilesSearchResultsViewerTable.hashsetHitsColLbl=Hash Set Hits",
|
||||||
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source(s)",
|
"CommonFilesSearchResultsViewerTable.caseColLbl1=Case",
|
||||||
|
"CommonFilesSearchResultsViewerTable.dataSourceColLbl=Data Source",
|
||||||
"CommonFilesSearchResultsViewerTable.mimeTypeColLbl=MIME Type",
|
"CommonFilesSearchResultsViewerTable.mimeTypeColLbl=MIME Type",
|
||||||
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
"CommonFilesSearchResultsViewerTable.tagsColLbl1=Tags"
|
||||||
})
|
})
|
@ -1,51 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
|
|
||||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
|
|
||||||
<Properties>
|
|
||||||
<Property name="defaultCloseOperation" type="int" value="2"/>
|
|
||||||
<Property name="size" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
|
||||||
<Dimension value="[340, 320]"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
<SyntheticProperties>
|
|
||||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
|
||||||
<SyntheticProperty name="generateCenter" type="boolean" value="true"/>
|
|
||||||
</SyntheticProperties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="windowClosed" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosed"/>
|
|
||||||
</Events>
|
|
||||||
<AuxValues>
|
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
|
||||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
|
||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
|
||||||
</AuxValues>
|
|
||||||
|
|
||||||
<Layout>
|
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="commonFilesPanel1" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="commonFilesPanel1" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
|
||||||
<Component class="org.sleuthkit.autopsy.commonfilesearch.CommonFilesPanel" name="commonFilesPanel1">
|
|
||||||
</Component>
|
|
||||||
</SubComponents>
|
|
||||||
</Form>
|
|
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.commonfilesearch;
|
|
||||||
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.windows.WindowManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dialog box for configuring and running common files search.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
|
||||||
public final class CommonFilesDialog extends javax.swing.JDialog {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates new form CommonFilesDialog
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFilesDialog.frame.title=Find Common Files",
|
|
||||||
"CommonFilesDialog.frame.msg=Find Common Files"})
|
|
||||||
public CommonFilesDialog() {
|
|
||||||
super(new JFrame(Bundle.CommonFilesDialog_frame_title()),
|
|
||||||
Bundle.CommonFilesDialog_frame_msg(), true);
|
|
||||||
initComponents();
|
|
||||||
|
|
||||||
this.setResizable(false);
|
|
||||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called from within the constructor to initialize the form.
|
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
|
||||||
* regenerated by the Form Editor.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
|
||||||
private void initComponents() {
|
|
||||||
|
|
||||||
commonFilesPanel1 = new org.sleuthkit.autopsy.commonfilesearch.CommonFilesPanel();
|
|
||||||
|
|
||||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
|
||||||
setSize(new java.awt.Dimension(340, 320));
|
|
||||||
addWindowListener(new java.awt.event.WindowAdapter() {
|
|
||||||
public void windowClosed(java.awt.event.WindowEvent evt) {
|
|
||||||
formWindowClosed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
|
||||||
getContentPane().setLayout(layout);
|
|
||||||
layout.setHorizontalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(commonFilesPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
|
||||||
);
|
|
||||||
layout.setVerticalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(commonFilesPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(0, 0, Short.MAX_VALUE))
|
|
||||||
);
|
|
||||||
|
|
||||||
pack();
|
|
||||||
setLocationRelativeTo(null);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
|
||||||
|
|
||||||
private void formWindowClosed(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosed
|
|
||||||
SwingUtilities.windowForComponent(this).dispose();
|
|
||||||
}//GEN-LAST:event_formWindowClosed
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
|
||||||
private org.sleuthkit.autopsy.commonfilesearch.CommonFilesPanel commonFilesPanel1;
|
|
||||||
// End of variables declaration//GEN-END:variables
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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.commonfilesearch;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility and wrapper model around data required for Common Files Search results.
|
|
||||||
* Subclass this to implement different selections of files from the case.
|
|
||||||
*/
|
|
||||||
final public class CommonFilesMetadata {
|
|
||||||
|
|
||||||
private final Map<Integer, List<Md5Metadata>> metadata;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a metadata object which can be handed off to the node
|
|
||||||
* factories.
|
|
||||||
*
|
|
||||||
* @param metadata list of Md5Metadata indexed by size of Md5Metadata
|
|
||||||
*/
|
|
||||||
CommonFilesMetadata(Map<Integer, List<Md5Metadata>> metadata){
|
|
||||||
this.metadata = metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the meta data for the given md5.
|
|
||||||
*
|
|
||||||
* This is a convenience method - you can also iterate over
|
|
||||||
* <code>getMetadata()</code>.
|
|
||||||
*
|
|
||||||
* @param md5 key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
List<Md5Metadata> getMetadataForMd5(Integer instanceCount) {
|
|
||||||
return this.metadata.get(instanceCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Integer, List<Md5Metadata>> getMetadata() {
|
|
||||||
return Collections.unmodifiableMap(this.metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How many distinct file instances exist for this metadata?
|
|
||||||
* @return number of file instances
|
|
||||||
*/
|
|
||||||
public int size() {
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
for (List<Md5Metadata> data : this.metadata.values()) {
|
|
||||||
for(Md5Metadata md5 : data){
|
|
||||||
count += md5.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,277 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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.commonfilesearch;
|
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|
||||||
import org.sleuthkit.datamodel.HashUtility;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Generates a <code>List<CommonFilesMetadata></code> when
|
|
||||||
* <code>findCommonFiles()</code> is called, which organizes files by md5 to
|
|
||||||
* prepare to display in viewer.
|
|
||||||
*
|
|
||||||
* This entire thing runs on a background thread where exceptions are handled.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("PMD.AbstractNaming")
|
|
||||||
public abstract class CommonFilesMetadataBuilder {
|
|
||||||
|
|
||||||
private final Map<Long, String> dataSourceIdToNameMap;
|
|
||||||
private final boolean filterByMedia;
|
|
||||||
private final boolean filterByDoc;
|
|
||||||
private static final String FILTER_BY_MIME_TYPES_WHERE_CLAUSE = " and mime_type in (%s)"; //NON-NLS // where %s is csv list of mime_types to filter on
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The set of the MIME types that will be checked for extension mismatches
|
|
||||||
* when checkType is ONLY_MEDIA.
|
|
||||||
* ".jpg", ".jpeg", ".png", ".psd", ".nef", ".tiff", ".bmp", ".tec"
|
|
||||||
* ".aaf", ".3gp", ".asf", ".avi", ".m1v", ".m2v", //NON-NLS
|
|
||||||
* ".m4v", ".mp4", ".mov", ".mpeg", ".mpg", ".mpe", ".mp4", ".rm", ".wmv", ".mpv", ".flv", ".swf"
|
|
||||||
*/
|
|
||||||
private static final Set<String> MEDIA_PICS_VIDEO_MIME_TYPES = Stream.of(
|
|
||||||
"image/bmp", //NON-NLS
|
|
||||||
"image/gif", //NON-NLS
|
|
||||||
"image/jpeg", //NON-NLS
|
|
||||||
"image/png", //NON-NLS
|
|
||||||
"image/tiff", //NON-NLS
|
|
||||||
"image/vnd.adobe.photoshop", //NON-NLS
|
|
||||||
"image/x-raw-nikon", //NON-NLS
|
|
||||||
"image/x-ms-bmp", //NON-NLS
|
|
||||||
"image/x-icon", //NON-NLS
|
|
||||||
"video/webm", //NON-NLS
|
|
||||||
"video/3gpp", //NON-NLS
|
|
||||||
"video/3gpp2", //NON-NLS
|
|
||||||
"video/ogg", //NON-NLS
|
|
||||||
"video/mpeg", //NON-NLS
|
|
||||||
"video/mp4", //NON-NLS
|
|
||||||
"video/quicktime", //NON-NLS
|
|
||||||
"video/x-msvideo", //NON-NLS
|
|
||||||
"video/x-flv", //NON-NLS
|
|
||||||
"video/x-m4v", //NON-NLS
|
|
||||||
"video/x-ms-wmv", //NON-NLS
|
|
||||||
"application/vnd.ms-asf", //NON-NLS
|
|
||||||
"application/vnd.rn-realmedia", //NON-NLS
|
|
||||||
"application/x-shockwave-flash" //NON-NLS
|
|
||||||
).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The set of the MIME types that will be checked for extension mismatches
|
|
||||||
* when checkType is ONLY_TEXT_FILES.
|
|
||||||
* ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx"
|
|
||||||
* ".txt", ".rtf", ".log", ".text", ".xml"
|
|
||||||
* ".html", ".htm", ".css", ".js", ".php", ".aspx"
|
|
||||||
* ".pdf"
|
|
||||||
*/
|
|
||||||
private static final Set<String> TEXT_FILES_MIME_TYPES = Stream.of(
|
|
||||||
"text/plain", //NON-NLS
|
|
||||||
"application/rtf", //NON-NLS
|
|
||||||
"application/pdf", //NON-NLS
|
|
||||||
"text/css", //NON-NLS
|
|
||||||
"text/html", //NON-NLS
|
|
||||||
"text/csv", //NON-NLS
|
|
||||||
"application/json", //NON-NLS
|
|
||||||
"application/javascript", //NON-NLS
|
|
||||||
"application/xml", //NON-NLS
|
|
||||||
"text/calendar", //NON-NLS
|
|
||||||
"application/x-msoffice", //NON-NLS
|
|
||||||
"application/x-ooxml", //NON-NLS
|
|
||||||
"application/msword", //NON-NLS
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document", //NON-NLS
|
|
||||||
"application/vnd.ms-powerpoint", //NON-NLS
|
|
||||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation", //NON-NLS
|
|
||||||
"application/vnd.ms-excel", //NON-NLS
|
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //NON-NLS
|
|
||||||
"application/vnd.oasis.opendocument.presentation", //NON-NLS
|
|
||||||
"application/vnd.oasis.opendocument.spreadsheet", //NON-NLS
|
|
||||||
"application/vnd.oasis.opendocument.text" //NON-NLS
|
|
||||||
).collect(Collectors.toSet());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subclass this to implement different algorithms for getting common files.
|
|
||||||
*
|
|
||||||
* @param dataSourceIdMap a map of obj_id to datasource name
|
|
||||||
* @param filterByMediaMimeType match only on files whose mime types can be
|
|
||||||
* broadly categorized as media types
|
|
||||||
* @param filterByDocMimeType match only on files whose mime types can be
|
|
||||||
* broadly categorized as document types
|
|
||||||
*/
|
|
||||||
CommonFilesMetadataBuilder(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
|
|
||||||
dataSourceIdToNameMap = dataSourceIdMap;
|
|
||||||
filterByMedia = filterByMediaMimeType;
|
|
||||||
filterByDoc = filterByDocMimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use this as a prefix when building the SQL select statement.
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>You only have to specify the WHERE clause if you use this.</li>
|
|
||||||
* <li>If you do not use this string, you must use at least the columns
|
|
||||||
* selected below, in that order.</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
static final String SELECT_PREFIX = "SELECT obj_id, md5, data_source_obj_id from tsk_files where"; //NON-NLS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should build a SQL SELECT statement to be passed to
|
|
||||||
* SleuthkitCase.executeQuery(sql) which will select the desired file ids
|
|
||||||
* and MD5 hashes.
|
|
||||||
*
|
|
||||||
* The statement should select obj_id, md5, data_source_obj_id in that
|
|
||||||
* order.
|
|
||||||
*
|
|
||||||
* @return sql string select statement
|
|
||||||
*/
|
|
||||||
protected abstract String buildSqlSelectStatement();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a meta data object which encapsulates everything need to add the
|
|
||||||
* tree table tab to the top component.
|
|
||||||
*
|
|
||||||
* @return a data object with all of the matched files in a hierarchical
|
|
||||||
* format
|
|
||||||
* @throws TskCoreException
|
|
||||||
* @throws NoCurrentCaseException
|
|
||||||
* @throws SQLException
|
|
||||||
*/
|
|
||||||
public CommonFilesMetadata findCommonFiles() throws TskCoreException, NoCurrentCaseException, SQLException {
|
|
||||||
|
|
||||||
Map<String, Md5Metadata> commonFiles = new HashMap<>();
|
|
||||||
|
|
||||||
SleuthkitCase sleuthkitCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
|
||||||
String selectStatement = this.buildSqlSelectStatement();
|
|
||||||
|
|
||||||
try (
|
|
||||||
CaseDbQuery query = sleuthkitCase.executeQuery(selectStatement);
|
|
||||||
ResultSet resultSet = query.getResultSet()) {
|
|
||||||
|
|
||||||
while (resultSet.next()) {
|
|
||||||
Long objectId = resultSet.getLong(1);
|
|
||||||
String md5 = resultSet.getString(2);
|
|
||||||
Long dataSourceId = resultSet.getLong(3);
|
|
||||||
String dataSource = this.dataSourceIdToNameMap.get(dataSourceId);
|
|
||||||
|
|
||||||
if (md5 == null || HashUtility.isNoDataMd5(md5)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commonFiles.containsKey(md5)) {
|
|
||||||
final Md5Metadata md5Metadata = commonFiles.get(md5);
|
|
||||||
md5Metadata.addFileInstanceMetadata(new FileInstanceMetadata(objectId, dataSource));
|
|
||||||
} else {
|
|
||||||
final List<FileInstanceMetadata> fileInstances = new ArrayList<>();
|
|
||||||
fileInstances.add(new FileInstanceMetadata(objectId, dataSource));
|
|
||||||
Md5Metadata md5Metadata = new Md5Metadata(md5, fileInstances);
|
|
||||||
commonFiles.put(md5, md5Metadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Integer, List<Md5Metadata>> instanceCollatedCommonFiles = new TreeMap<>();
|
|
||||||
|
|
||||||
for(Md5Metadata md5Metadata : commonFiles.values()){
|
|
||||||
Integer size = md5Metadata.size();
|
|
||||||
|
|
||||||
if(instanceCollatedCommonFiles.containsKey(size)){
|
|
||||||
instanceCollatedCommonFiles.get(size).add(md5Metadata);
|
|
||||||
} else {
|
|
||||||
ArrayList<Md5Metadata> value = new ArrayList<>();
|
|
||||||
value.add(md5Metadata);
|
|
||||||
instanceCollatedCommonFiles.put(size, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CommonFilesMetadata(instanceCollatedCommonFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should be used by subclasses, in their
|
|
||||||
* <code>buildSqlSelectStatement()</code> function to create an SQL boolean
|
|
||||||
* expression which will filter our matches based on mime type. The
|
|
||||||
* expression will be conjoined to base query with an AND operator.
|
|
||||||
*
|
|
||||||
* @return sql fragment of the form:
|
|
||||||
* 'and "mime_type" in ( [comma delimited list of mime types] )'
|
|
||||||
* or empty string in the event that no types to filter on were given.
|
|
||||||
*/
|
|
||||||
String determineMimeTypeFilter() {
|
|
||||||
|
|
||||||
Set<String> mimeTypesToFilterOn = new HashSet<>();
|
|
||||||
String mimeTypeString = "";
|
|
||||||
if (filterByMedia) {
|
|
||||||
mimeTypesToFilterOn.addAll(MEDIA_PICS_VIDEO_MIME_TYPES);
|
|
||||||
}
|
|
||||||
if (filterByDoc) {
|
|
||||||
mimeTypesToFilterOn.addAll(TEXT_FILES_MIME_TYPES);
|
|
||||||
}
|
|
||||||
StringBuilder mimeTypeFilter = new StringBuilder(mimeTypesToFilterOn.size());
|
|
||||||
if (!mimeTypesToFilterOn.isEmpty()) {
|
|
||||||
for (String mimeType : mimeTypesToFilterOn) {
|
|
||||||
mimeTypeFilter.append("'").append(mimeType).append("',");
|
|
||||||
}
|
|
||||||
mimeTypeString = mimeTypeFilter.toString().substring(0, mimeTypeFilter.length() - 1);
|
|
||||||
mimeTypeString = String.format(FILTER_BY_MIME_TYPES_WHERE_CLAUSE, new Object[]{mimeTypeString});
|
|
||||||
}
|
|
||||||
return mimeTypeString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFilesMetadataBuilder.buildTabTitle.titleAll=Common Files (All Data Sources, %s)",
|
|
||||||
"CommonFilesMetadataBuilder.buildTabTitle.titleSingle=Common Files (Match Within Data Source: %s, %s)"
|
|
||||||
})
|
|
||||||
protected abstract String buildTabTitle();
|
|
||||||
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFilesMetadataBuilder.buildCategorySelectionString.doc=Documents",
|
|
||||||
"CommonFilesMetadataBuilder.buildCategorySelectionString.media=Media",
|
|
||||||
"CommonFilesMetadataBuilder.buildCategorySelectionString.all=All File Categories"
|
|
||||||
})
|
|
||||||
|
|
||||||
protected String buildCategorySelectionString() {
|
|
||||||
if (!this.filterByDoc && !this.filterByMedia) {
|
|
||||||
return Bundle.CommonFilesMetadataBuilder_buildCategorySelectionString_all();
|
|
||||||
} else {
|
|
||||||
List<String> filters = new ArrayList<>();
|
|
||||||
if (this.filterByDoc) {
|
|
||||||
filters.add(Bundle.CommonFilesMetadataBuilder_buildCategorySelectionString_doc());
|
|
||||||
}
|
|
||||||
if (this.filterByMedia) {
|
|
||||||
filters.add(Bundle.CommonFilesMetadataBuilder_buildCategorySelectionString_media());
|
|
||||||
}
|
|
||||||
return String.join(", ", filters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,261 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
|
|
||||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
|
||||||
<NonVisualComponents>
|
|
||||||
<Component class="javax.swing.ButtonGroup" name="dataSourcesButtonGroup">
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.ButtonGroup" name="fileTypeFilterButtonGroup">
|
|
||||||
</Component>
|
|
||||||
</NonVisualComponents>
|
|
||||||
<AuxValues>
|
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
|
||||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
|
||||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
|
||||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
|
||||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
|
||||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
|
||||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
|
||||||
</AuxValues>
|
|
||||||
|
|
||||||
<Layout>
|
|
||||||
<DimensionLayout dim="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
|
||||||
<Group type="102" alignment="1" attributes="0">
|
|
||||||
<Component id="errorText" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
|
||||||
<Component id="searchButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="cancelButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="categoriesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="commonFilesSearchLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="dataSourceLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Group type="102" attributes="0">
|
|
||||||
<EmptySpace min="6" pref="6" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="-2" pref="29" max="-2" attributes="0"/>
|
|
||||||
<Component id="selectDataSourceComboBox" min="-2" pref="261" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Component id="withinDataSourceRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="allDataSourcesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="allFileCategoriesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="selectedFileCategoriesButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="documentsCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
<DimensionLayout dim="1">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="1" attributes="0">
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="commonFilesSearchLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace min="-2" pref="18" max="-2" attributes="0"/>
|
|
||||||
<Component id="dataSourceLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="allDataSourcesRadioButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="withinDataSourceRadioButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="selectDataSourceComboBox" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
|
||||||
<Component id="categoriesLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="selectedFileCategoriesButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="pictureVideoCheckbox" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="documentsCheckbox" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="allFileCategoriesRadioButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
|
||||||
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="searchButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="errorText" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</DimensionLayout>
|
|
||||||
</Layout>
|
|
||||||
<SubComponents>
|
|
||||||
<Component class="javax.swing.JButton" name="searchButton">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.searchButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="enabled" type="boolean" value="false"/>
|
|
||||||
<Property name="horizontalTextPosition" type="int" value="10"/>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="searchButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JRadioButton" name="allDataSourcesRadioButton">
|
|
||||||
<Properties>
|
|
||||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
|
||||||
<ComponentRef name="dataSourcesButtonGroup"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.allDataSourcesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="allDataSourcesRadioButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JRadioButton" name="withinDataSourceRadioButton">
|
|
||||||
<Properties>
|
|
||||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
|
||||||
<ComponentRef name="dataSourcesButtonGroup"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.withinDataSourceRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="withinDataSourceRadioButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JComboBox" name="selectDataSourceComboBox">
|
|
||||||
<Properties>
|
|
||||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
|
||||||
<Connection code="dataSourcesList" type="code"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="enabled" type="boolean" value="false"/>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectDataSourceComboBoxActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
<AuxValues>
|
|
||||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
|
||||||
</AuxValues>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JLabel" name="commonFilesSearchLabel">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.commonFilesSearchLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="focusable" type="boolean" value="false"/>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JButton" name="cancelButton">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.cancelButton.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="horizontalTextPosition" type="int" value="10"/>
|
|
||||||
</Properties>
|
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JRadioButton" name="allFileCategoriesRadioButton">
|
|
||||||
<Properties>
|
|
||||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
|
||||||
<ComponentRef name="fileTypeFilterButtonGroup"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.allFileCategoriesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.allFileCategoriesRadioButton.toolTipText" 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="allFileCategoriesRadioButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JRadioButton" name="selectedFileCategoriesButton">
|
|
||||||
<Properties>
|
|
||||||
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
|
||||||
<ComponentRef name="fileTypeFilterButtonGroup"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.selectedFileCategoriesButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.selectedFileCategoriesButton.toolTipText" 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="selectedFileCategoriesButtonActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JCheckBox" name="pictureVideoCheckbox">
|
|
||||||
<Properties>
|
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.pictureVideoCheckbox.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="pictureVideoCheckboxActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JCheckBox" name="documentsCheckbox">
|
|
||||||
<Properties>
|
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.documentsCheckbox.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="documentsCheckboxActionPerformed"/>
|
|
||||||
</Events>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JLabel" name="dataSourceLabel">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JLabel" name="categoriesLabel">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.categoriesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JLabel" name="errorText">
|
|
||||||
<Properties>
|
|
||||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
|
||||||
<Color blue="0" green="0" red="ff" type="rgb"/>
|
|
||||||
</Property>
|
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="CommonFilesPanel.errorText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
</SubComponents>
|
|
||||||
</Form>
|
|
@ -1,580 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.commonfilesearch;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import javax.swing.ComboBoxModel;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
import javax.swing.SwingWorker;
|
|
||||||
import org.netbeans.api.progress.ProgressHandle;
|
|
||||||
import org.openide.explorer.ExplorerManager;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
|
|
||||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Panel used for common files search configuration and configuration business
|
|
||||||
* logic. Nested within CommonFilesDialog.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
|
||||||
public final class CommonFilesPanel extends javax.swing.JPanel {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final Long NO_DATA_SOURCE_SELECTED = -1L;
|
|
||||||
|
|
||||||
private ComboBoxModel<String> dataSourcesList = new DataSourceComboBoxModel();
|
|
||||||
private Map<Long, String> dataSourceMap;
|
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(CommonFilesPanel.class.getName());
|
|
||||||
private boolean singleDataSource = false;
|
|
||||||
private String selectedDataSource = "";
|
|
||||||
private boolean pictureViewCheckboxState;
|
|
||||||
private boolean documentsCheckboxState;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates new form CommonFilesPanel
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFilesPanel.title=Common Files Panel",
|
|
||||||
"CommonFilesPanel.exception=Unexpected Exception loading DataSources."})
|
|
||||||
public CommonFilesPanel() {
|
|
||||||
initComponents();
|
|
||||||
|
|
||||||
this.setupDataSources();
|
|
||||||
|
|
||||||
this.errorText.setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the data sources dropdown and returns the data sources map for
|
|
||||||
* future usage.
|
|
||||||
*
|
|
||||||
* @return a mapping of data source ids to data source names
|
|
||||||
*/
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFilesPanel.buildDataSourceMap.done.tskCoreException=Unable to run query against DB.",
|
|
||||||
"CommonFilesPanel.buildDataSourceMap.done.noCurrentCaseException=Unable to open case file.",
|
|
||||||
"CommonFilesPanel.buildDataSourceMap.done.exception=Unexpected exception building data sources map.",
|
|
||||||
"CommonFilesPanel.buildDataSourceMap.done.interupted=Something went wrong building the Common Files Search dialog box.",
|
|
||||||
"CommonFilesPanel.buildDataSourceMap.done.sqlException=Unable to query db for data sources.",
|
|
||||||
"CommonFilesPanel.buildDataSourcesMap.updateUi.noDataSources=No data sources were found."})
|
|
||||||
private void setupDataSources() {
|
|
||||||
|
|
||||||
new SwingWorker<Map<Long, String>, Void>() {
|
|
||||||
|
|
||||||
private void updateUi() {
|
|
||||||
|
|
||||||
String[] dataSourcesNames = new String[CommonFilesPanel.this.dataSourceMap.size()];
|
|
||||||
|
|
||||||
//only enable all this stuff if we actually have datasources
|
|
||||||
if (dataSourcesNames.length > 0) {
|
|
||||||
dataSourcesNames = CommonFilesPanel.this.dataSourceMap.values().toArray(dataSourcesNames);
|
|
||||||
CommonFilesPanel.this.dataSourcesList = new DataSourceComboBoxModel(dataSourcesNames);
|
|
||||||
CommonFilesPanel.this.selectDataSourceComboBox.setModel(CommonFilesPanel.this.dataSourcesList);
|
|
||||||
|
|
||||||
boolean multipleDataSources = this.caseHasMultipleSources();
|
|
||||||
|
|
||||||
CommonFilesPanel.this.allDataSourcesRadioButton.setEnabled(true);
|
|
||||||
CommonFilesPanel.this.allDataSourcesRadioButton.setSelected(true);
|
|
||||||
|
|
||||||
if (!multipleDataSources) {
|
|
||||||
CommonFilesPanel.this.withinDataSourceRadioButton.setEnabled(false);
|
|
||||||
CommonFilesPanel.this.withinDataSourceRadioButton.setSelected(false);
|
|
||||||
withinDataSourceSelected(false);
|
|
||||||
CommonFilesPanel.this.selectDataSourceComboBox.setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
CommonFilesPanel.this.searchButton.setEnabled(true);
|
|
||||||
} else {
|
|
||||||
MessageNotifyUtil.Message.info(Bundle.CommonFilesPanel_buildDataSourcesMap_updateUi_noDataSources());
|
|
||||||
CommonFilesPanel.this.cancelButtonActionPerformed(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean caseHasMultipleSources() {
|
|
||||||
return CommonFilesPanel.this.dataSourceMap.size() >= 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Map<Long, String> doInBackground() throws NoCurrentCaseException, TskCoreException, SQLException {
|
|
||||||
DataSourceLoader loader = new DataSourceLoader();
|
|
||||||
return loader.getDataSourceMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void done() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
CommonFilesPanel.this.dataSourceMap = this.get();
|
|
||||||
|
|
||||||
updateUi();
|
|
||||||
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Interrupted while building Common Files Search dialog.", ex);
|
|
||||||
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_buildDataSourceMap_done_interupted());
|
|
||||||
} catch (ExecutionException ex) {
|
|
||||||
String errorMessage;
|
|
||||||
Throwable inner = ex.getCause();
|
|
||||||
if (inner instanceof TskCoreException) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Failed to load data sources from database.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_tskCoreException();
|
|
||||||
} else if (inner instanceof NoCurrentCaseException) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Current case has been closed.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_noCurrentCaseException();
|
|
||||||
} else if (inner instanceof SQLException) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unable to query db for data sources.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_sqlException();
|
|
||||||
} else {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unexpected exception while building Common Files Search dialog panel.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_buildDataSourceMap_done_exception();
|
|
||||||
}
|
|
||||||
MessageNotifyUtil.Message.error(errorMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"CommonFilesPanel.search.results.titleAll=Common Files (All Data Sources)",
|
|
||||||
"CommonFilesPanel.search.results.titleSingle=Common Files (Match Within Data Source: %s)",
|
|
||||||
"CommonFilesPanel.search.results.pathText=Common Files Search Results",
|
|
||||||
"CommonFilesPanel.search.done.searchProgressGathering=Gathering Common Files Search Results.",
|
|
||||||
"CommonFilesPanel.search.done.searchProgressDisplay=Displaying Common Files Search Results.",
|
|
||||||
"CommonFilesPanel.search.done.tskCoreException=Unable to run query against DB.",
|
|
||||||
"CommonFilesPanel.search.done.noCurrentCaseException=Unable to open case file.",
|
|
||||||
"CommonFilesPanel.search.done.exception=Unexpected exception running Common Files Search.",
|
|
||||||
"CommonFilesPanel.search.done.interupted=Something went wrong finding common files.",
|
|
||||||
"CommonFilesPanel.search.done.sqlException=Unable to query db for files or data sources."})
|
|
||||||
private void search() {
|
|
||||||
String pathText = Bundle.CommonFilesPanel_search_results_pathText();
|
|
||||||
|
|
||||||
new SwingWorker<CommonFilesMetadata, Void>() {
|
|
||||||
|
|
||||||
private String tabTitle;
|
|
||||||
private ProgressHandle progress;
|
|
||||||
|
|
||||||
private void setTitleForAllDataSources() {
|
|
||||||
this.tabTitle = Bundle.CommonFilesPanel_search_results_titleAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setTitleForSingleSource(Long dataSourceId) {
|
|
||||||
final String CommonFilesPanel_search_results_titleSingle = Bundle.CommonFilesPanel_search_results_titleSingle();
|
|
||||||
final Object[] dataSourceName = new Object[]{dataSourceMap.get(dataSourceId)};
|
|
||||||
|
|
||||||
this.tabTitle = String.format(CommonFilesPanel_search_results_titleSingle, dataSourceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long determineDataSourceId() {
|
|
||||||
Long selectedObjId = CommonFilesPanel.NO_DATA_SOURCE_SELECTED;
|
|
||||||
if (CommonFilesPanel.this.singleDataSource) {
|
|
||||||
for (Entry<Long, String> dataSource : CommonFilesPanel.this.dataSourceMap.entrySet()) {
|
|
||||||
if (dataSource.getValue().equals(CommonFilesPanel.this.selectedDataSource)) {
|
|
||||||
selectedObjId = dataSource.getKey();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return selectedObjId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings({"BoxedValueEquality", "NumberEquality"})
|
|
||||||
protected CommonFilesMetadata doInBackground() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
|
|
||||||
progress = ProgressHandle.createHandle(Bundle.CommonFilesPanel_search_done_searchProgressGathering());
|
|
||||||
progress.start();
|
|
||||||
progress.switchToIndeterminate();
|
|
||||||
|
|
||||||
Long dataSourceId = determineDataSourceId();
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder builder;
|
|
||||||
boolean filterByMedia = false;
|
|
||||||
boolean filterByDocuments = false;
|
|
||||||
if (selectedFileCategoriesButton.isSelected()) {
|
|
||||||
if (pictureVideoCheckbox.isSelected()) {
|
|
||||||
filterByMedia = true;
|
|
||||||
}
|
|
||||||
if (documentsCheckbox.isSelected()) {
|
|
||||||
filterByDocuments = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dataSourceId == CommonFilesPanel.NO_DATA_SOURCE_SELECTED) {
|
|
||||||
builder = new AllDataSourcesCommonFilesAlgorithm(CommonFilesPanel.this.dataSourceMap, filterByMedia, filterByDocuments);
|
|
||||||
|
|
||||||
setTitleForAllDataSources();
|
|
||||||
} else {
|
|
||||||
builder = new SingleDataSource(dataSourceId, CommonFilesPanel.this.dataSourceMap, filterByMedia, filterByDocuments);
|
|
||||||
|
|
||||||
setTitleForSingleSource(dataSourceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tabTitle = builder.buildTabTitle();
|
|
||||||
|
|
||||||
CommonFilesMetadata metadata = builder.findCommonFiles();
|
|
||||||
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void done() {
|
|
||||||
try {
|
|
||||||
super.done();
|
|
||||||
CommonFilesMetadata metadata = get();
|
|
||||||
|
|
||||||
CommonFilesNode commonFilesNode = new CommonFilesNode(metadata);
|
|
||||||
|
|
||||||
//TODO this could be enumerating the children!!!
|
|
||||||
DataResultFilterNode dataResultFilterNode = new DataResultFilterNode(commonFilesNode, ExplorerManager.find(CommonFilesPanel.this));
|
|
||||||
|
|
||||||
TableFilterNode tableFilterWithDescendantsNode = new TableFilterNode(dataResultFilterNode, 3);
|
|
||||||
|
|
||||||
DataResultViewerTable table = new CommonFilesSearchResultsViewerTable();
|
|
||||||
|
|
||||||
Collection<DataResultViewer> viewers = new ArrayList<>(1);
|
|
||||||
viewers.add(table);
|
|
||||||
progress.setDisplayName(Bundle.CommonFilesPanel_search_done_searchProgressDisplay());
|
|
||||||
DataResultTopComponent.createInstance(tabTitle, pathText, tableFilterWithDescendantsNode, metadata.size(), viewers);
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Interrupted while loading Common Files", ex);
|
|
||||||
MessageNotifyUtil.Message.error(Bundle.CommonFilesPanel_search_done_interupted());
|
|
||||||
} catch (ExecutionException ex) {
|
|
||||||
String errorMessage;
|
|
||||||
Throwable inner = ex.getCause();
|
|
||||||
if (inner instanceof TskCoreException) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Failed to load files from database.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_search_done_tskCoreException();
|
|
||||||
} else if (inner instanceof NoCurrentCaseException) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Current case has been closed.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_search_done_noCurrentCaseException();
|
|
||||||
} else if (inner instanceof SQLException) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unable to query db for files.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_search_done_sqlException();
|
|
||||||
} else {
|
|
||||||
LOGGER.log(Level.SEVERE, "Unexpected exception while running Common Files Search.", ex);
|
|
||||||
errorMessage = Bundle.CommonFilesPanel_search_done_exception();
|
|
||||||
}
|
|
||||||
MessageNotifyUtil.Message.error(errorMessage);
|
|
||||||
} finally {
|
|
||||||
progress.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called from within the constructor to initialize the form.
|
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
|
||||||
* regenerated by the Form Editor.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
|
||||||
private void initComponents() {
|
|
||||||
|
|
||||||
dataSourcesButtonGroup = new javax.swing.ButtonGroup();
|
|
||||||
fileTypeFilterButtonGroup = new javax.swing.ButtonGroup();
|
|
||||||
searchButton = new javax.swing.JButton();
|
|
||||||
allDataSourcesRadioButton = new javax.swing.JRadioButton();
|
|
||||||
withinDataSourceRadioButton = new javax.swing.JRadioButton();
|
|
||||||
selectDataSourceComboBox = new javax.swing.JComboBox<>();
|
|
||||||
commonFilesSearchLabel = new javax.swing.JLabel();
|
|
||||||
cancelButton = new javax.swing.JButton();
|
|
||||||
allFileCategoriesRadioButton = new javax.swing.JRadioButton();
|
|
||||||
selectedFileCategoriesButton = new javax.swing.JRadioButton();
|
|
||||||
pictureVideoCheckbox = new javax.swing.JCheckBox();
|
|
||||||
documentsCheckbox = new javax.swing.JCheckBox();
|
|
||||||
dataSourceLabel = new javax.swing.JLabel();
|
|
||||||
categoriesLabel = new javax.swing.JLabel();
|
|
||||||
errorText = new javax.swing.JLabel();
|
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(searchButton, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.searchButton.text")); // NOI18N
|
|
||||||
searchButton.setEnabled(false);
|
|
||||||
searchButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
|
||||||
searchButton.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
searchButtonActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dataSourcesButtonGroup.add(allDataSourcesRadioButton);
|
|
||||||
allDataSourcesRadioButton.setSelected(true);
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(allDataSourcesRadioButton, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.allDataSourcesRadioButton.text")); // NOI18N
|
|
||||||
allDataSourcesRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
|
||||||
allDataSourcesRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
allDataSourcesRadioButtonActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dataSourcesButtonGroup.add(withinDataSourceRadioButton);
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(withinDataSourceRadioButton, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.withinDataSourceRadioButton.text")); // NOI18N
|
|
||||||
withinDataSourceRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
|
||||||
withinDataSourceRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
withinDataSourceRadioButtonActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
selectDataSourceComboBox.setModel(dataSourcesList);
|
|
||||||
selectDataSourceComboBox.setEnabled(false);
|
|
||||||
selectDataSourceComboBox.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
selectDataSourceComboBoxActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(commonFilesSearchLabel, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.commonFilesSearchLabel.text")); // NOI18N
|
|
||||||
commonFilesSearchLabel.setFocusable(false);
|
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.cancelButton.text")); // NOI18N
|
|
||||||
cancelButton.setActionCommand(org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.cancelButton.actionCommand")); // NOI18N
|
|
||||||
cancelButton.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
|
||||||
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
cancelButtonActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fileTypeFilterButtonGroup.add(allFileCategoriesRadioButton);
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(allFileCategoriesRadioButton, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.allFileCategoriesRadioButton.text")); // NOI18N
|
|
||||||
allFileCategoriesRadioButton.setToolTipText(org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.allFileCategoriesRadioButton.toolTipText")); // NOI18N
|
|
||||||
allFileCategoriesRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
allFileCategoriesRadioButtonActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
fileTypeFilterButtonGroup.add(selectedFileCategoriesButton);
|
|
||||||
selectedFileCategoriesButton.setSelected(true);
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(selectedFileCategoriesButton, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.selectedFileCategoriesButton.text")); // NOI18N
|
|
||||||
selectedFileCategoriesButton.setToolTipText(org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.selectedFileCategoriesButton.toolTipText")); // NOI18N
|
|
||||||
selectedFileCategoriesButton.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
selectedFileCategoriesButtonActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
pictureVideoCheckbox.setSelected(true);
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(pictureVideoCheckbox, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.pictureVideoCheckbox.text")); // NOI18N
|
|
||||||
pictureVideoCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
pictureVideoCheckboxActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
documentsCheckbox.setSelected(true);
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(documentsCheckbox, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.documentsCheckbox.text")); // NOI18N
|
|
||||||
documentsCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
|
||||||
documentsCheckboxActionPerformed(evt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(dataSourceLabel, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.text")); // NOI18N
|
|
||||||
dataSourceLabel.setName(""); // NOI18N
|
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(categoriesLabel, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.categoriesLabel.text")); // NOI18N
|
|
||||||
categoriesLabel.setName(""); // NOI18N
|
|
||||||
|
|
||||||
errorText.setForeground(new java.awt.Color(255, 0, 0));
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(errorText, org.openide.util.NbBundle.getMessage(CommonFilesPanel.class, "CommonFilesPanel.errorText.text")); // NOI18N
|
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
|
||||||
this.setLayout(layout);
|
|
||||||
layout.setHorizontalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
|
||||||
.addComponent(errorText)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addComponent(searchButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(cancelButton)
|
|
||||||
.addContainerGap())
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(categoriesLabel)
|
|
||||||
.addComponent(commonFilesSearchLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addComponent(dataSourceLabel)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addGap(6, 6, 6)
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addGap(29, 29, 29)
|
|
||||||
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE))
|
|
||||||
.addComponent(withinDataSourceRadioButton)
|
|
||||||
.addComponent(allDataSourcesRadioButton)
|
|
||||||
.addComponent(allFileCategoriesRadioButton)
|
|
||||||
.addComponent(selectedFileCategoriesButton)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addGap(21, 21, 21)
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(pictureVideoCheckbox)
|
|
||||||
.addComponent(documentsCheckbox))))))
|
|
||||||
.addGap(19, 19, 19))))
|
|
||||||
);
|
|
||||||
layout.setVerticalGroup(
|
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
|
||||||
.addContainerGap()
|
|
||||||
.addComponent(commonFilesSearchLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(18, 18, 18)
|
|
||||||
.addComponent(dataSourceLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(allDataSourcesRadioButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(withinDataSourceRadioButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addGap(18, 18, 18)
|
|
||||||
.addComponent(categoriesLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(selectedFileCategoriesButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(pictureVideoCheckbox)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(documentsCheckbox)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(allFileCategoriesRadioButton)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
|
||||||
.addComponent(cancelButton)
|
|
||||||
.addComponent(searchButton)
|
|
||||||
.addComponent(errorText)))
|
|
||||||
);
|
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
|
||||||
|
|
||||||
private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
|
|
||||||
search();
|
|
||||||
SwingUtilities.windowForComponent(this).dispose();
|
|
||||||
}//GEN-LAST:event_searchButtonActionPerformed
|
|
||||||
|
|
||||||
private void allDataSourcesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allDataSourcesRadioButtonActionPerformed
|
|
||||||
selectDataSourceComboBox.setEnabled(!allDataSourcesRadioButton.isSelected());
|
|
||||||
singleDataSource = false;
|
|
||||||
}//GEN-LAST:event_allDataSourcesRadioButtonActionPerformed
|
|
||||||
|
|
||||||
private void selectDataSourceComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectDataSourceComboBoxActionPerformed
|
|
||||||
final Object selectedItem = selectDataSourceComboBox.getSelectedItem();
|
|
||||||
if (selectedItem != null) {
|
|
||||||
selectedDataSource = selectedItem.toString();
|
|
||||||
} else {
|
|
||||||
selectedDataSource = "";
|
|
||||||
}
|
|
||||||
}//GEN-LAST:event_selectDataSourceComboBoxActionPerformed
|
|
||||||
|
|
||||||
private void withinDataSourceRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_withinDataSourceRadioButtonActionPerformed
|
|
||||||
withinDataSourceSelected(withinDataSourceRadioButton.isSelected());
|
|
||||||
}//GEN-LAST:event_withinDataSourceRadioButtonActionPerformed
|
|
||||||
|
|
||||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
|
||||||
SwingUtilities.windowForComponent(this).dispose();
|
|
||||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
|
||||||
|
|
||||||
private void allFileCategoriesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allFileCategoriesRadioButtonActionPerformed
|
|
||||||
this.manageCheckBoxState();
|
|
||||||
this.toggleErrorTextAndSearchBox();
|
|
||||||
}//GEN-LAST:event_allFileCategoriesRadioButtonActionPerformed
|
|
||||||
|
|
||||||
private void selectedFileCategoriesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectedFileCategoriesButtonActionPerformed
|
|
||||||
this.manageCheckBoxState();
|
|
||||||
}//GEN-LAST:event_selectedFileCategoriesButtonActionPerformed
|
|
||||||
|
|
||||||
private void pictureVideoCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pictureVideoCheckboxActionPerformed
|
|
||||||
this.toggleErrorTextAndSearchBox();
|
|
||||||
}//GEN-LAST:event_pictureVideoCheckboxActionPerformed
|
|
||||||
|
|
||||||
private void documentsCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_documentsCheckboxActionPerformed
|
|
||||||
this.toggleErrorTextAndSearchBox();
|
|
||||||
}//GEN-LAST:event_documentsCheckboxActionPerformed
|
|
||||||
|
|
||||||
private void toggleErrorTextAndSearchBox() {
|
|
||||||
if (!this.pictureVideoCheckbox.isSelected() && !this.documentsCheckbox.isSelected() && !this.allFileCategoriesRadioButton.isSelected()) {
|
|
||||||
this.searchButton.setEnabled(false);
|
|
||||||
this.errorText.setVisible(true);
|
|
||||||
} else {
|
|
||||||
this.searchButton.setEnabled(true);
|
|
||||||
this.errorText.setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void withinDataSourceSelected(boolean selected) {
|
|
||||||
selectDataSourceComboBox.setEnabled(selected);
|
|
||||||
if (selectDataSourceComboBox.isEnabled()) {
|
|
||||||
selectDataSourceComboBox.setSelectedIndex(0);
|
|
||||||
singleDataSource = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void manageCheckBoxState() {
|
|
||||||
|
|
||||||
if (this.allFileCategoriesRadioButton.isSelected()) {
|
|
||||||
|
|
||||||
this.pictureViewCheckboxState = this.pictureVideoCheckbox.isSelected();
|
|
||||||
this.documentsCheckboxState = this.documentsCheckbox.isSelected();
|
|
||||||
|
|
||||||
this.pictureVideoCheckbox.setEnabled(false);
|
|
||||||
this.documentsCheckbox.setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.selectedFileCategoriesButton.isSelected()) {
|
|
||||||
|
|
||||||
this.pictureVideoCheckbox.setSelected(this.pictureViewCheckboxState);
|
|
||||||
this.documentsCheckbox.setSelected(this.documentsCheckboxState);
|
|
||||||
|
|
||||||
this.pictureVideoCheckbox.setEnabled(true);
|
|
||||||
this.documentsCheckbox.setEnabled(true);
|
|
||||||
|
|
||||||
this.toggleErrorTextAndSearchBox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
|
||||||
private javax.swing.JRadioButton allDataSourcesRadioButton;
|
|
||||||
private javax.swing.JRadioButton allFileCategoriesRadioButton;
|
|
||||||
private javax.swing.JButton cancelButton;
|
|
||||||
private javax.swing.JLabel categoriesLabel;
|
|
||||||
private javax.swing.JLabel commonFilesSearchLabel;
|
|
||||||
private javax.swing.JLabel dataSourceLabel;
|
|
||||||
private javax.swing.ButtonGroup dataSourcesButtonGroup;
|
|
||||||
private javax.swing.JCheckBox documentsCheckbox;
|
|
||||||
private javax.swing.JLabel errorText;
|
|
||||||
private javax.swing.ButtonGroup fileTypeFilterButtonGroup;
|
|
||||||
private javax.swing.JCheckBox pictureVideoCheckbox;
|
|
||||||
private javax.swing.JButton searchButton;
|
|
||||||
private javax.swing.JComboBox<String> selectDataSourceComboBox;
|
|
||||||
private javax.swing.JRadioButton selectedFileCategoriesButton;
|
|
||||||
private javax.swing.JRadioButton withinDataSourceRadioButton;
|
|
||||||
// End of variables declaration//GEN-END:variables
|
|
||||||
}
|
|
@ -24,6 +24,8 @@ import org.openide.util.HelpCtx;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
@ -32,9 +34,10 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
*/
|
*/
|
||||||
final public class CommonFilesSearchAction extends CallableSystemAction {
|
final public class CommonFilesSearchAction extends CallableSystemAction {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CommonFilesSearchAction.class.getName());
|
||||||
|
|
||||||
private static CommonFilesSearchAction instance = null;
|
private static CommonFilesSearchAction instance = null;
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(CommonFilesSearchAction.class.getName());
|
|
||||||
|
|
||||||
CommonFilesSearchAction() {
|
CommonFilesSearchAction() {
|
||||||
super();
|
super();
|
||||||
@ -45,9 +48,22 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
|
|||||||
public boolean isEnabled(){
|
public boolean isEnabled(){
|
||||||
boolean shouldBeEnabled = false;
|
boolean shouldBeEnabled = false;
|
||||||
try {
|
try {
|
||||||
shouldBeEnabled = Case.isCaseOpen() && Case.getCurrentCase().getDataSources().size() > 1;
|
//dont refactor any of this to pull out common expressions - order of evaluation of each expression is significant
|
||||||
|
shouldBeEnabled =
|
||||||
|
(Case.isCaseOpen() &&
|
||||||
|
Case.getCurrentCase().getDataSources().size() > 1)
|
||||||
|
||
|
||||||
|
(EamDb.isEnabled() &&
|
||||||
|
EamDb.getInstance() != null &&
|
||||||
|
EamDb.getInstance().getCases().size() > 1 &&
|
||||||
|
Case.isCaseOpen() &&
|
||||||
|
Case.getCurrentCase() != null &&
|
||||||
|
EamDb.getInstance().getCase(Case.getCurrentCase()) != null);
|
||||||
|
|
||||||
} catch(TskCoreException ex) {
|
} catch(TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Error getting data sources for action enabled check", ex);
|
LOGGER.log(Level.SEVERE, "Error getting data sources for action enabled check", ex);
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error getting CR cases for action enabled check", ex);
|
||||||
}
|
}
|
||||||
return super.isEnabled() && shouldBeEnabled;
|
return super.isEnabled() && shouldBeEnabled;
|
||||||
}
|
}
|
||||||
@ -61,12 +77,12 @@ final public class CommonFilesSearchAction extends CallableSystemAction {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent event) {
|
public void actionPerformed(ActionEvent event) {
|
||||||
new CommonFilesDialog().setVisible(true);
|
new CommonAttributePanel().setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performAction() {
|
public void performAction() {
|
||||||
new CommonFilesDialog().setVisible(true);
|
new CommonAttributePanel().setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
|
@ -30,7 +30,7 @@ public class DataSourceComboBoxModel extends AbstractListModel<String> implement
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final String[] dataSourceList;
|
private final String[] dataSourceList;
|
||||||
String selection = null;
|
private String selection = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this to initialize the panel
|
* Use this to initialize the panel
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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.commonfilesearch;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates data required to instantiate a <code>FileInstanceNode</code>.
|
|
||||||
*/
|
|
||||||
final public class FileInstanceMetadata {
|
|
||||||
|
|
||||||
private final Long objectId;
|
|
||||||
private final String dataSourceName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create meta data required to find an abstract file and build a FileInstanceNode.
|
|
||||||
* @param objectId id of abstract file to find
|
|
||||||
* @param dataSourceName name of datasource where the object is found
|
|
||||||
*/
|
|
||||||
FileInstanceMetadata(Long objectId, String dataSourceName) {
|
|
||||||
this.objectId = objectId;
|
|
||||||
this.dataSourceName = dataSourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* obj_id for the file represented by this object
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Long getObjectId(){
|
|
||||||
return this.objectId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of datasource where this instance was found.
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public String getDataSourceName(){
|
|
||||||
return this.dataSourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -40,24 +40,24 @@ import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
|||||||
final public class InstanceCountNode extends DisplayableItemNode {
|
final public class InstanceCountNode extends DisplayableItemNode {
|
||||||
|
|
||||||
final private int instanceCount;
|
final private int instanceCount;
|
||||||
final private List<Md5Metadata> metadataList;
|
final private List<CommonAttributeValue> attributeValues;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a node with the given number of instances, and the given
|
* Create a node with the given number of instances, and the given
|
||||||
* selection of metadata.
|
* selection of metadata.
|
||||||
* @param instanceCount
|
* @param instanceCount
|
||||||
* @param md5Metadata
|
* @param attributeValues
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"InstanceCountNode.displayName=Files with %s instances (%s)"
|
"InstanceCountNode.displayName=Files with %s instances (%s)"
|
||||||
})
|
})
|
||||||
public InstanceCountNode(int instanceCount, List<Md5Metadata> md5Metadata) {
|
public InstanceCountNode(int instanceCount, List<CommonAttributeValue> attributeValues) {
|
||||||
super(Children.create(new Md5NodeFactory(md5Metadata), true));
|
super(Children.create(new CommonAttributeValueNodeFactory(attributeValues), true));
|
||||||
|
|
||||||
this.instanceCount = instanceCount;
|
this.instanceCount = instanceCount;
|
||||||
this.metadataList = md5Metadata;
|
this.attributeValues = attributeValues;
|
||||||
|
|
||||||
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), md5Metadata.size()));
|
this.setDisplayName(String.format(Bundle.InstanceCountNode_displayName(), Integer.toString(instanceCount), attributeValues.size()));
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/fileset-icon-16.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,8 +73,8 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
|||||||
* Get a list of metadata for the MD5s which are children of this object.
|
* Get a list of metadata for the MD5s which are children of this object.
|
||||||
* @return List<Md5Metadata>
|
* @return List<Md5Metadata>
|
||||||
*/
|
*/
|
||||||
List<Md5Metadata> getMetadata() {
|
List<CommonAttributeValue> getAttributeValues() {
|
||||||
return Collections.unmodifiableList(this.metadataList);
|
return Collections.unmodifiableList(this.attributeValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -113,34 +113,36 @@ final public class InstanceCountNode extends DisplayableItemNode {
|
|||||||
* ChildFactory which builds CommonFileParentNodes from the
|
* ChildFactory which builds CommonFileParentNodes from the
|
||||||
* CommonFilesMetaaData models.
|
* CommonFilesMetaaData models.
|
||||||
*/
|
*/
|
||||||
static class Md5NodeFactory extends ChildFactory<String> {
|
static class CommonAttributeValueNodeFactory extends ChildFactory<String> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of models, each of which is a parent node matching a single md5,
|
* List of models, each of which is a parent node matching a single md5,
|
||||||
* containing children FileNodes.
|
* containing children FileNodes.
|
||||||
*/
|
*/
|
||||||
private final Map<String, Md5Metadata> metadata;
|
// maps sting version of value to value Object (??)
|
||||||
|
private final Map<String, CommonAttributeValue> metadata;
|
||||||
|
|
||||||
Md5NodeFactory(List<Md5Metadata> metadata) {
|
CommonAttributeValueNodeFactory(List<CommonAttributeValue> attributeValues) {
|
||||||
this.metadata = new HashMap<>();
|
this.metadata = new HashMap<>();
|
||||||
|
|
||||||
Iterator<Md5Metadata> iterator = metadata.iterator();
|
Iterator<CommonAttributeValue> iterator = attributeValues.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Md5Metadata md5Metadata = iterator.next();
|
CommonAttributeValue attributeValue = iterator.next();
|
||||||
this.metadata.put(md5Metadata.getMd5(), md5Metadata);
|
this.metadata.put(attributeValue.getValue(), attributeValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(String md5) {
|
|
||||||
Md5Metadata md5Metadata = this.metadata.get(md5);
|
|
||||||
return new Md5Node(md5Metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<String> list) {
|
protected boolean createKeys(List<String> list) {
|
||||||
|
// @@@ We should just use CommonAttributeValue as the key...
|
||||||
list.addAll(this.metadata.keySet());
|
list.addAll(this.metadata.keySet());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(String attributeValue) {
|
||||||
|
CommonAttributeValue md5Metadata = this.metadata.get(attributeValue);
|
||||||
|
return new CommonAttributeValueNode(md5Metadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides logic for selecting common files from all data sources and all cases
|
||||||
|
* in the Central Repo.
|
||||||
|
*/
|
||||||
|
abstract class InterCaseCommonAttributeSearcher extends AbstractCommonAttributeSearcher {
|
||||||
|
|
||||||
|
private final EamDb dbManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the algorithm for getting common files across all data sources
|
||||||
|
* and all cases. Can filter on mime types conjoined by logical AND.
|
||||||
|
*
|
||||||
|
* @param filterByMediaMimeType match only on files whose mime types can be
|
||||||
|
* broadly categorized as media types
|
||||||
|
* @param filterByDocMimeType match only on files whose mime types can be
|
||||||
|
* broadly categorized as document types
|
||||||
|
*
|
||||||
|
* @throws EamDbException
|
||||||
|
*/
|
||||||
|
InterCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) throws EamDbException {
|
||||||
|
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
|
||||||
|
dbManager = EamDb.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CorrelationCase getCorrelationCaseFromId(int correlationCaseId) throws EamDbException {
|
||||||
|
for (CorrelationCase cCase : this.dbManager.getCases()) {
|
||||||
|
if (cCase.getID() == correlationCaseId) {
|
||||||
|
return cCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Cannot locate case.");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<NonVisualComponents>
|
||||||
|
<Component class="javax.swing.ButtonGroup" name="buttonGroup">
|
||||||
|
</Component>
|
||||||
|
</NonVisualComponents>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="anyCentralRepoCaseRadio" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
|
||||||
|
<Component id="caseComboBox" min="-2" pref="261" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Component id="specificCentralRepoCaseRadio" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<Component id="anyCentralRepoCaseRadio" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="specificCentralRepoCaseRadio" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="caseComboBox" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="anyCentralRepoCaseRadio">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="buttonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.anyCentralRepoCaseRadio.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="anyCentralRepoCaseRadioActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="specificCentralRepoCaseRadio">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="buttonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="InterCasePanel.specificCentralRepoCaseRadio.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="specificCentralRepoCaseRadioActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JComboBox" name="caseComboBox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||||
|
<Connection code="casesList" type="code"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||||
|
</AuxValues>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import javax.swing.ComboBoxModel;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI controls for Common Files Search scenario where the user intends to find
|
||||||
|
* common files between cases in addition to the present case.
|
||||||
|
*/
|
||||||
|
public class InterCasePanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
static final int NO_CASE_SELECTED = -1;
|
||||||
|
|
||||||
|
private ComboBoxModel<String> casesList = new DataSourceComboBoxModel();
|
||||||
|
|
||||||
|
private final Map<Integer, String> caseMap;
|
||||||
|
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
//True if we are looking in any or all cases,
|
||||||
|
// false if we must find matches in a given case plus the current case
|
||||||
|
private boolean anyCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form InterCasePanel
|
||||||
|
*/
|
||||||
|
public InterCasePanel() {
|
||||||
|
initComponents();
|
||||||
|
this.errorMessage = "";
|
||||||
|
this.caseMap = new HashMap<>();
|
||||||
|
this.anyCase = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void specificCaseSelected(boolean selected) {
|
||||||
|
this.specificCentralRepoCaseRadio.setEnabled(selected);
|
||||||
|
if (this.specificCentralRepoCaseRadio.isEnabled()) {
|
||||||
|
this.caseComboBox.setEnabled(true);
|
||||||
|
this.caseComboBox.setSelectedIndex(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getErrorMessage(){
|
||||||
|
return this.errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
buttonGroup = new javax.swing.ButtonGroup();
|
||||||
|
anyCentralRepoCaseRadio = new javax.swing.JRadioButton();
|
||||||
|
specificCentralRepoCaseRadio = new javax.swing.JRadioButton();
|
||||||
|
caseComboBox = new javax.swing.JComboBox<>();
|
||||||
|
|
||||||
|
buttonGroup.add(anyCentralRepoCaseRadio);
|
||||||
|
anyCentralRepoCaseRadio.setSelected(true);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(anyCentralRepoCaseRadio, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.anyCentralRepoCaseRadio.text")); // NOI18N
|
||||||
|
anyCentralRepoCaseRadio.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
anyCentralRepoCaseRadioActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonGroup.add(specificCentralRepoCaseRadio);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(specificCentralRepoCaseRadio, org.openide.util.NbBundle.getMessage(InterCasePanel.class, "InterCasePanel.specificCentralRepoCaseRadio.text")); // NOI18N
|
||||||
|
specificCentralRepoCaseRadio.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
specificCentralRepoCaseRadioActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
caseComboBox.setModel(casesList);
|
||||||
|
caseComboBox.setEnabled(false);
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
|
this.setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(anyCentralRepoCaseRadio)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addGap(21, 21, 21)
|
||||||
|
.addComponent(caseComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
|
.addComponent(specificCentralRepoCaseRadio))
|
||||||
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addComponent(anyCentralRepoCaseRadio)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(specificCentralRepoCaseRadio)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(caseComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
|
);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void specificCentralRepoCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_specificCentralRepoCaseRadioActionPerformed
|
||||||
|
this.caseComboBox.setEnabled(true);
|
||||||
|
if(this.caseComboBox.isEnabled() && this.caseComboBox.getSelectedItem() == null){
|
||||||
|
this.caseComboBox.setSelectedIndex(0);
|
||||||
|
}
|
||||||
|
this.anyCase = false;
|
||||||
|
}//GEN-LAST:event_specificCentralRepoCaseRadioActionPerformed
|
||||||
|
|
||||||
|
private void anyCentralRepoCaseRadioActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_anyCentralRepoCaseRadioActionPerformed
|
||||||
|
this.caseComboBox.setEnabled(false);
|
||||||
|
this.anyCase = true;
|
||||||
|
}//GEN-LAST:event_anyCentralRepoCaseRadioActionPerformed
|
||||||
|
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JRadioButton anyCentralRepoCaseRadio;
|
||||||
|
private javax.swing.ButtonGroup buttonGroup;
|
||||||
|
private javax.swing.JComboBox<String> caseComboBox;
|
||||||
|
private javax.swing.JRadioButton specificCentralRepoCaseRadio;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
Map<Integer, String> getCaseMap() {
|
||||||
|
return Collections.unmodifiableMap(this.caseMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCaseList(DataSourceComboBoxModel dataSourceComboBoxModel) {
|
||||||
|
this.casesList = dataSourceComboBoxModel;
|
||||||
|
this.caseComboBox.setModel(dataSourceComboBoxModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rigForMultipleCases(boolean multipleCases) {
|
||||||
|
this.anyCentralRepoCaseRadio.setEnabled(multipleCases);
|
||||||
|
this.anyCentralRepoCaseRadio.setEnabled(multipleCases);
|
||||||
|
|
||||||
|
if(!multipleCases){
|
||||||
|
this.specificCentralRepoCaseRadio.setSelected(true);
|
||||||
|
this.specificCaseSelected(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCaseMap(Map<Integer, String> caseMap) {
|
||||||
|
this.caseMap.clear();
|
||||||
|
this.caseMap.putAll(caseMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean centralRepoHasMultipleCases() {
|
||||||
|
return this.caseMap.size() >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Integer getSelectedCaseId(){
|
||||||
|
if(this.anyCase){
|
||||||
|
return InterCasePanel.NO_CASE_SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Entry<Integer, String> entry : this.caseMap.entrySet()){
|
||||||
|
if(entry.getValue().equals(this.caseComboBox.getSelectedItem())){
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return InterCasePanel.NO_CASE_SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"InterCasePanel.showInterCaseErrorMessage.message=Cannot run intercase correlation search: no cases in Central Repository."
|
||||||
|
})
|
||||||
|
boolean areSearchCriteriaMet() {
|
||||||
|
if(this.caseMap.isEmpty()){
|
||||||
|
this.errorMessage = Bundle.InterCasePanel_showInterCaseErrorMessage_message();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.InstanceTableCallback;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
import org.sleuthkit.datamodel.HashUtility;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to process and return CorrelationCase md5s from the EamDB for
|
||||||
|
* CommonFilesSearch.
|
||||||
|
*/
|
||||||
|
final class InterCaseSearchResultsProcessor {
|
||||||
|
|
||||||
|
private Map<Long, String> dataSources;
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(CommonAttributePanel.class.getName());
|
||||||
|
|
||||||
|
private final String interCaseWhereClause = "value IN (SELECT value FROM file_instances"
|
||||||
|
+ " WHERE value IN (SELECT value FROM file_instances"
|
||||||
|
+ " WHERE case_id=%s AND (known_status !=%s OR known_status IS NULL) GROUP BY value)"
|
||||||
|
+ " GROUP BY value HAVING COUNT(DISTINCT case_id) > 1) ORDER BY value";
|
||||||
|
|
||||||
|
private final String singleInterCaseWhereClause = "value IN (SELECT value FROM file_instances "
|
||||||
|
+ "WHERE value IN (SELECT value FROM file_instances "
|
||||||
|
+ "WHERE case_id=%s AND (known_status !=%s OR known_status IS NULL) GROUP BY value) "
|
||||||
|
+ "AND (case_id=%s OR case_id=%s) GROUP BY value HAVING COUNT(DISTINCT case_id) > 1) ORDER BY value";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in the InterCaseCommonAttributeSearchers to find common attribute instances and generate nodes at the UI level.
|
||||||
|
* @param dataSources
|
||||||
|
*/
|
||||||
|
InterCaseSearchResultsProcessor(Map<Long, String> dataSources){
|
||||||
|
this.dataSources = dataSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used in the CentralRepoCommonAttributeInstance to find common attribute instances and generate nodes at the UI level.
|
||||||
|
*/
|
||||||
|
InterCaseSearchResultsProcessor(){
|
||||||
|
//intentionally emtpy - we need a constructor which does not set the data sources field
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a single CorrelationAttribute given an id.
|
||||||
|
*
|
||||||
|
* @param attrbuteId Row of CorrelationAttribute to retrieve from the EamDb
|
||||||
|
* @return CorrelationAttribute object representation of retrieved match
|
||||||
|
*/
|
||||||
|
CorrelationAttribute findSingleCorrelationAttribute(int attrbuteId) {
|
||||||
|
try {
|
||||||
|
InterCaseCommonAttributeRowCallback instancetableCallback = new InterCaseCommonAttributeRowCallback();
|
||||||
|
EamDb DbManager = EamDb.getInstance();
|
||||||
|
CorrelationAttribute.Type fileType = DbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
|
||||||
|
DbManager.processInstanceTableWhere(fileType, String.format("id = %s", attrbuteId), instancetableCallback);
|
||||||
|
|
||||||
|
return instancetableCallback.getCorrelationAttribute();
|
||||||
|
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error accessing EamDb processing InstanceTable row.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the current case, fins all intercase common files from the EamDb
|
||||||
|
* and builds maps of obj id to md5 and case.
|
||||||
|
*
|
||||||
|
* @param currentCase The current TSK Case.
|
||||||
|
*/
|
||||||
|
Map<Integer, List<CommonAttributeValue>> findInterCaseCommonAttributeValues(Case currentCase) {
|
||||||
|
try {
|
||||||
|
InterCaseCommonAttributesCallback instancetableCallback = new InterCaseCommonAttributesCallback();
|
||||||
|
EamDb DbManager = EamDb.getInstance();
|
||||||
|
CorrelationAttribute.Type fileType = DbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
|
||||||
|
int caseId = DbManager.getCase(currentCase).getID();
|
||||||
|
|
||||||
|
DbManager.processInstanceTableWhere(fileType, String.format(interCaseWhereClause, caseId,
|
||||||
|
TskData.FileKnown.KNOWN.getFileKnownValue()),
|
||||||
|
instancetableCallback);
|
||||||
|
|
||||||
|
return instancetableCallback.getInstanceCollatedCommonFiles();
|
||||||
|
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error accessing EamDb processing CaseInstancesTable.", ex);
|
||||||
|
}
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the current case, and a specific case of interest, finds common
|
||||||
|
* files which exist between cases from the EamDb. Builds maps of obj id to
|
||||||
|
* md5 and case.
|
||||||
|
*
|
||||||
|
* @param currentCase The current TSK Case.
|
||||||
|
* @param singleCase The case of interest. Matches must exist in this case.
|
||||||
|
*/
|
||||||
|
Map<Integer, List<CommonAttributeValue>> findSingleInterCaseCommonAttributeValues(Case currentCase, CorrelationCase singleCase) {
|
||||||
|
try {
|
||||||
|
InterCaseCommonAttributesCallback instancetableCallback = new InterCaseCommonAttributesCallback();
|
||||||
|
EamDb DbManager = EamDb.getInstance();
|
||||||
|
CorrelationAttribute.Type fileType = DbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
|
||||||
|
int caseId = DbManager.getCase(currentCase).getID();
|
||||||
|
int targetCaseId = singleCase.getID();
|
||||||
|
DbManager.processInstanceTableWhere(fileType, String.format(singleInterCaseWhereClause, caseId,
|
||||||
|
TskData.FileKnown.KNOWN.getFileKnownValue(), caseId, targetCaseId), instancetableCallback);
|
||||||
|
return instancetableCallback.getInstanceCollatedCommonFiles();
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error accessing EamDb processing CaseInstancesTable.", ex);
|
||||||
|
}
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to use with findInterCaseCommonAttributeValues which generates a
|
||||||
|
* list of md5s for common files search
|
||||||
|
*/
|
||||||
|
private class InterCaseCommonAttributesCallback implements InstanceTableCallback {
|
||||||
|
|
||||||
|
final Map<Integer, List<CommonAttributeValue>> instanceCollatedCommonFiles = new HashMap<>();
|
||||||
|
|
||||||
|
private CommonAttributeValue commonAttributeValue = null;
|
||||||
|
private String previousRowMd5 = "";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(ResultSet resultSet) {
|
||||||
|
try {
|
||||||
|
while (resultSet.next()) {
|
||||||
|
|
||||||
|
int resultId = InstanceTableCallback.getId(resultSet);
|
||||||
|
String md5Value = InstanceTableCallback.getValue(resultSet);
|
||||||
|
if (previousRowMd5.isEmpty()) {
|
||||||
|
previousRowMd5 = md5Value;
|
||||||
|
}
|
||||||
|
if (md5Value == null || HashUtility.isNoDataMd5(md5Value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
countAndAddCommonAttributes(md5Value, resultId);
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error getting artifact instances from database.", ex); // NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void countAndAddCommonAttributes(String md5Value, int resultId) {
|
||||||
|
if (commonAttributeValue == null) {
|
||||||
|
commonAttributeValue = new CommonAttributeValue(md5Value);
|
||||||
|
}
|
||||||
|
if (!md5Value.equals(previousRowMd5)) {
|
||||||
|
int size = commonAttributeValue.getInstanceCount();
|
||||||
|
if (instanceCollatedCommonFiles.containsKey(size)) {
|
||||||
|
instanceCollatedCommonFiles.get(size).add(commonAttributeValue);
|
||||||
|
} else {
|
||||||
|
ArrayList<CommonAttributeValue> value = new ArrayList<>();
|
||||||
|
value.add(commonAttributeValue);
|
||||||
|
instanceCollatedCommonFiles.put(size, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
commonAttributeValue = new CommonAttributeValue(md5Value);
|
||||||
|
previousRowMd5 = md5Value;
|
||||||
|
}
|
||||||
|
// we don't *have* all the information for the rows in the CR,
|
||||||
|
// so we need to consult the present case via the SleuthkitCase object
|
||||||
|
// Later, when the FileInstanceNode is built. Therefore, build node generators for now.
|
||||||
|
AbstractCommonAttributeInstance searchResult = new CentralRepoCommonAttributeInstance(resultId, InterCaseSearchResultsProcessor.this.dataSources);
|
||||||
|
commonAttributeValue.addInstance(searchResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, List<CommonAttributeValue>> getInstanceCollatedCommonFiles() {
|
||||||
|
return Collections.unmodifiableMap(instanceCollatedCommonFiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to use with findSingleCorrelationAttribute which retrieves a
|
||||||
|
* single CorrelationAttribute from the EamDb.
|
||||||
|
*/
|
||||||
|
private class InterCaseCommonAttributeRowCallback implements InstanceTableCallback {
|
||||||
|
|
||||||
|
CorrelationAttribute correlationAttribute = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(ResultSet resultSet) {
|
||||||
|
try {
|
||||||
|
EamDb DbManager = EamDb.getInstance();
|
||||||
|
CorrelationAttribute.Type fileType = DbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
|
||||||
|
|
||||||
|
while (resultSet.next()) {
|
||||||
|
CorrelationCase correlationCase = DbManager.getCaseById(InstanceTableCallback.getCaseId(resultSet));
|
||||||
|
CorrelationDataSource dataSource = DbManager.getDataSourceById(correlationCase, InstanceTableCallback.getDataSourceId(resultSet));
|
||||||
|
correlationAttribute = DbManager.getCorrelationAttribute(fileType,
|
||||||
|
correlationCase,
|
||||||
|
dataSource,
|
||||||
|
InstanceTableCallback.getValue(resultSet),
|
||||||
|
InstanceTableCallback.getFilePath(resultSet));
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (SQLException | EamDbException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error getting single correlation artifact instance from database.", ex); // NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CorrelationAttribute getCorrelationAttribute() {
|
||||||
|
return correlationAttribute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.datamodel.HashUtility;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase.CaseDbQuery;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Generates a <code>List<CommonFilesMetadata></code> when
|
||||||
|
* <code>findFiles()</code> is called, which organizes files by md5 to
|
||||||
|
* prepare to display in viewer.
|
||||||
|
*
|
||||||
|
* This entire thing runs on a background thread where exceptions are handled.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.AbstractNaming")
|
||||||
|
public abstract class IntraCaseCommonAttributeSearcher extends AbstractCommonAttributeSearcher {
|
||||||
|
|
||||||
|
private static final String FILTER_BY_MIME_TYPES_WHERE_CLAUSE = " and mime_type in (%s)"; //NON-NLS // where %s is csv list of mime_types to filter on
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclass this to implement different algorithms for getting common files.
|
||||||
|
*
|
||||||
|
* @param dataSourceIdMap a map of obj_id to datasource name
|
||||||
|
* @param filterByMediaMimeType match only on files whose mime types can be
|
||||||
|
* broadly categorized as media types
|
||||||
|
* @param filterByDocMimeType match only on files whose mime types can be
|
||||||
|
* broadly categorized as document types
|
||||||
|
*/
|
||||||
|
IntraCaseCommonAttributeSearcher(Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
|
||||||
|
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this as a prefix when building the SQL select statement.
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>You only have to specify the WHERE clause if you use this.</li>
|
||||||
|
* <li>If you do not use this string, you must use at least the columns
|
||||||
|
* selected below, in that order.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
static final String SELECT_PREFIX = "SELECT obj_id, md5, data_source_obj_id from tsk_files where"; //NON-NLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should build a SQL SELECT statement to be passed to
|
||||||
|
* SleuthkitCase.executeQuery(sql) which will select the desired file ids
|
||||||
|
* and MD5 hashes.
|
||||||
|
*
|
||||||
|
* The statement should select obj_id, md5, data_source_obj_id in that
|
||||||
|
* order.
|
||||||
|
*
|
||||||
|
* @return sql string select statement
|
||||||
|
*/
|
||||||
|
protected abstract String buildSqlSelectStatement();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a meta data object which encapsulates everything need to add the
|
||||||
|
* tree table tab to the top component.
|
||||||
|
*
|
||||||
|
* @return a data object with all of the matched files in a hierarchical
|
||||||
|
* format
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws NoCurrentCaseException
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CommonAttributeSearchResults findFiles() throws TskCoreException, NoCurrentCaseException, SQLException {
|
||||||
|
Map<String, CommonAttributeValue> commonFiles = new HashMap<>();
|
||||||
|
|
||||||
|
final Case currentCase = Case.getCurrentCaseThrows();
|
||||||
|
final String caseName = currentCase.getDisplayName();
|
||||||
|
|
||||||
|
SleuthkitCase sleuthkitCase = currentCase.getSleuthkitCase();
|
||||||
|
|
||||||
|
String selectStatement = this.buildSqlSelectStatement();
|
||||||
|
|
||||||
|
try (
|
||||||
|
CaseDbQuery query = sleuthkitCase.executeQuery(selectStatement);
|
||||||
|
ResultSet resultSet = query.getResultSet()) {
|
||||||
|
|
||||||
|
while (resultSet.next()) {
|
||||||
|
Long objectId = resultSet.getLong(1);
|
||||||
|
String md5 = resultSet.getString(2);
|
||||||
|
Long dataSourceId = resultSet.getLong(3);
|
||||||
|
String dataSource = this.getDataSourceIdToNameMap().get(dataSourceId);
|
||||||
|
|
||||||
|
if (md5 == null || HashUtility.isNoDataMd5(md5)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commonFiles.containsKey(md5)) {
|
||||||
|
final CommonAttributeValue commonAttributeValue = commonFiles.get(md5);
|
||||||
|
commonAttributeValue.addInstance(new CaseDBCommonAttributeInstance(objectId, dataSource, caseName));
|
||||||
|
} else {
|
||||||
|
final CommonAttributeValue commonAttributeValue = new CommonAttributeValue(md5);
|
||||||
|
commonAttributeValue.addInstance(new CaseDBCommonAttributeInstance(objectId, dataSource, caseName));
|
||||||
|
commonFiles.put(md5, commonAttributeValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, List<CommonAttributeValue>> instanceCollatedCommonFiles = collateMatchesByNumberOfInstances(commonFiles);
|
||||||
|
|
||||||
|
return new CommonAttributeSearchResults(instanceCollatedCommonFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be used by subclasses, in their
|
||||||
|
* <code>buildSqlSelectStatement()</code> function to create an SQL boolean
|
||||||
|
* expression which will filter our matches based on mime type. The
|
||||||
|
* expression will be conjoined to base query with an AND operator.
|
||||||
|
*
|
||||||
|
* @return sql fragment of the form:
|
||||||
|
* 'and "mime_type" in ( [comma delimited list of mime types] )'
|
||||||
|
* or empty string in the event that no types to filter on were given.
|
||||||
|
*/
|
||||||
|
String determineMimeTypeFilter() {
|
||||||
|
|
||||||
|
Set<String> mimeTypesToFilterOn = new HashSet<>();
|
||||||
|
String mimeTypeString = "";
|
||||||
|
if (isFilterByMedia()) {
|
||||||
|
mimeTypesToFilterOn.addAll(MEDIA_PICS_VIDEO_MIME_TYPES);
|
||||||
|
}
|
||||||
|
if (isFilterByDoc()) {
|
||||||
|
mimeTypesToFilterOn.addAll(TEXT_FILES_MIME_TYPES);
|
||||||
|
}
|
||||||
|
StringBuilder mimeTypeFilter = new StringBuilder(mimeTypesToFilterOn.size());
|
||||||
|
if (!mimeTypesToFilterOn.isEmpty()) {
|
||||||
|
for (String mimeType : mimeTypesToFilterOn) {
|
||||||
|
mimeTypeFilter.append(SINGLE_QUOTE).append(mimeType).append(SINGLE_QUTOE_COMMA);
|
||||||
|
}
|
||||||
|
mimeTypeString = mimeTypeFilter.toString().substring(0, mimeTypeFilter.length() - 1);
|
||||||
|
mimeTypeString = String.format(FILTER_BY_MIME_TYPES_WHERE_CLAUSE, new Object[]{mimeTypeString});
|
||||||
|
}
|
||||||
|
return mimeTypeString;
|
||||||
|
}
|
||||||
|
static final String SINGLE_QUTOE_COMMA = "',";
|
||||||
|
static final String SINGLE_QUOTE = "'";
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<NonVisualComponents>
|
||||||
|
<Component class="javax.swing.ButtonGroup" name="buttonGroup">
|
||||||
|
</Component>
|
||||||
|
</NonVisualComponents>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
|
||||||
|
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||||
|
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||||
|
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||||
|
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="allDataSourcesRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="withinDataSourceRadioButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
|
||||||
|
<Component id="selectDataSourceComboBox" min="-2" pref="261" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<Component id="allDataSourcesRadioButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="withinDataSourceRadioButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="selectDataSourceComboBox" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
</Layout>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="allDataSourcesRadioButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="buttonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.allDataSourcesRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="allDataSourcesRadioButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JRadioButton" name="withinDataSourceRadioButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
|
||||||
|
<ComponentRef name="buttonGroup"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/commonfilesearch/Bundle.properties" key="IntraCasePanel.withinDataSourceRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="withinDataSourceRadioButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JComboBox" name="selectDataSourceComboBox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||||
|
<Connection code="dataSourcesList" type="code"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="selectDataSourceComboBoxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||||
|
</AuxValues>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import javax.swing.ComboBoxModel;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UI controls for Common Files Search scenario where the user intends to find
|
||||||
|
* common files between datasources. It is an inner panel which provides the ability
|
||||||
|
* to select all datasources or a single datasource from a dropdown list of
|
||||||
|
* sources in the current case.
|
||||||
|
*/
|
||||||
|
public class IntraCasePanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
static final long NO_DATA_SOURCE_SELECTED = -1;
|
||||||
|
|
||||||
|
private boolean singleDataSource;
|
||||||
|
private ComboBoxModel<String> dataSourcesList = new DataSourceComboBoxModel();
|
||||||
|
private final Map<Long, String> dataSourceMap;
|
||||||
|
|
||||||
|
private String errorMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new form IntraCasePanel
|
||||||
|
*/
|
||||||
|
public IntraCasePanel() {
|
||||||
|
initComponents();
|
||||||
|
this.errorMessage = "";
|
||||||
|
this.dataSourceMap = new HashMap<>();
|
||||||
|
this.singleDataSource = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Long, String> getDataSourceMap(){
|
||||||
|
return Collections.unmodifiableMap(this.dataSourceMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long getSelectedDataSourceId(){
|
||||||
|
if(!this.singleDataSource){
|
||||||
|
return IntraCasePanel.NO_DATA_SOURCE_SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Entry<Long, String> entry : this.dataSourceMap.entrySet()){
|
||||||
|
if(entry.getValue().equals(this.selectDataSourceComboBox.getSelectedItem())){
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return IntraCasePanel.NO_DATA_SOURCE_SELECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called from within the constructor to initialize the form.
|
||||||
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
|
* regenerated by the Form Editor.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
|
private void initComponents() {
|
||||||
|
|
||||||
|
buttonGroup = new javax.swing.ButtonGroup();
|
||||||
|
allDataSourcesRadioButton = new javax.swing.JRadioButton();
|
||||||
|
withinDataSourceRadioButton = new javax.swing.JRadioButton();
|
||||||
|
selectDataSourceComboBox = new javax.swing.JComboBox<>();
|
||||||
|
|
||||||
|
buttonGroup.add(allDataSourcesRadioButton);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(allDataSourcesRadioButton, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.allDataSourcesRadioButton.text")); // NOI18N
|
||||||
|
allDataSourcesRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||||
|
allDataSourcesRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
allDataSourcesRadioButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttonGroup.add(withinDataSourceRadioButton);
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(withinDataSourceRadioButton, org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.withinDataSourceRadioButton.text")); // NOI18N
|
||||||
|
withinDataSourceRadioButton.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||||
|
withinDataSourceRadioButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
withinDataSourceRadioButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
selectDataSourceComboBox.setModel(dataSourcesList);
|
||||||
|
selectDataSourceComboBox.setActionCommand(org.openide.util.NbBundle.getMessage(IntraCasePanel.class, "IntraCasePanel.selectDataSourceComboBox.actionCommand")); // NOI18N
|
||||||
|
selectDataSourceComboBox.setEnabled(false);
|
||||||
|
|
||||||
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
|
this.setLayout(layout);
|
||||||
|
layout.setHorizontalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addContainerGap()
|
||||||
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(allDataSourcesRadioButton)
|
||||||
|
.addComponent(withinDataSourceRadioButton)))
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addGap(27, 27, 27)
|
||||||
|
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||||
|
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
|
);
|
||||||
|
layout.setVerticalGroup(
|
||||||
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(layout.createSequentialGroup()
|
||||||
|
.addComponent(allDataSourcesRadioButton)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(withinDataSourceRadioButton)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(selectDataSourceComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
|
);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void allDataSourcesRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allDataSourcesRadioButtonActionPerformed
|
||||||
|
selectDataSourceComboBox.setEnabled(!allDataSourcesRadioButton.isSelected());
|
||||||
|
singleDataSource = false;
|
||||||
|
}//GEN-LAST:event_allDataSourcesRadioButtonActionPerformed
|
||||||
|
|
||||||
|
private void withinDataSourceRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_withinDataSourceRadioButtonActionPerformed
|
||||||
|
withinDataSourceSelected(withinDataSourceRadioButton.isSelected());
|
||||||
|
}//GEN-LAST:event_withinDataSourceRadioButtonActionPerformed
|
||||||
|
|
||||||
|
private void withinDataSourceSelected(boolean selected) {
|
||||||
|
selectDataSourceComboBox.setEnabled(selected);
|
||||||
|
if (selectDataSourceComboBox.isEnabled()) {
|
||||||
|
selectDataSourceComboBox.setSelectedIndex(0);
|
||||||
|
singleDataSource = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JRadioButton allDataSourcesRadioButton;
|
||||||
|
private javax.swing.ButtonGroup buttonGroup;
|
||||||
|
private javax.swing.JComboBox<String> selectDataSourceComboBox;
|
||||||
|
private javax.swing.JRadioButton withinDataSourceRadioButton;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
|
void setDataModel(DataSourceComboBoxModel dataSourceComboBoxModel) {
|
||||||
|
this.dataSourcesList = dataSourceComboBoxModel;
|
||||||
|
this.selectDataSourceComboBox.setModel(dataSourcesList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rigForMultipleDataSources(boolean multipleDataSources) {
|
||||||
|
this.withinDataSourceRadioButton.setEnabled(multipleDataSources);
|
||||||
|
this.allDataSourcesRadioButton.setSelected(!multipleDataSources);
|
||||||
|
this.withinDataSourceRadioButton.setSelected(multipleDataSources);
|
||||||
|
this.withinDataSourceSelected(multipleDataSources);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDataSourceMap(Map<Long, String> dataSourceMap) {
|
||||||
|
this.dataSourceMap.clear();
|
||||||
|
this.dataSourceMap.putAll(dataSourceMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"IntraCasePanel.areSearchCriteriaMet.message=Cannot run intra-case correlation search."
|
||||||
|
})
|
||||||
|
boolean areSearchCriteriaMet() {
|
||||||
|
if(this.dataSourceMap.isEmpty()){
|
||||||
|
this.errorMessage = Bundle.IntraCasePanel_areSearchCriteriaMet_message();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getErrorMessage() {
|
||||||
|
return this.errorMessage;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilesearch;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SingleInterCaseCommonAttributeSearcher extends InterCaseCommonAttributeSearcher {
|
||||||
|
|
||||||
|
private final int corrleationCaseId;
|
||||||
|
private String correlationCaseName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param correlationCaseId
|
||||||
|
* @param filterByMediaMimeType
|
||||||
|
* @param filterByDocMimeType
|
||||||
|
* @throws EamDbException
|
||||||
|
*/
|
||||||
|
public SingleInterCaseCommonAttributeSearcher(int correlationCaseId, Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) throws EamDbException {
|
||||||
|
super(dataSourceIdMap,filterByMediaMimeType, filterByDocMimeType);
|
||||||
|
|
||||||
|
this.corrleationCaseId = correlationCaseId;
|
||||||
|
this.correlationCaseName = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collect metadata required to render the tree table where matches must
|
||||||
|
* occur in the case with the given ID.
|
||||||
|
*
|
||||||
|
* @param correlationCaseId id of case where matches must occur (no other matches will be shown)
|
||||||
|
* @return business object needed to populate tree table with results
|
||||||
|
* @throws TskCoreException
|
||||||
|
* @throws NoCurrentCaseException
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws EamDbException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CommonAttributeSearchResults findFiles() throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
|
||||||
|
|
||||||
|
CorrelationCase cCase = this.getCorrelationCaseFromId(this.corrleationCaseId);
|
||||||
|
correlationCaseName = cCase.getDisplayName();
|
||||||
|
return this.findFiles(cCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommonAttributeSearchResults findFiles(CorrelationCase correlationCase) throws TskCoreException, NoCurrentCaseException, SQLException, EamDbException {
|
||||||
|
InterCaseSearchResultsProcessor eamDbAttrInst = new InterCaseSearchResultsProcessor(this.getDataSourceIdToNameMap());
|
||||||
|
Map<Integer, List<CommonAttributeValue>> interCaseCommonFiles = eamDbAttrInst.findSingleInterCaseCommonAttributeValues(Case.getCurrentCase(), correlationCase);
|
||||||
|
|
||||||
|
return new CommonAttributeSearchResults(interCaseCommonFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String buildTabTitle() {
|
||||||
|
final String buildCategorySelectionString = this.buildCategorySelectionString();
|
||||||
|
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleInterSingle();
|
||||||
|
return String.format(titleTemplate, new Object[]{correlationCaseName, buildCategorySelectionString});
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ import org.sleuthkit.datamodel.TskData.FileKnown;
|
|||||||
/**
|
/**
|
||||||
* Provides logic for selecting common files from a single data source.
|
* Provides logic for selecting common files from a single data source.
|
||||||
*/
|
*/
|
||||||
final public class SingleDataSource extends CommonFilesMetadataBuilder {
|
final public class SingleIntraCaseCommonAttributeSearcher extends IntraCaseCommonAttributeSearcher {
|
||||||
|
|
||||||
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL) and data_source_obj_id=%s%s) GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
|
private static final String WHERE_CLAUSE = "%s md5 in (select md5 from tsk_files where md5 in (select md5 from tsk_files where (known != "+ FileKnown.KNOWN.getFileKnownValue() + " OR known IS NULL) and data_source_obj_id=%s%s) GROUP BY md5 HAVING COUNT(DISTINCT data_source_obj_id) > 1) order by md5"; //NON-NLS
|
||||||
private final Long selectedDataSourceId;
|
private final Long selectedDataSourceId;
|
||||||
@ -41,7 +41,7 @@ final public class SingleDataSource extends CommonFilesMetadataBuilder {
|
|||||||
* @param filterByDocMimeType match only on files whose mime types can be
|
* @param filterByDocMimeType match only on files whose mime types can be
|
||||||
* broadly categorized as document types
|
* broadly categorized as document types
|
||||||
*/
|
*/
|
||||||
public SingleDataSource(Long dataSourceId, Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
|
public SingleIntraCaseCommonAttributeSearcher(Long dataSourceId, Map<Long, String> dataSourceIdMap, boolean filterByMediaMimeType, boolean filterByDocMimeType) {
|
||||||
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
|
super(dataSourceIdMap, filterByMediaMimeType, filterByDocMimeType);
|
||||||
this.selectedDataSourceId = dataSourceId;
|
this.selectedDataSourceId = dataSourceId;
|
||||||
this.dataSourceName = dataSourceIdMap.get(this.selectedDataSourceId);
|
this.dataSourceName = dataSourceIdMap.get(this.selectedDataSourceId);
|
||||||
@ -50,13 +50,13 @@ final public class SingleDataSource extends CommonFilesMetadataBuilder {
|
|||||||
@Override
|
@Override
|
||||||
protected String buildSqlSelectStatement() {
|
protected String buildSqlSelectStatement() {
|
||||||
Object[] args = new String[]{SELECT_PREFIX, Long.toString(this.selectedDataSourceId), determineMimeTypeFilter()};
|
Object[] args = new String[]{SELECT_PREFIX, Long.toString(this.selectedDataSourceId), determineMimeTypeFilter()};
|
||||||
return String.format(SingleDataSource.WHERE_CLAUSE, args);
|
return String.format(SingleIntraCaseCommonAttributeSearcher.WHERE_CLAUSE, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String buildTabTitle() {
|
public String buildTabTitle() {
|
||||||
final String buildCategorySelectionString = this.buildCategorySelectionString();
|
final String buildCategorySelectionString = this.buildCategorySelectionString();
|
||||||
final String titleTemplate = Bundle.CommonFilesMetadataBuilder_buildTabTitle_titleSingle();
|
final String titleTemplate = Bundle.AbstractCommonFilesMetadataBuilder_buildTabTitle_titleIntraSingle();
|
||||||
return String.format(titleTemplate, new Object[]{this.dataSourceName, buildCategorySelectionString});
|
return String.format(titleTemplate, new Object[]{this.dataSourceName, buildCategorySelectionString});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -18,10 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesNode;
|
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceNode;
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResultRootNode;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
|
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.Md5Node;
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueNode;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CaseDBCommonAttributeInstanceNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
|
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
|
import org.sleuthkit.autopsy.datamodel.FileSize.FileSizeRootChildren.FileSizeNode;
|
||||||
@ -115,11 +116,13 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
|
|
||||||
T visit(InterestingHits.SetNameNode ihsn);
|
T visit(InterestingHits.SetNameNode ihsn);
|
||||||
|
|
||||||
T visit(Md5Node mn);
|
T visit(CommonAttributeValueNode cavn);
|
||||||
|
|
||||||
T visit(CommonFilesNode cfn);
|
T visit(CommonAttributeSearchResultRootNode cfn);
|
||||||
|
|
||||||
T visit(FileInstanceNode fin);
|
T visit(CaseDBCommonAttributeInstanceNode fin);
|
||||||
|
|
||||||
|
T visit(CentralRepoCommonAttributeInstanceNode crfin);
|
||||||
|
|
||||||
T visit(InstanceCountNode icn);
|
T visit(InstanceCountNode icn);
|
||||||
|
|
||||||
@ -192,17 +195,17 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
protected abstract T defaultVisit(DisplayableItemNode c);
|
protected abstract T defaultVisit(DisplayableItemNode c);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(FileInstanceNode fin) {
|
public T visit(CaseDBCommonAttributeInstanceNode fin) {
|
||||||
return defaultVisit(fin);
|
return defaultVisit(fin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(Md5Node mn) {
|
public T visit(CommonAttributeValueNode cavn) {
|
||||||
return defaultVisit(mn);
|
return defaultVisit(cavn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(CommonFilesNode cfn) {
|
public T visit(CommonAttributeSearchResultRootNode cfn) {
|
||||||
return defaultVisit(cfn);
|
return defaultVisit(cfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +213,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
public T visit(InstanceCountNode icn){
|
public T visit(InstanceCountNode icn){
|
||||||
return defaultVisit(icn);
|
return defaultVisit(icn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(CentralRepoCommonAttributeInstanceNode crfin){
|
||||||
|
return defaultVisit(crfin);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(DirectoryNode dn) {
|
public T visit(DirectoryNode dn) {
|
||||||
|
@ -27,7 +27,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class FileTypeExtensions {
|
public class FileTypeExtensions {
|
||||||
|
|
||||||
private final static List<String> IMAGE_EXTENSIONS = Arrays.asList(".jpg", ".jpeg", ".png", ".psd", ".nef", ".tiff", ".bmp", ".tec"); //NON-NLS
|
private final static List<String> IMAGE_EXTENSIONS = Arrays.asList(".jpg", ".jpeg", ".png", ".psd", ".nef", ".tiff", ".bmp", ".tec", ".tif"); //NON-NLS
|
||||||
private final static List<String> VIDEO_EXTENSIONS = Arrays.asList(".aaf", ".3gp", ".asf", ".avi", ".m1v", ".m2v", //NON-NLS
|
private final static List<String> VIDEO_EXTENSIONS = Arrays.asList(".aaf", ".3gp", ".asf", ".avi", ".m1v", ".m2v", //NON-NLS
|
||||||
".m4v", ".mp4", ".mov", ".mpeg", ".mpg", ".mpe", ".mp4", ".rm", ".wmv", ".mpv", ".flv", ".swf"); //NON-NLS
|
".m4v", ".mp4", ".mov", ".mpeg", ".mpg", ".mpe", ".mp4", ".rm", ".wmv", ".mpv", ".flv", ".swf"); //NON-NLS
|
||||||
private final static List<String> AUDIO_EXTENSIONS = Arrays.asList(".aiff", ".aif", ".flac", ".wav", ".m4a", ".ape", //NON-NLS
|
private final static List<String> AUDIO_EXTENSIONS = Arrays.asList(".aiff", ".aif", ".flac", ".wav", ".m4a", ".ape", //NON-NLS
|
||||||
|
@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
|||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceNode;
|
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -56,15 +55,17 @@ import org.sleuthkit.autopsy.datamodel.FileNode;
|
|||||||
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
|
import org.sleuthkit.autopsy.datamodel.FileTypeExtensions;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
|
import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesNode;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
|
import org.sleuthkit.autopsy.commonfilesearch.InstanceCountNode;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.Md5Node;
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValueNode;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode;
|
import org.sleuthkit.autopsy.datamodel.LocalDirectoryNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
|
import org.sleuthkit.autopsy.datamodel.NodeSelectionInfo;
|
||||||
import org.sleuthkit.autopsy.datamodel.Reports;
|
import org.sleuthkit.autopsy.datamodel.Reports;
|
||||||
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
|
import org.sleuthkit.autopsy.datamodel.SlackFileNode;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CaseDBCommonAttributeInstanceNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
|
import org.sleuthkit.autopsy.datamodel.VirtualDirectoryNode;
|
||||||
import static org.sleuthkit.autopsy.directorytree.Bundle.*;
|
import static org.sleuthkit.autopsy.directorytree.Bundle.DataResultFilterNode_viewSourceArtifact_text;
|
||||||
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
import org.sleuthkit.autopsy.modules.embeddedfileextractor.ExtractArchiveWithPasswordAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
@ -529,12 +530,17 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractAction visit(Md5Node md5n){
|
public AbstractAction visit(CommonAttributeValueNode md5n){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractAction visit(FileInstanceNode fin){
|
public AbstractAction visit(CaseDBCommonAttributeInstanceNode fin){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractAction visit(CentralRepoCommonAttributeInstanceNode iccan){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,7 +838,7 @@ public class CentralRepoDatamodelTest extends TestCase {
|
|||||||
// This is the expected behavior
|
// This is the expected behavior
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test getting instances with expected resuls
|
// Test getting instances with expected results
|
||||||
try {
|
try {
|
||||||
List<CorrelationAttributeInstance> instances = EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash);
|
List<CorrelationAttributeInstance> instances = EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash);
|
||||||
assertTrue("getArtifactInstancesByTypeValue returned " + instances.size() + " results - expected 3", instances.size() == 3);
|
assertTrue("getArtifactInstancesByTypeValue returned " + instances.size() + " results - expected 3", instances.size() == 3);
|
||||||
@ -1123,6 +1123,34 @@ public class CentralRepoDatamodelTest extends TestCase {
|
|||||||
} catch (EamDbException ex) {
|
} catch (EamDbException ex) {
|
||||||
// This is the expected
|
// This is the expected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test running processinstance which queries all rows from instances table
|
||||||
|
try {
|
||||||
|
// Add two instances to the central repository and use the callback query to verify we can see them
|
||||||
|
CorrelationAttribute attr = new CorrelationAttribute(fileType, callbackTestFileHash);
|
||||||
|
CorrelationAttributeInstance inst1 = new CorrelationAttributeInstance(case1, dataSource1fromCase1, callbackTestFilePath1);
|
||||||
|
CorrelationAttributeInstance inst2 = new CorrelationAttributeInstance(case1, dataSource1fromCase1, callbackTestFilePath2);
|
||||||
|
attr.addInstance(inst1);
|
||||||
|
attr.addInstance(inst2);
|
||||||
|
EamDb DbManager = EamDb.getInstance();
|
||||||
|
DbManager.addArtifact(attr);
|
||||||
|
AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback();
|
||||||
|
DbManager.processInstanceTableWhere(fileType, String.format("id = %s", attr.getID()), instancetableCallback);
|
||||||
|
int count1 = instancetableCallback.getCounter();
|
||||||
|
int count2 = instancetableCallback.getCounterNamingConvention();
|
||||||
|
assertTrue("Process Instance count with filepath naming convention: " + count2 + "-expected 2", count2 == 2);
|
||||||
|
assertTrue("Process Instance count with filepath without naming convention: " + count1 + "-expected greater than 0", count1 > 0);
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
//test null inputs
|
||||||
|
EamDb.getInstance().processInstanceTableWhere(null, null, null);
|
||||||
|
Assert.fail("processinstance method failed to throw exception for null type value");
|
||||||
|
} catch (EamDbException ex) {
|
||||||
|
// This is the expected
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,465 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* 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.commonfilessearch;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import junit.framework.Test;
|
|
||||||
import org.netbeans.junit.NbModuleSuite;
|
|
||||||
import org.netbeans.junit.NbTestCase;
|
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.python.icu.impl.Assert;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.AllDataSourcesCommonFilesAlgorithm;
|
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata;
|
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadataBuilder;
|
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.SingleDataSource;
|
|
||||||
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseUtils.*;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleTemplate;
|
|
||||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
|
|
||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory;
|
|
||||||
import org.sleuthkit.autopsy.testutils.IngestUtils;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add set 1, set 2, set 3, and set 4 to case and ingest with hash algorithm.
|
|
||||||
*/
|
|
||||||
public class IngestedWithHashAndFileType extends NbTestCase {
|
|
||||||
|
|
||||||
public static Test suite() {
|
|
||||||
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestedWithHashAndFileType.class).
|
|
||||||
clusters(".*").
|
|
||||||
enableModules(".*");
|
|
||||||
return conf.suite();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final IntraCaseUtils utils;
|
|
||||||
|
|
||||||
public IngestedWithHashAndFileType(String name) {
|
|
||||||
super(name);
|
|
||||||
|
|
||||||
this.utils = new IntraCaseUtils(this, "IngestedWithHashAndFileTypeTests");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() {
|
|
||||||
this.utils.setUp();
|
|
||||||
|
|
||||||
IngestModuleTemplate hashLookupTemplate = IngestUtils.getIngestModuleTemplate(new HashLookupModuleFactory());
|
|
||||||
IngestModuleTemplate mimeTypeLookupTemplate = IngestUtils.getIngestModuleTemplate(new FileTypeIdModuleFactory());
|
|
||||||
|
|
||||||
ArrayList<IngestModuleTemplate> templates = new ArrayList<>();
|
|
||||||
templates.add(hashLookupTemplate);
|
|
||||||
templates.add(mimeTypeLookupTemplate);
|
|
||||||
|
|
||||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithHashAndFileType.class.getCanonicalName(), IngestType.FILES_ONLY, templates);
|
|
||||||
|
|
||||||
try {
|
|
||||||
IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings);
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tearDown() {
|
|
||||||
this.utils.tearDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all matches & all file types. Confirm file.jpg is found on all three
|
|
||||||
* and file.docx is found on two.
|
|
||||||
*/
|
|
||||||
public void testOneA() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, false, false);
|
|
||||||
CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = IntraCaseUtils.mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = IntraCaseUtils.getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all matches & only image types. Confirm file.jpg is found on all
|
|
||||||
* three.
|
|
||||||
*/
|
|
||||||
public void testOneB() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, true, false);
|
|
||||||
CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all matches & only image types. Confirm file.jpg is found on all
|
|
||||||
* three.
|
|
||||||
*/
|
|
||||||
public void testOneC() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, false, true);
|
|
||||||
CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find matches on set 1 & all file types. Confirm same results.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void testTwoA() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
Long first = getDataSourceIdByName(SET1, dataSources);
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, false, false);
|
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find matches on set 1 & only media types. Confirm same results.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void testTwoB() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
Long first = getDataSourceIdByName(SET1, dataSources);
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, true, false);
|
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find matches on set 1 & all file types. Confirm same results.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void testTwoC() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
Long first = getDataSourceIdByName(SET1, dataSources);
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, false, true);
|
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find matches on set 2 & all file types: Confirm file.jpg.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void testThree() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
Long second = getDataSourceIdByName(SET2, dataSources);
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(second, dataSources, false, false);
|
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find matches on set 4 & all file types: Confirm nothing is found.
|
|
||||||
*/
|
|
||||||
public void testFour() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
Long last = getDataSourceIdByName(SET4, dataSources);
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(last, dataSources, false, false);
|
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find matches on set 3 & all file types: Confirm file.jpg and file.docx.
|
|
||||||
*/
|
|
||||||
public void testFive() {
|
|
||||||
try {
|
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
|
||||||
Long third = getDataSourceIdByName(SET3, dataSources);
|
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(third, dataSources, false, false);
|
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
|
||||||
|
|
||||||
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
|
||||||
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
|
||||||
assertTrue(verifyFileExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
|
||||||
Exceptions.printStackTrace(ex);
|
|
||||||
Assert.fail(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilessearch;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Map;
|
||||||
|
import junit.framework.Test;
|
||||||
|
import org.netbeans.junit.NbModuleSuite;
|
||||||
|
import org.netbeans.junit.NbTestCase;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
|
import org.python.icu.impl.Assert;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeSearcher;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.AllInterCaseCommonAttributeSearcher;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.SingleInterCaseCommonAttributeSearcher;
|
||||||
|
import static org.sleuthkit.autopsy.commonfilessearch.InterCaseTestUtils.*;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests with case 3 as the current case.
|
||||||
|
*
|
||||||
|
* If I use the search all cases option: One node for Hash A (1_1_A.jpg,
|
||||||
|
* 1_2_A.jpg, 3_1_A.jpg) If I search for matches only in Case 1: One node for
|
||||||
|
* Hash A (1_1_A.jpg, 1_2_A.jpg, 3_1_A.jpg) If I search for matches only in Case
|
||||||
|
* 2: No matches If I only search in the current case (existing mode), allowing
|
||||||
|
* all data sources: One node for Hash C (3_1_C.jpg, 3_2_C.jpg)
|
||||||
|
*/
|
||||||
|
public class IngestedWithHashAndFileTypeInterCaseTests extends NbTestCase {
|
||||||
|
|
||||||
|
private final InterCaseTestUtils utils;
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestedWithHashAndFileTypeInterCaseTests.class).
|
||||||
|
clusters(".*").
|
||||||
|
enableModules(".*");
|
||||||
|
return conf.suite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IngestedWithHashAndFileTypeInterCaseTests(String name) {
|
||||||
|
super(name);
|
||||||
|
this.utils = new InterCaseTestUtils(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp(){
|
||||||
|
this.utils.clearTestDir();
|
||||||
|
try {
|
||||||
|
this.utils.enableCentralRepo();
|
||||||
|
this.utils.createCases(this.utils.getIngestSettingsForHashAndFileType(), InterCaseTestUtils.CASE3);
|
||||||
|
} catch (TskCoreException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tearDown(){
|
||||||
|
this.utils.clearTestDir();
|
||||||
|
this.utils.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search All cases with no file type filtering.
|
||||||
|
*/
|
||||||
|
public void testOne() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
|
//note that the params false and false are presently meaningless because that feature is not supported yet
|
||||||
|
AbstractCommonAttributeSearcher builder = new AllInterCaseCommonAttributeSearcher(dataSources, false, false);
|
||||||
|
|
||||||
|
CommonAttributeSearchResults metadata = builder.findFiles();
|
||||||
|
|
||||||
|
assertTrue("Results should not be empty", metadata.size() != 0);
|
||||||
|
|
||||||
|
//case 1 data set 1
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_0_DAT, CASE1_DATASET_1, CASE1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE1_DATASET_1, CASE1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE1_DATASET_1, CASE1, 1));
|
||||||
|
|
||||||
|
//case 1 data set 2
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_0_DAT, CASE1_DATASET_2, CASE1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE1_DATASET_2, CASE1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE1_DATASET_2, CASE1, 1));
|
||||||
|
|
||||||
|
//case 2 data set 1
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_B_PDF, CASE2_DATASET_1, CASE2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_B_JPG, CASE2_DATASET_1, CASE2, 0));
|
||||||
|
|
||||||
|
//case 2 data set 2
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE2_DATASET_2, CASE2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE2_DATASET_2, CASE2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_D_DOC, CASE2_DATASET_2, CASE2, 1));
|
||||||
|
|
||||||
|
//case 3 data set 1
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE3_DATASET_1, CASE3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE3_DATASET_1, CASE3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_JPG, CASE3_DATASET_1, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_PDF, CASE3_DATASET_1, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_D_JPG, CASE3_DATASET_1, CASE3, 0));
|
||||||
|
|
||||||
|
//case 3 data set 2
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_JPG, CASE3_DATASET_2, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_PDF, CASE3_DATASET_2, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_D_DOC, CASE3_DATASET_2, CASE3, 1));
|
||||||
|
|
||||||
|
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search All cases with no file type filtering.
|
||||||
|
*/
|
||||||
|
public void testTwo() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
|
int matchesMustAlsoBeFoundInThisCase = this.utils.getCaseMap().get(CASE2);
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher builder = new SingleInterCaseCommonAttributeSearcher(matchesMustAlsoBeFoundInThisCase, dataSources, false, false);
|
||||||
|
|
||||||
|
CommonAttributeSearchResults metadata = builder.findFiles();
|
||||||
|
|
||||||
|
assertTrue("Results should not be empty", metadata.size() != 0);
|
||||||
|
|
||||||
|
//case 1 data set 1
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_0_DAT, CASE1_DATASET_1, CASE1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE1_DATASET_1, CASE1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE1_DATASET_1, CASE1, 1));
|
||||||
|
|
||||||
|
//case 1 data set 2
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_0_DAT, CASE1_DATASET_2, CASE1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE1_DATASET_2, CASE1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE1_DATASET_2, CASE1, 1));
|
||||||
|
|
||||||
|
//case 2 data set 1
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_B_PDF, CASE2_DATASET_1, CASE2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_B_JPG, CASE2_DATASET_1, CASE2, 0));
|
||||||
|
|
||||||
|
//case 2 data set 2
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE2_DATASET_2, CASE2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE2_DATASET_2, CASE2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_D_DOC, CASE2_DATASET_2, CASE2, 1));
|
||||||
|
|
||||||
|
//case 3 data set 1
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_JPG, CASE3_DATASET_1, CASE3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_A_PDF, CASE3_DATASET_1, CASE3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_JPG, CASE3_DATASET_1, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_PDF, CASE3_DATASET_1, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_D_JPG, CASE3_DATASET_1, CASE3, 0));
|
||||||
|
|
||||||
|
//case 3 data set 2
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_JPG, CASE3_DATASET_2, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_C_PDF, CASE3_DATASET_2, CASE3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(metadata, HASH_D_DOC, CASE3_DATASET_2, CASE3, 1));
|
||||||
|
|
||||||
|
|
||||||
|
} catch (TskCoreException | NoCurrentCaseException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,466 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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.commonfilessearch;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import junit.framework.Test;
|
||||||
|
import org.netbeans.junit.NbModuleSuite;
|
||||||
|
import org.netbeans.junit.NbTestCase;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
|
import org.python.icu.impl.Assert;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeSearcher;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.AllIntraCaseCommonAttributeSearcher;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.SingleIntraCaseCommonAttributeSearcher;
|
||||||
|
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseTestUtils.*;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestModuleTemplate;
|
||||||
|
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
|
||||||
|
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory;
|
||||||
|
import org.sleuthkit.autopsy.testutils.IngestUtils;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add set 1, set 2, set 3, and set 4 to case and ingest with hash algorithm.
|
||||||
|
*/
|
||||||
|
public class IngestedWithHashAndFileTypeIntraCaseTests extends NbTestCase {
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestedWithHashAndFileTypeIntraCaseTests.class).
|
||||||
|
clusters(".*").
|
||||||
|
enableModules(".*");
|
||||||
|
return conf.suite();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final IntraCaseTestUtils utils;
|
||||||
|
|
||||||
|
public IngestedWithHashAndFileTypeIntraCaseTests(String name) {
|
||||||
|
super(name);
|
||||||
|
|
||||||
|
this.utils = new IntraCaseTestUtils(this, "IngestedWithHashAndFileTypeTests");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() {
|
||||||
|
this.utils.setUp();
|
||||||
|
|
||||||
|
IngestModuleTemplate hashLookupTemplate = IngestUtils.getIngestModuleTemplate(new HashLookupModuleFactory());
|
||||||
|
IngestModuleTemplate mimeTypeLookupTemplate = IngestUtils.getIngestModuleTemplate(new FileTypeIdModuleFactory());
|
||||||
|
|
||||||
|
ArrayList<IngestModuleTemplate> templates = new ArrayList<>();
|
||||||
|
templates.add(hashLookupTemplate);
|
||||||
|
templates.add(mimeTypeLookupTemplate);
|
||||||
|
|
||||||
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithHashAndFileTypeIntraCaseTests.class.getCanonicalName(), IngestType.FILES_ONLY, templates);
|
||||||
|
|
||||||
|
try {
|
||||||
|
IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings);
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tearDown() {
|
||||||
|
this.utils.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all matches & all file types. Confirm file.jpg is found on all three
|
||||||
|
* and file.docx is found on two.
|
||||||
|
*/
|
||||||
|
public void testOneA() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher allSourcesBuilder = new AllIntraCaseCommonAttributeSearcher(dataSources, false, false);
|
||||||
|
CommonAttributeSearchResults metadata = allSourcesBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = IntraCaseTestUtils.mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = IntraCaseTestUtils.getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all matches & only image types. Confirm file.jpg is found on all
|
||||||
|
* three.
|
||||||
|
*/
|
||||||
|
public void testOneB() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher allSourcesBuilder = new AllIntraCaseCommonAttributeSearcher(dataSources, true, false);
|
||||||
|
CommonAttributeSearchResults metadata = allSourcesBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all matches & only image types. Confirm file.jpg is found on all
|
||||||
|
* three.
|
||||||
|
*/
|
||||||
|
public void testOneC() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher allSourcesBuilder = new AllIntraCaseCommonAttributeSearcher(dataSources, false, true);
|
||||||
|
CommonAttributeSearchResults metadata = allSourcesBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find matches on set 1 & all file types. Confirm same results.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testTwoA() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
Long first = getDataSourceIdByName(SET1, dataSources);
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(first, dataSources, false, false);
|
||||||
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find matches on set 1 & only media types. Confirm same results.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testTwoB() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
Long first = getDataSourceIdByName(SET1, dataSources);
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(first, dataSources, true, false);
|
||||||
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find matches on set 1 & all file types. Confirm same results.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testTwoC() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
Long first = getDataSourceIdByName(SET1, dataSources);
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(first, dataSources, false, true);
|
||||||
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find matches on set 2 & all file types: Confirm file.jpg.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testThree() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
Long second = getDataSourceIdByName(SET2, dataSources);
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(second, dataSources, false, false);
|
||||||
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find matches on set 4 & all file types: Confirm nothing is found.
|
||||||
|
*/
|
||||||
|
public void testFour() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
Long last = getDataSourceIdByName(SET4, dataSources);
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(last, dataSources, false, false);
|
||||||
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find matches on set 3 & all file types: Confirm file.jpg and file.docx.
|
||||||
|
*/
|
||||||
|
public void testFive() {
|
||||||
|
try {
|
||||||
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
Long third = getDataSourceIdByName(SET3, dataSources);
|
||||||
|
|
||||||
|
AbstractCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(third, dataSources, false, false);
|
||||||
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
|
Map<Long, String> objectIdToDataSource = mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
|
List<AbstractFile> files = getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET1, 2));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET2, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, IMG, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET1, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET3, 1));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, DOC, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, PDF, SET4, 0));
|
||||||
|
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET1, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET2, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET3, 0));
|
||||||
|
assertTrue(verifyInstanceExistanceAndCount(files, objectIdToDataSource, EMPTY, SET4, 0));
|
||||||
|
|
||||||
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,10 +31,10 @@ import org.openide.util.Exceptions;
|
|||||||
import org.python.icu.impl.Assert;
|
import org.python.icu.impl.Assert;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.AllDataSourcesCommonFilesAlgorithm;
|
import org.sleuthkit.autopsy.commonfilesearch.AllIntraCaseCommonAttributeSearcher;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata;
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadataBuilder;
|
import org.sleuthkit.autopsy.commonfilesearch.IntraCaseCommonAttributeSearcher;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.SingleDataSource;
|
import org.sleuthkit.autopsy.commonfilesearch.SingleIntraCaseCommonAttributeSearcher;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleTemplate;
|
import org.sleuthkit.autopsy.ingest.IngestModuleTemplate;
|
||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory;
|
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory;
|
||||||
@ -51,21 +51,21 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
* Add images set 1, set 2, set 3, and set 4 to case. Do not run mime type
|
* Add images set 1, set 2, set 3, and set 4 to case. Do not run mime type
|
||||||
* module.
|
* module.
|
||||||
*/
|
*/
|
||||||
public class IngestedWithNoFileTypes extends NbTestCase {
|
public class IngestedWithNoFileTypesIntraCaseTests extends NbTestCase {
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestedWithNoFileTypes.class).
|
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(IngestedWithNoFileTypesIntraCaseTests.class).
|
||||||
clusters(".*").
|
clusters(".*").
|
||||||
enableModules(".*");
|
enableModules(".*");
|
||||||
return conf.suite();
|
return conf.suite();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final IntraCaseUtils utils;
|
private final IntraCaseTestUtils utils;
|
||||||
|
|
||||||
public IngestedWithNoFileTypes(String name) {
|
public IngestedWithNoFileTypesIntraCaseTests(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
this.utils = new IntraCaseUtils(this, "IngestedWithNoFileTypes");
|
this.utils = new IntraCaseTestUtils(this, "IngestedWithNoFileTypes");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -77,7 +77,7 @@ public class IngestedWithNoFileTypes extends NbTestCase {
|
|||||||
ArrayList<IngestModuleTemplate> templates = new ArrayList<>();
|
ArrayList<IngestModuleTemplate> templates = new ArrayList<>();
|
||||||
templates.add(hashLookupTemplate);
|
templates.add(hashLookupTemplate);
|
||||||
|
|
||||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithHashAndFileType.class.getCanonicalName(), IngestJobSettings.IngestType.FILES_ONLY, templates);
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithNoFileTypesIntraCaseTests.class.getCanonicalName(), IngestJobSettings.IngestType.FILES_ONLY, templates);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings);
|
IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings);
|
||||||
@ -97,20 +97,22 @@ public class IngestedWithNoFileTypes extends NbTestCase {
|
|||||||
* find nothing and no errors should arise.
|
* find nothing and no errors should arise.
|
||||||
*/
|
*/
|
||||||
public void testOne() {
|
public void testOne() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, true, false);
|
IntraCaseCommonAttributeSearcher allSourcesBuilder = new AllIntraCaseCommonAttributeSearcher(dataSources, true, false);
|
||||||
CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles();
|
CommonAttributeSearchResults metadata = allSourcesBuilder.findFiles();
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = IntraCaseUtils.mapFileInstancesToDataSources(metadata);
|
Map<Long, String> objectIdToDataSource = IntraCaseTestUtils.mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
List<AbstractFile> files = IntraCaseUtils.getFiles(objectIdToDataSource.keySet());
|
List<AbstractFile> files = IntraCaseTestUtils.getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
assertTrue(files.isEmpty());
|
assertTrue(files.isEmpty());
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
} catch (TskCoreException | NoCurrentCaseException | SQLException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,18 +123,18 @@ public class IngestedWithNoFileTypes extends NbTestCase {
|
|||||||
public void testTwo() {
|
public void testTwo() {
|
||||||
try {
|
try {
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
Long third = IntraCaseUtils.getDataSourceIdByName(IntraCaseUtils.SET3, dataSources);
|
Long third = IntraCaseTestUtils.getDataSourceIdByName(IntraCaseTestUtils.SET3, dataSources);
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(third, dataSources, true, false);
|
IntraCaseCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(third, dataSources, true, false);
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = IntraCaseUtils.mapFileInstancesToDataSources(metadata);
|
Map<Long, String> objectIdToDataSource = IntraCaseTestUtils.mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
List<AbstractFile> files = IntraCaseUtils.getFiles(objectIdToDataSource.keySet());
|
List<AbstractFile> files = IntraCaseTestUtils.getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
assertTrue(files.isEmpty());
|
assertTrue(files.isEmpty());
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
} catch (Exception ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
Assert.fail(ex);
|
Assert.fail(ex);
|
||||||
}
|
}
|
@ -0,0 +1,392 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 testFile 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.commonfilessearch;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.netbeans.junit.NbTestCase;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbPlatformEnum;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteEamDbSettings;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType;
|
||||||
|
import org.sleuthkit.autopsy.ingest.IngestModuleTemplate;
|
||||||
|
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
|
||||||
|
import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupModuleFactory;
|
||||||
|
import org.sleuthkit.autopsy.testutils.CaseUtils;
|
||||||
|
import org.sleuthkit.autopsy.testutils.IngestUtils;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.python.icu.impl.Assert;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CaseDBCommonAttributeInstanceNode;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CentralRepoCommonAttributeInstanceNode;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for testing intercase correlation feature.
|
||||||
|
*
|
||||||
|
* This will be more useful when we add more flush out the intercase
|
||||||
|
* correlation features and need to add more tests. In particular,
|
||||||
|
* testing scenarios where we need different cases to be the current case
|
||||||
|
* will suggest that we create additional test classes, and we will want to
|
||||||
|
* import this utility in each new intercase test file.
|
||||||
|
*
|
||||||
|
* Description of Test Data:
|
||||||
|
(Note: files of the same name and extension are identical;
|
||||||
|
files of the same name and differing extension are not identical.)
|
||||||
|
|
||||||
|
Case 1
|
||||||
|
+Data Set 1
|
||||||
|
- Hash-0.dat [testFile of size 0]
|
||||||
|
- Hash-A.jpg
|
||||||
|
- Hash-A.pdf
|
||||||
|
+Data Set2
|
||||||
|
- Hash-0.dat [testFile of size 0]
|
||||||
|
- Hash-A.jpg
|
||||||
|
- Hash-A.pdf
|
||||||
|
Case 2
|
||||||
|
+Data Set 1
|
||||||
|
- Hash-B.jpg
|
||||||
|
- Hash-B.pdf
|
||||||
|
+Data Set 2
|
||||||
|
- Hash-A.jpg
|
||||||
|
- Hash-A.pdf
|
||||||
|
- Hash_D.doc
|
||||||
|
Case 3
|
||||||
|
+Data Set 1
|
||||||
|
- Hash-A.jpg
|
||||||
|
- Hash-A.pdf
|
||||||
|
- Hash-C.jpg
|
||||||
|
- Hash-C.pdf
|
||||||
|
- Hash-D.jpg
|
||||||
|
+Data Set 2
|
||||||
|
- Hash-C.jpg
|
||||||
|
- Hash-C.pdf
|
||||||
|
- Hash-D.doc
|
||||||
|
*/
|
||||||
|
class InterCaseTestUtils {
|
||||||
|
|
||||||
|
private static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), "InterCaseCommonFilesSearchTest");
|
||||||
|
private static final String CR_DB_NAME = "testcentralrepo.db";
|
||||||
|
|
||||||
|
static final String CASE1 = "Case1";
|
||||||
|
static final String CASE2 = "Case2";
|
||||||
|
static final String CASE3 = "Case3";
|
||||||
|
static final String CASE4 = "Case4";
|
||||||
|
|
||||||
|
final Path case1DataSet1Path;
|
||||||
|
final Path case1DataSet2Path;
|
||||||
|
final Path case2DataSet1Path;
|
||||||
|
final Path case2DataSet2Path;
|
||||||
|
final Path case3DataSet1Path;
|
||||||
|
final Path case3DataSet2Path;
|
||||||
|
|
||||||
|
static final String HASH_0_DAT = "Hash-0.dat";
|
||||||
|
static final String HASH_A_JPG = "Hash-A.jpg";
|
||||||
|
static final String HASH_A_PDF = "Hash-A.pdf";
|
||||||
|
static final String HASH_B_JPG = "Hash-B.jpg";
|
||||||
|
static final String HASH_B_PDF = "Hash-B.pdf";
|
||||||
|
static final String HASH_C_JPG = "Hash-C.jpg";
|
||||||
|
static final String HASH_C_PDF = "Hash-C.pdf";
|
||||||
|
static final String HASH_D_JPG = "Hash-D.jpg";
|
||||||
|
static final String HASH_D_DOC = "Hash-D.doc";
|
||||||
|
|
||||||
|
static final String CASE1_DATASET_1 = "c1ds1_v1.vhd";
|
||||||
|
static final String CASE1_DATASET_2 = "c1ds2_v1.vhd";
|
||||||
|
static final String CASE2_DATASET_1 = "c2ds1_v1.vhd";
|
||||||
|
static final String CASE2_DATASET_2 = "c2ds2_v1.vhd";
|
||||||
|
static final String CASE3_DATASET_1 = "c3ds1_v1.vhd";
|
||||||
|
static final String CASE3_DATASET_2 = "c3ds2_v1.vhd";
|
||||||
|
|
||||||
|
private final ImageDSProcessor imageDSProcessor;
|
||||||
|
|
||||||
|
private final IngestJobSettings hashAndFileType;
|
||||||
|
private final IngestJobSettings hashAndNoFileType;
|
||||||
|
private final DataSourceLoader dataSourceLoader;
|
||||||
|
|
||||||
|
InterCaseTestUtils(NbTestCase testCase) {
|
||||||
|
|
||||||
|
this.case1DataSet1Path = Paths.get(testCase.getDataDir().toString(), CASE1_DATASET_1);
|
||||||
|
this.case1DataSet2Path = Paths.get(testCase.getDataDir().toString(), CASE1_DATASET_2);
|
||||||
|
this.case2DataSet1Path = Paths.get(testCase.getDataDir().toString(), CASE1_DATASET_1);
|
||||||
|
this.case2DataSet2Path = Paths.get(testCase.getDataDir().toString(), CASE2_DATASET_2);
|
||||||
|
this.case3DataSet1Path = Paths.get(testCase.getDataDir().toString(), CASE3_DATASET_1);
|
||||||
|
this.case3DataSet2Path = Paths.get(testCase.getDataDir().toString(), CASE3_DATASET_2);
|
||||||
|
|
||||||
|
this.imageDSProcessor = new ImageDSProcessor();
|
||||||
|
|
||||||
|
final IngestModuleTemplate hashLookupTemplate = IngestUtils.getIngestModuleTemplate(new HashLookupModuleFactory());
|
||||||
|
final IngestModuleTemplate mimeTypeLookupTemplate = IngestUtils.getIngestModuleTemplate(new FileTypeIdModuleFactory());
|
||||||
|
final IngestModuleTemplate eamDbTemplate = IngestUtils.getIngestModuleTemplate(new org.sleuthkit.autopsy.centralrepository.ingestmodule.IngestModuleFactory());
|
||||||
|
|
||||||
|
ArrayList<IngestModuleTemplate> hashAndMimeTemplate = new ArrayList<>(2);
|
||||||
|
hashAndMimeTemplate.add(hashLookupTemplate);
|
||||||
|
hashAndMimeTemplate.add(mimeTypeLookupTemplate);
|
||||||
|
hashAndMimeTemplate.add(eamDbTemplate);
|
||||||
|
|
||||||
|
this.hashAndFileType = new IngestJobSettings(InterCaseTestUtils.class.getCanonicalName(), IngestType.FILES_ONLY, hashAndMimeTemplate);
|
||||||
|
|
||||||
|
ArrayList<IngestModuleTemplate> hashAndNoMimeTemplate = new ArrayList<>(1);
|
||||||
|
hashAndNoMimeTemplate.add(hashLookupTemplate);
|
||||||
|
hashAndMimeTemplate.add(eamDbTemplate);
|
||||||
|
|
||||||
|
this.hashAndNoFileType = new IngestJobSettings(InterCaseTestUtils.class.getCanonicalName(), IngestType.FILES_ONLY, hashAndNoMimeTemplate);
|
||||||
|
|
||||||
|
this.dataSourceLoader = new DataSourceLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearTestDir(){
|
||||||
|
if(CASE_DIRECTORY_PATH.toFile().exists()){
|
||||||
|
try{
|
||||||
|
if(EamDb.isEnabled()) {
|
||||||
|
EamDb.getInstance().shutdownConnections();
|
||||||
|
}
|
||||||
|
FileUtils.deleteDirectory(CASE_DIRECTORY_PATH.toFile());
|
||||||
|
} catch(IOException | EamDbException ex){
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CASE_DIRECTORY_PATH.toFile().exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, String> getDataSourceMap() throws NoCurrentCaseException, TskCoreException, SQLException {
|
||||||
|
return this.dataSourceLoader.getDataSourceMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Integer> getCaseMap() throws EamDbException {
|
||||||
|
|
||||||
|
if (EamDb.isEnabled()) {
|
||||||
|
Map<String, Integer> mapOfCaseIdsToCase = new HashMap<>();
|
||||||
|
|
||||||
|
for (CorrelationCase caze : EamDb.getInstance().getCases()) {
|
||||||
|
mapOfCaseIdsToCase.put(caze.getDisplayName(), caze.getID());
|
||||||
|
}
|
||||||
|
return mapOfCaseIdsToCase;
|
||||||
|
} else {
|
||||||
|
//it is reasonable that this might happen...
|
||||||
|
// for example when we test the feature in the absence of an enabled eamdb
|
||||||
|
return new HashMap<>(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IngestJobSettings getIngestSettingsForHashAndFileType() {
|
||||||
|
return this.hashAndFileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
IngestJobSettings getIngestSettingsForHashAndNoFileType() {
|
||||||
|
return this.hashAndNoFileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enableCentralRepo() throws EamDbException {
|
||||||
|
|
||||||
|
SqliteEamDbSettings crSettings = new SqliteEamDbSettings();
|
||||||
|
crSettings.setDbName(CR_DB_NAME);
|
||||||
|
crSettings.setDbDirectory(CASE_DIRECTORY_PATH.toString());
|
||||||
|
if (!crSettings.dbDirectoryExists()) {
|
||||||
|
crSettings.createDbDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
crSettings.initializeDatabaseSchema();
|
||||||
|
crSettings.insertDefaultDatabaseContent();
|
||||||
|
|
||||||
|
crSettings.saveSettings();
|
||||||
|
|
||||||
|
EamDbUtil.setUseCentralRepo(true);
|
||||||
|
EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name());
|
||||||
|
EamDbPlatformEnum.saveSelectedPlatform();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create 3 cases and ingest each with the given settings. Null settings are
|
||||||
|
* permitted but IngestUtils will not be run.
|
||||||
|
*
|
||||||
|
* @param ingestJobSettings HashLookup FileType etc...
|
||||||
|
* @param caseReferenceToStore
|
||||||
|
*/
|
||||||
|
Case createCases(IngestJobSettings ingestJobSettings, String caseReferenceToStore) throws TskCoreException {
|
||||||
|
|
||||||
|
Case currentCase = null;
|
||||||
|
|
||||||
|
String[] cases = new String[]{
|
||||||
|
CASE1,
|
||||||
|
CASE2,
|
||||||
|
CASE3};
|
||||||
|
|
||||||
|
Path[][] paths = {
|
||||||
|
{this.case1DataSet1Path, this.case1DataSet2Path},
|
||||||
|
{this.case2DataSet1Path, this.case2DataSet2Path},
|
||||||
|
{this.case3DataSet1Path, this.case3DataSet2Path}};
|
||||||
|
|
||||||
|
String lastCaseName = null;
|
||||||
|
Path[] lastPathsForCase = null;
|
||||||
|
//iterate over the collections above, creating cases, and storing
|
||||||
|
// just one of them for future reference
|
||||||
|
for (int i = 0; i < cases.length; i++) {
|
||||||
|
String caseName = cases[i];
|
||||||
|
Path[] pathsForCase = paths[i];
|
||||||
|
|
||||||
|
if (caseName.equals(caseReferenceToStore)) {
|
||||||
|
//put aside and do this one last so we can hang onto the case
|
||||||
|
lastCaseName = caseName;
|
||||||
|
lastPathsForCase = pathsForCase;
|
||||||
|
} else {
|
||||||
|
//dont hang onto this case; close it
|
||||||
|
this.createCase(caseName, ingestJobSettings, false, pathsForCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastCaseName != null && lastPathsForCase != null) {
|
||||||
|
//hang onto this caes and dont close it
|
||||||
|
currentCase = this.createCase(lastCaseName, ingestJobSettings, true, lastPathsForCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCase == null) {
|
||||||
|
Assert.fail(new IllegalArgumentException("caseReferenceToStore should be one of: CASE1, CASE2, CASE3"));
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return currentCase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Case createCase(String caseName, IngestJobSettings ingestJobSettings, boolean keepAlive, Path... dataSetPaths) throws TskCoreException {
|
||||||
|
|
||||||
|
Case caze = CaseUtils.createAsCurrentCase(caseName);
|
||||||
|
for (Path dataSetPath : dataSetPaths) {
|
||||||
|
IngestUtils.addDataSource(this.imageDSProcessor, dataSetPath);
|
||||||
|
}
|
||||||
|
if (ingestJobSettings != null) {
|
||||||
|
IngestUtils.runIngestJob(caze.getDataSources(), ingestJobSettings);
|
||||||
|
}
|
||||||
|
if (keepAlive) {
|
||||||
|
return caze;
|
||||||
|
} else {
|
||||||
|
CaseUtils.closeCurrentCase(false);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO refactor
|
||||||
|
static boolean verifyInstanceExistanceAndCount(CommonAttributeSearchResults searchDomain, String fileName, String dataSource, String crCase, int instanceCount){
|
||||||
|
|
||||||
|
int tally = 0;
|
||||||
|
|
||||||
|
for(Map.Entry<Integer, List<CommonAttributeValue>> entry : searchDomain.getMetadata().entrySet()){
|
||||||
|
|
||||||
|
for(CommonAttributeValue value : entry.getValue()){
|
||||||
|
|
||||||
|
for(AbstractCommonAttributeInstance commonAttribute : value.getInstances()){
|
||||||
|
|
||||||
|
if(commonAttribute instanceof CentralRepoCommonAttributeInstance){
|
||||||
|
CentralRepoCommonAttributeInstance results = (CentralRepoCommonAttributeInstance) commonAttribute;
|
||||||
|
for (DisplayableItemNode din : results.generateNodes()){
|
||||||
|
|
||||||
|
if(din instanceof CentralRepoCommonAttributeInstanceNode){
|
||||||
|
|
||||||
|
CentralRepoCommonAttributeInstanceNode node = (CentralRepoCommonAttributeInstanceNode) din;
|
||||||
|
CorrelationAttributeInstance instance = node.getCorrelationAttributeInstance();
|
||||||
|
|
||||||
|
final String fullPath = instance.getFilePath();
|
||||||
|
final File testFile = new File(fullPath);
|
||||||
|
|
||||||
|
final String testCaseName = instance.getCorrelationCase().getDisplayName();
|
||||||
|
|
||||||
|
final String testFileName = testFile.getName();
|
||||||
|
|
||||||
|
final String testDataSource = instance.getCorrelationDataSource().getName();
|
||||||
|
|
||||||
|
boolean sameFileName = testFileName.equalsIgnoreCase(fileName);
|
||||||
|
boolean sameDataSource = testDataSource.equalsIgnoreCase(dataSource);
|
||||||
|
boolean sameCrCase = testCaseName.equalsIgnoreCase(crCase);
|
||||||
|
|
||||||
|
if( sameFileName && sameDataSource && sameCrCase){
|
||||||
|
tally++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(din instanceof CaseDBCommonAttributeInstanceNode){
|
||||||
|
|
||||||
|
CaseDBCommonAttributeInstanceNode node = (CaseDBCommonAttributeInstanceNode) din;
|
||||||
|
AbstractFile file = node.getContent();
|
||||||
|
|
||||||
|
final String testFileName = file.getName();
|
||||||
|
final String testCaseName = node.getCase();
|
||||||
|
final String testDataSource = node.getDataSource();
|
||||||
|
|
||||||
|
boolean sameFileName = testFileName.equalsIgnoreCase(fileName);
|
||||||
|
boolean sameCaseName = testCaseName.equalsIgnoreCase(crCase);
|
||||||
|
boolean sameDataSource = testDataSource.equalsIgnoreCase(dataSource);
|
||||||
|
|
||||||
|
if(sameFileName && sameDataSource && sameCaseName){
|
||||||
|
tally++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Assert.fail("Unable to cast AbstractCommonAttributeInstanceNode to InterCaseCommonAttributeSearchResults.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tally == instanceCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the currently open case, delete the case directory, delete the
|
||||||
|
* central repo db.
|
||||||
|
*/
|
||||||
|
void tearDown() {
|
||||||
|
|
||||||
|
CaseUtils.closeCurrentCase(false);
|
||||||
|
|
||||||
|
String[] cases = new String[]{CASE1,CASE2,CASE3};
|
||||||
|
|
||||||
|
try {
|
||||||
|
for(String caze : cases){
|
||||||
|
CaseUtils.deleteCaseDir(new File(caze));
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Exceptions.printStackTrace(ex);
|
||||||
|
Assert.fail(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,10 +33,10 @@ import org.python.icu.impl.Assert;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
|
import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata;
|
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeInstance;
|
||||||
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
|
import org.sleuthkit.autopsy.commonfilesearch.DataSourceLoader;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.FileInstanceMetadata;
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeValue;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.Md5Metadata;
|
|
||||||
import org.sleuthkit.autopsy.testutils.CaseUtils;
|
import org.sleuthkit.autopsy.testutils.CaseUtils;
|
||||||
import org.sleuthkit.autopsy.testutils.IngestUtils;
|
import org.sleuthkit.autopsy.testutils.IngestUtils;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -68,7 +68,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
* set 4
|
* set 4
|
||||||
* - file.dat (empty file)
|
* - file.dat (empty file)
|
||||||
*/
|
*/
|
||||||
class IntraCaseUtils {
|
class IntraCaseTestUtils {
|
||||||
|
|
||||||
private static final String CASE_NAME = "IntraCaseCommonFilesSearchTest";
|
private static final String CASE_NAME = "IntraCaseCommonFilesSearchTest";
|
||||||
static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), CASE_NAME);
|
static final Path CASE_DIRECTORY_PATH = Paths.get(System.getProperty("java.io.tmpdir"), CASE_NAME);
|
||||||
@ -91,13 +91,13 @@ class IntraCaseUtils {
|
|||||||
private final DataSourceLoader dataSourceLoader;
|
private final DataSourceLoader dataSourceLoader;
|
||||||
|
|
||||||
private final String caseName;
|
private final String caseName;
|
||||||
|
|
||||||
IntraCaseUtils(NbTestCase nbTestCase, String caseName) {
|
IntraCaseTestUtils(NbTestCase nbTestCase, String caseName){
|
||||||
imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), SET1);
|
this.imagePath1 = Paths.get(nbTestCase.getDataDir().toString(), SET1);
|
||||||
imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), SET2);
|
this.imagePath2 = Paths.get(nbTestCase.getDataDir().toString(), SET2);
|
||||||
imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), SET3);
|
this.imagePath3 = Paths.get(nbTestCase.getDataDir().toString(), SET3);
|
||||||
imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), SET4);
|
this.imagePath4 = Paths.get(nbTestCase.getDataDir().toString(), SET4);
|
||||||
|
|
||||||
this.dataSourceLoader = new DataSourceLoader();
|
this.dataSourceLoader = new DataSourceLoader();
|
||||||
|
|
||||||
this.caseName = caseName;
|
this.caseName = caseName;
|
||||||
@ -152,32 +152,32 @@ class IntraCaseUtils {
|
|||||||
* Verify that the given file appears a precise number times in the given
|
* Verify that the given file appears a precise number times in the given
|
||||||
* data source.
|
* data source.
|
||||||
*
|
*
|
||||||
* @param files search domain
|
* @param searchDomain search domain
|
||||||
* @param objectIdToDataSource mapping of file ids to data source names
|
* @param objectIdToDataSourceMap mapping of file ids to data source names
|
||||||
* @param name name of file to search for
|
* @param fileName name of file to search for
|
||||||
* @param dataSource name of data source where file should appear
|
* @param dataSource name of data source where file should appear
|
||||||
* @param count number of appearances of the given file
|
* @param instanceCount number of appearances of the given file
|
||||||
* @return true if a file with the given name exists the specified number of
|
* @return true if a file with the given name exists the specified number of
|
||||||
* times in the given data source
|
* times in the given data source
|
||||||
*/
|
*/
|
||||||
static boolean verifyFileExistanceAndCount(List<AbstractFile> files, Map<Long, String> objectIdToDataSource, String name, String dataSource, int count) {
|
static boolean verifyInstanceExistanceAndCount(List<AbstractFile> searchDomain, Map<Long, String> objectIdToDataSourceMap, String fileName, String dataSource, int instanceCount) {
|
||||||
|
|
||||||
int tally = 0;
|
int tally = 0;
|
||||||
|
|
||||||
for (AbstractFile file : files) {
|
for (AbstractFile file : searchDomain) {
|
||||||
|
|
||||||
Long objectId = file.getId();
|
Long objectId = file.getId();
|
||||||
|
|
||||||
String fileName = file.getName();
|
String name = file.getName();
|
||||||
|
|
||||||
String dataSourceName = objectIdToDataSource.get(objectId);
|
String dataSourceName = objectIdToDataSourceMap.get(objectId);
|
||||||
|
|
||||||
if (fileName.equals(name) && dataSourceName.equals(dataSource)) {
|
if (name.equals(name) && dataSourceName.equals(dataSource)) {
|
||||||
tally++;
|
tally++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tally == count;
|
return tally == instanceCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -191,17 +191,24 @@ class IntraCaseUtils {
|
|||||||
* @return true if a file with the given name exists once in the given data
|
* @return true if a file with the given name exists once in the given data
|
||||||
* source
|
* source
|
||||||
*/
|
*/
|
||||||
static boolean verifySingularFileExistance(List<AbstractFile> files, Map<Long, String> objectIdToDataSource, String name, String dataSource) {
|
static boolean verifySingularInstanceExistance(List<AbstractFile> files, Map<Long, String> objectIdToDataSource, String name, String dataSource) {
|
||||||
return verifyFileExistanceAndCount(files, objectIdToDataSource, name, dataSource, 1);
|
return verifyInstanceExistanceAndCount(files, objectIdToDataSource, name, dataSource, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<Long, String> mapFileInstancesToDataSources(CommonFilesMetadata metadata) {
|
/**
|
||||||
|
* Create a convenience lookup table mapping file instance object ids to
|
||||||
|
* the data source they appear in.
|
||||||
|
*
|
||||||
|
* @param metadata object returned by the code under test
|
||||||
|
* @return mapping of objectId to data source name
|
||||||
|
*/
|
||||||
|
static Map<Long, String> mapFileInstancesToDataSources(CommonAttributeSearchResults metadata) {
|
||||||
Map<Long, String> instanceIdToDataSource = new HashMap<>();
|
Map<Long, String> instanceIdToDataSource = new HashMap<>();
|
||||||
|
|
||||||
for (Map.Entry<Integer, List<Md5Metadata>> entry : metadata.getMetadata().entrySet()) {
|
for (Map.Entry<Integer, List<CommonAttributeValue>> entry : metadata.getMetadata().entrySet()) {
|
||||||
for (Md5Metadata md : entry.getValue()) {
|
for (CommonAttributeValue md : entry.getValue()) {
|
||||||
for (FileInstanceMetadata fim : md.getMetadata()) {
|
for (AbstractCommonAttributeInstance fim : md.getInstances()) {
|
||||||
instanceIdToDataSource.put(fim.getObjectId(), fim.getDataSourceName());
|
instanceIdToDataSource.put(fim.getAbstractFileObjectId(), fim.getDataSource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +216,7 @@ class IntraCaseUtils {
|
|||||||
return instanceIdToDataSource;
|
return instanceIdToDataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static List<AbstractFile> getFiles(Set<Long> objectIds) {
|
static List<AbstractFile> getFiles(Set<Long> objectIds) {
|
||||||
List<AbstractFile> files = new ArrayList<>(objectIds.size());
|
List<AbstractFile> files = new ArrayList<>(objectIds.size());
|
||||||
|
|
@ -31,10 +31,11 @@ import org.python.icu.impl.Assert;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
|
import org.sleuthkit.autopsy.casemodule.ImageDSProcessor;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.AllDataSourcesCommonFilesAlgorithm;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata;
|
import org.sleuthkit.autopsy.commonfilesearch.AbstractCommonAttributeSearcher;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadataBuilder;
|
import org.sleuthkit.autopsy.commonfilesearch.AllIntraCaseCommonAttributeSearcher;
|
||||||
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseUtils.*;
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
|
||||||
|
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseTestUtils.*;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
import org.sleuthkit.autopsy.ingest.IngestJobSettings;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleTemplate;
|
import org.sleuthkit.autopsy.ingest.IngestModuleTemplate;
|
||||||
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
|
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeIdModuleFactory;
|
||||||
@ -52,21 +53,21 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
*
|
*
|
||||||
* None of the test files should be found in the results of this test.
|
* None of the test files should be found in the results of this test.
|
||||||
*/
|
*/
|
||||||
public class MatchesInAtLeastTwoSources extends NbTestCase {
|
public class MatchesInAtLeastTwoSourcesIntraCaseTests extends NbTestCase {
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(MatchesInAtLeastTwoSources.class).
|
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(MatchesInAtLeastTwoSourcesIntraCaseTests.class).
|
||||||
clusters(".*").
|
clusters(".*").
|
||||||
enableModules(".*");
|
enableModules(".*");
|
||||||
return conf.suite();
|
return conf.suite();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final IntraCaseUtils utils;
|
private final IntraCaseTestUtils utils;
|
||||||
|
|
||||||
public MatchesInAtLeastTwoSources(String name) {
|
public MatchesInAtLeastTwoSourcesIntraCaseTests(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
this.utils = new IntraCaseUtils(this, "MatchesInAtLeastTwoSources");
|
this.utils = new IntraCaseTestUtils(this, "MatchesInAtLeastTwoSources");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -85,7 +86,7 @@ public class MatchesInAtLeastTwoSources extends NbTestCase {
|
|||||||
templates.add(hashLookupTemplate);
|
templates.add(hashLookupTemplate);
|
||||||
templates.add(mimeTypeLookupTemplate);
|
templates.add(mimeTypeLookupTemplate);
|
||||||
|
|
||||||
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithHashAndFileType.class.getCanonicalName(), IngestJobSettings.IngestType.FILES_ONLY, templates);
|
IngestJobSettings ingestJobSettings = new IngestJobSettings(IngestedWithHashAndFileTypeIntraCaseTests.class.getCanonicalName(), IngestJobSettings.IngestType.FILES_ONLY, templates);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings);
|
IngestUtils.runIngestJob(Case.getCurrentCaseThrows().getDataSources(), ingestJobSettings);
|
||||||
@ -104,23 +105,23 @@ public class MatchesInAtLeastTwoSources extends NbTestCase {
|
|||||||
try {
|
try {
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, false, false);
|
AbstractCommonAttributeSearcher allSourcesBuilder = new AllIntraCaseCommonAttributeSearcher(dataSources, false, false);
|
||||||
CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles();
|
CommonAttributeSearchResults metadata = allSourcesBuilder.findFiles();
|
||||||
|
|
||||||
Map<Long, String> objectIdToDataSource = IntraCaseUtils.mapFileInstancesToDataSources(metadata);
|
Map<Long, String> objectIdToDataSource = IntraCaseTestUtils.mapFileInstancesToDataSources(metadata);
|
||||||
|
|
||||||
List<AbstractFile> files = IntraCaseUtils.getFiles(objectIdToDataSource.keySet());
|
List<AbstractFile> files = IntraCaseTestUtils.getFiles(objectIdToDataSource.keySet());
|
||||||
|
|
||||||
assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, dataSources, IMG, SET1, 0));
|
assertTrue(IntraCaseTestUtils.verifyInstanceExistanceAndCount(files, dataSources, IMG, SET1, 0));
|
||||||
assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, dataSources, IMG, SET4, 0));
|
assertTrue(IntraCaseTestUtils.verifyInstanceExistanceAndCount(files, dataSources, IMG, SET4, 0));
|
||||||
|
|
||||||
assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, dataSources, DOC, SET1, 0));
|
assertTrue(IntraCaseTestUtils.verifyInstanceExistanceAndCount(files, dataSources, DOC, SET1, 0));
|
||||||
assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, dataSources, DOC, SET4, 0));
|
assertTrue(IntraCaseTestUtils.verifyInstanceExistanceAndCount(files, dataSources, DOC, SET4, 0));
|
||||||
|
|
||||||
assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, dataSources, EMPTY, SET1, 0));
|
assertTrue(IntraCaseTestUtils.verifyInstanceExistanceAndCount(files, dataSources, EMPTY, SET1, 0));
|
||||||
assertTrue(IntraCaseUtils.verifyFileExistanceAndCount(files, dataSources, EMPTY, SET4, 0));
|
assertTrue(IntraCaseTestUtils.verifyInstanceExistanceAndCount(files, dataSources, EMPTY, SET4, 0));
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
} catch (NoCurrentCaseException | TskCoreException | SQLException | EamDbException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
Assert.fail(ex);
|
Assert.fail(ex);
|
||||||
}
|
}
|
@ -28,12 +28,13 @@ import org.netbeans.junit.NbTestCase;
|
|||||||
import org.openide.util.Exceptions;
|
import org.openide.util.Exceptions;
|
||||||
import org.python.icu.impl.Assert;
|
import org.python.icu.impl.Assert;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.AllDataSourcesCommonFilesAlgorithm;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadata;
|
import org.sleuthkit.autopsy.commonfilesearch.AllIntraCaseCommonAttributeSearcher;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.CommonFilesMetadataBuilder;
|
import org.sleuthkit.autopsy.commonfilesearch.CommonAttributeSearchResults;
|
||||||
import org.sleuthkit.autopsy.commonfilesearch.SingleDataSource;
|
import org.sleuthkit.autopsy.commonfilesearch.IntraCaseCommonAttributeSearcher;
|
||||||
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseUtils.SET1;
|
import org.sleuthkit.autopsy.commonfilesearch.SingleIntraCaseCommonAttributeSearcher;
|
||||||
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseUtils.getDataSourceIdByName;
|
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseTestUtils.SET1;
|
||||||
|
import static org.sleuthkit.autopsy.commonfilessearch.IntraCaseTestUtils.getDataSourceIdByName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,21 +46,21 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
* Add images set 1, set 2, set 3, and set 4 to case. Do not ingest.
|
* Add images set 1, set 2, set 3, and set 4 to case. Do not ingest.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class UningestedCases extends NbTestCase {
|
public class UningestedCasesIntraCaseTests extends NbTestCase {
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(UningestedCases.class).
|
NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(UningestedCasesIntraCaseTests.class).
|
||||||
clusters(".*").
|
clusters(".*").
|
||||||
enableModules(".*");
|
enableModules(".*");
|
||||||
return conf.suite();
|
return conf.suite();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final IntraCaseUtils utils;
|
private final IntraCaseTestUtils utils;
|
||||||
|
|
||||||
public UningestedCases(String name) {
|
public UningestedCasesIntraCaseTests(String name) {
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
this.utils = new IntraCaseUtils(this, "UningestedCasesTests");
|
this.utils = new IntraCaseTestUtils(this, "UningestedCasesTests");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -80,13 +81,13 @@ public class UningestedCases extends NbTestCase {
|
|||||||
try {
|
try {
|
||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
|
|
||||||
CommonFilesMetadataBuilder allSourcesBuilder = new AllDataSourcesCommonFilesAlgorithm(dataSources, false, false);
|
IntraCaseCommonAttributeSearcher allSourcesBuilder = new AllIntraCaseCommonAttributeSearcher(dataSources, false, false);
|
||||||
CommonFilesMetadata metadata = allSourcesBuilder.findCommonFiles();
|
CommonAttributeSearchResults metadata = allSourcesBuilder.findFiles();
|
||||||
|
|
||||||
int resultCount = metadata.size();
|
int resultCount = metadata.size();
|
||||||
assertEquals(resultCount, 0);
|
assertEquals(resultCount, 0);
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
} catch (TskCoreException | NoCurrentCaseException | SQLException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
Assert.fail(ex);
|
Assert.fail(ex);
|
||||||
}
|
}
|
||||||
@ -100,13 +101,13 @@ public class UningestedCases extends NbTestCase {
|
|||||||
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
Map<Long, String> dataSources = this.utils.getDataSourceMap();
|
||||||
Long first = getDataSourceIdByName(SET1, dataSources);
|
Long first = getDataSourceIdByName(SET1, dataSources);
|
||||||
|
|
||||||
CommonFilesMetadataBuilder singleSourceBuilder = new SingleDataSource(first, dataSources, false, false);
|
IntraCaseCommonAttributeSearcher singleSourceBuilder = new SingleIntraCaseCommonAttributeSearcher(first, dataSources, false, false);
|
||||||
CommonFilesMetadata metadata = singleSourceBuilder.findCommonFiles();
|
CommonAttributeSearchResults metadata = singleSourceBuilder.findFiles();
|
||||||
|
|
||||||
int resultCount = metadata.size();
|
int resultCount = metadata.size();
|
||||||
assertEquals(resultCount, 0);
|
assertEquals(resultCount, 0);
|
||||||
|
|
||||||
} catch (NoCurrentCaseException | TskCoreException | SQLException ex) {
|
} catch (TskCoreException | NoCurrentCaseException | SQLException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
Assert.fail(ex);
|
Assert.fail(ex);
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user