mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge branch 'develop' of https://github.com/sleuthkit/autopsy into 1110-no-prepop-2
# Conflicts: # ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java
This commit is contained in:
commit
d5bd765c9b
@ -116,6 +116,7 @@ import org.sleuthkit.datamodel.Report;
|
|||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
|
import org.sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Autopsy case. Currently, only one case at a time may be open.
|
* An Autopsy case. Currently, only one case at a time may be open.
|
||||||
@ -707,11 +708,15 @@ public class Case {
|
|||||||
"Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
|
"Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
|
||||||
})
|
})
|
||||||
public static void deleteCase(CaseMetadata metadata) throws CaseActionException {
|
public static void deleteCase(CaseMetadata metadata) throws CaseActionException {
|
||||||
|
StopWatch stopWatch = new StopWatch();
|
||||||
|
stopWatch.start();
|
||||||
synchronized (caseActionSerializationLock) {
|
synchronized (caseActionSerializationLock) {
|
||||||
if (null != currentCase) {
|
if (null != currentCase) {
|
||||||
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
|
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to acquire caseActionSerializationLock (Java monitor in Case class) for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up either a GUI progress indicator without a cancel button (can't
|
* Set up either a GUI progress indicator without a cancel button (can't
|
||||||
@ -733,10 +738,19 @@ public class Case {
|
|||||||
* cannot be deleted if another node has it open.
|
* cannot be deleted if another node has it open.
|
||||||
*/
|
*/
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_checkingForOtherUser());
|
progressIndicator.progress(Bundle.Case_progressMessage_checkingForOtherUser());
|
||||||
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
try (CoordinationService.Lock dirLock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, metadata.getCaseDirectory())) {
|
try (CoordinationService.Lock dirLock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, metadata.getCaseDirectory())) {
|
||||||
assert (null != dirLock);
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to acquire case directory coordination service lock for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
|
if (dirLock != null) {
|
||||||
deleteCase(metadata, progressIndicator);
|
deleteCase(metadata, progressIndicator);
|
||||||
|
} else {
|
||||||
|
throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
|
||||||
|
}
|
||||||
} catch (CoordinationServiceException ex) {
|
} catch (CoordinationServiceException ex) {
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to fail to acquire case directory coordination service lock for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
|
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -946,11 +960,13 @@ public class Case {
|
|||||||
"Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
|
"Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
|
||||||
})
|
})
|
||||||
private static void deleteCase(CaseMetadata metadata, ProgressIndicator progressIndicator) throws CaseActionException {
|
private static void deleteCase(CaseMetadata metadata, ProgressIndicator progressIndicator) throws CaseActionException {
|
||||||
|
StopWatch stopWatch = new StopWatch();
|
||||||
boolean errorsOccurred = false;
|
boolean errorsOccurred = false;
|
||||||
if (CaseType.MULTI_USER_CASE == metadata.getCaseType()) {
|
if (CaseType.MULTI_USER_CASE == metadata.getCaseType()) {
|
||||||
/*
|
/*
|
||||||
* Delete the case database from the database server.
|
* Delete the case database from the database server.
|
||||||
*/
|
*/
|
||||||
|
stopWatch.start();
|
||||||
try {
|
try {
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDatabase());
|
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDatabase());
|
||||||
CaseDbConnectionInfo db;
|
CaseDbConnectionInfo db;
|
||||||
@ -960,10 +976,14 @@ public class Case {
|
|||||||
Statement statement = connection.createStatement();) {
|
Statement statement = connection.createStatement();) {
|
||||||
String deleteCommand = "DROP DATABASE \"" + metadata.getCaseDatabaseName() + "\""; //NON-NLS
|
String deleteCommand = "DROP DATABASE \"" + metadata.getCaseDatabaseName() + "\""; //NON-NLS
|
||||||
statement.execute(deleteCommand);
|
statement.execute(deleteCommand);
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to delete case database for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
}
|
}
|
||||||
} catch (UserPreferencesException | ClassNotFoundException | SQLException ex) {
|
} catch (UserPreferencesException | ClassNotFoundException | SQLException ex) {
|
||||||
logger.log(Level.SEVERE, String.format("Failed to delete case database %s for %s (%s) in %s", metadata.getCaseDatabaseName(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
|
logger.log(Level.SEVERE, String.format("Failed to delete case database %s for %s (%s) in %s", metadata.getCaseDatabaseName(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
|
||||||
errorsOccurred = true;
|
errorsOccurred = true;
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to fail delete case database for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -973,10 +993,16 @@ public class Case {
|
|||||||
progressIndicator.progress(Bundle.Case_progressMessage_deletingTextIndex());
|
progressIndicator.progress(Bundle.Case_progressMessage_deletingTextIndex());
|
||||||
for (KeywordSearchService searchService : Lookup.getDefault().lookupAll(KeywordSearchService.class)) {
|
for (KeywordSearchService searchService : Lookup.getDefault().lookupAll(KeywordSearchService.class)) {
|
||||||
try {
|
try {
|
||||||
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
searchService.deleteTextIndex(metadata);
|
searchService.deleteTextIndex(metadata);
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to delete text index for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
} catch (KeywordSearchServiceException ex) {
|
} catch (KeywordSearchServiceException ex) {
|
||||||
logger.log(Level.SEVERE, String.format("Failed to delete text index for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
|
logger.log(Level.SEVERE, String.format("Failed to delete text index for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
|
||||||
errorsOccurred = true;
|
errorsOccurred = true;
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to fail to delete text index for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -984,9 +1010,16 @@ public class Case {
|
|||||||
* Delete the case directory.
|
* Delete the case directory.
|
||||||
*/
|
*/
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDirectory());
|
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDirectory());
|
||||||
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
if (!FileUtil.deleteDir(new File(metadata.getCaseDirectory()))) {
|
if (!FileUtil.deleteDir(new File(metadata.getCaseDirectory()))) {
|
||||||
logger.log(Level.SEVERE, String.format("Failed to delete case directory for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
logger.log(Level.SEVERE, String.format("Failed to delete case directory for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
errorsOccurred = true;
|
errorsOccurred = true;
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to fail to delete case directory for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
|
} else {
|
||||||
|
stopWatch.stop();
|
||||||
|
logger.log(Level.INFO, String.format("Used %d s to delete case directory for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1540,11 +1573,13 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies case event subscribers that a central repository comment has been changed.
|
* Notifies case event subscribers that a central repository comment has
|
||||||
|
* been changed.
|
||||||
*
|
*
|
||||||
* This should not be called from the event dispatch thread (EDT)
|
* This should not be called from the event dispatch thread (EDT)
|
||||||
*
|
*
|
||||||
* @param contentId the objectId for the Content which has had its central repo comment changed
|
* @param contentId the objectId for the Content which has had its central
|
||||||
|
* repo comment changed
|
||||||
* @param newComment the new value of the comment
|
* @param newComment the new value of the comment
|
||||||
*/
|
*/
|
||||||
public void notifyCentralRepoCommentChanged(long contentId, String newComment) {
|
public void notifyCentralRepoCommentChanged(long contentId, String newComment) {
|
||||||
@ -1800,7 +1835,7 @@ public class Case {
|
|||||||
progressIndicator.progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
|
progressIndicator.progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
|
||||||
acquireSharedCaseDirLock(metadata.getCaseDirectory());
|
acquireSharedCaseDirLock(metadata.getCaseDirectory());
|
||||||
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(metadata.getCaseDirectory())) {
|
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(metadata.getCaseDirectory())) {
|
||||||
assert (null != resourcesLock);
|
assert(resourcesLock != null); // Use reference to avoid compile time warning.
|
||||||
open(isNewCase, progressIndicator);
|
open(isNewCase, progressIndicator);
|
||||||
} catch (CaseActionException ex) {
|
} catch (CaseActionException ex) {
|
||||||
releaseSharedCaseDirLock(getMetadata().getCaseDirectory());
|
releaseSharedCaseDirLock(getMetadata().getCaseDirectory());
|
||||||
@ -2375,7 +2410,7 @@ public class Case {
|
|||||||
* @throws CaseActionException with a user-friendly message if the lock
|
* @throws CaseActionException with a user-friendly message if the lock
|
||||||
* cannot be acquired.
|
* cannot be acquired.
|
||||||
*/
|
*/
|
||||||
@Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
|
@Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory"})
|
||||||
private void acquireSharedCaseDirLock(String caseDir) throws CaseActionException {
|
private void acquireSharedCaseDirLock(String caseDir) throws CaseActionException {
|
||||||
try {
|
try {
|
||||||
caseDirLock = CoordinationService.getInstance().tryGetSharedLock(CategoryNode.CASES, caseDir, DIR_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);
|
caseDirLock = CoordinationService.getInstance().tryGetSharedLock(CategoryNode.CASES, caseDir, DIR_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);
|
||||||
|
@ -369,7 +369,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor, AutoIngestDat
|
|||||||
@Override
|
@Override
|
||||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
||||||
List<String> filePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
|
List<String> filePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
|
||||||
run(deviceId, deviceId, filePaths, progressMonitor, callBack);
|
run(deviceId, "", filePaths, progressMonitor, callBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -419,7 +419,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we can correlate based on the MD5 if it is enabled
|
// we can correlate based on the MD5 if it is enabled
|
||||||
if (this.file != null && EamDb.isEnabled()) {
|
if (this.file != null && EamDb.isEnabled() && this.file.getSize() > 0) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
List<CorrelationAttributeInstance.Type> artifactTypes = EamDb.getInstance().getDefinedCorrelationTypes();
|
List<CorrelationAttributeInstance.Type> artifactTypes = EamDb.getInstance().getDefinedCorrelationTypes();
|
||||||
@ -447,11 +447,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
|||||||
} catch (EamDbException | TskCoreException ex) {
|
} catch (EamDbException | TskCoreException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
|
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
|
// If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
|
||||||
if (this.file != null) {
|
} else if (this.file != null && this.file.getSize() > 0) {
|
||||||
String md5 = this.file.getMd5Hash();
|
String md5 = this.file.getMd5Hash();
|
||||||
if (md5 != null && !md5.isEmpty()) {
|
if (md5 != null && !md5.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
@ -470,7 +467,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -657,9 +653,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
|||||||
// - The central repo is disabled and the backing file has a valid MD5 hash
|
// - The central repo is disabled and the backing file has a valid MD5 hash
|
||||||
this.file = this.getAbstractFileFromNode(node);
|
this.file = this.getAbstractFileFromNode(node);
|
||||||
if (EamDb.isEnabled()) {
|
if (EamDb.isEnabled()) {
|
||||||
return this.file != null
|
return !getCorrelationAttributesFromNode(node).isEmpty();
|
||||||
&& this.file.getSize() > 0
|
|
||||||
&& !getCorrelationAttributesFromNode(node).isEmpty();
|
|
||||||
} else {
|
} else {
|
||||||
return this.file != null
|
return this.file != null
|
||||||
&& this.file.getSize() > 0
|
&& this.file.getSize() > 0
|
||||||
@ -733,8 +727,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
|
|||||||
* Adjust a given column for the text provided.
|
* Adjust a given column for the text provided.
|
||||||
*
|
*
|
||||||
* @param columnIndex The index of the column to adjust.
|
* @param columnIndex The index of the column to adjust.
|
||||||
* @param text The text whose length will be used to adjust the column
|
* @param text The text whose length will be used to adjust the
|
||||||
* width.
|
* column width.
|
||||||
*/
|
*/
|
||||||
private void setColumnWidthToText(int columnIndex, String text) {
|
private void setColumnWidthToText(int columnIndex, String text) {
|
||||||
TableColumn column = otherCasesTable.getColumnModel().getColumn(columnIndex);
|
TableColumn column = otherCasesTable.getColumnModel().getColumn(columnIndex);
|
||||||
|
@ -2964,7 +2964,6 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
|
resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
|
||||||
resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
|
resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
|
||||||
|
|
||||||
|
|
||||||
return eamCase;
|
return eamCase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3080,6 +3079,7 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
|
|
||||||
ResultSet resultSet = null;
|
ResultSet resultSet = null;
|
||||||
Statement statement = null;
|
Statement statement = null;
|
||||||
|
PreparedStatement preparedStatement = null;
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@ -3114,6 +3114,10 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
logger.log(Level.INFO, "Central Repository is up to date");
|
logger.log(Level.INFO, "Central Repository is up to date");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) > 0) {
|
||||||
|
logger.log(Level.INFO, "Central Repository is of newer version than software creates");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Update from 1.0 to 1.1
|
// Update from 1.0 to 1.1
|
||||||
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
|
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
|
||||||
@ -3126,7 +3130,56 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
// regardless of whether this succeeds.
|
// regardless of whether this succeeds.
|
||||||
EamDbUtil.insertDefaultOrganization(conn);
|
EamDbUtil.insertDefaultOrganization(conn);
|
||||||
}
|
}
|
||||||
|
//Update to 1.2
|
||||||
|
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
|
||||||
|
//update central repository to be able to store new correlation attributes
|
||||||
|
EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
|
||||||
|
final String addSsidTableTemplate;
|
||||||
|
final String addCaseIdIndexTemplate;
|
||||||
|
final String addDataSourceIdIndexTemplate;
|
||||||
|
final String addValueIndexTemplate;
|
||||||
|
final String addKnownStatusIndexTemplate;
|
||||||
|
final String addAttributeSql;
|
||||||
|
//get the data base specific code for creating a new _instance table
|
||||||
|
switch (selectedPlatform) {
|
||||||
|
case POSTGRESQL:
|
||||||
|
addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause();
|
||||||
|
addSsidTableTemplate = PostgresEamDbSettings.getCreateArtifactInstancesTableTemplate();
|
||||||
|
addCaseIdIndexTemplate = PostgresEamDbSettings.getAddCaseIdIndexTemplate();
|
||||||
|
addDataSourceIdIndexTemplate = PostgresEamDbSettings.getAddDataSourceIdIndexTemplate();
|
||||||
|
addValueIndexTemplate = PostgresEamDbSettings.getAddValueIndexTemplate();
|
||||||
|
addKnownStatusIndexTemplate = PostgresEamDbSettings.getAddKnownStatusIndexTemplate();
|
||||||
|
break;
|
||||||
|
case SQLITE:
|
||||||
|
addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)";
|
||||||
|
addSsidTableTemplate = SqliteEamDbSettings.getCreateArtifactInstancesTableTemplate();
|
||||||
|
addCaseIdIndexTemplate = SqliteEamDbSettings.getAddCaseIdIndexTemplate();
|
||||||
|
addDataSourceIdIndexTemplate = SqliteEamDbSettings.getAddDataSourceIdIndexTemplate();
|
||||||
|
addValueIndexTemplate = SqliteEamDbSettings.getAddValueIndexTemplate();
|
||||||
|
addKnownStatusIndexTemplate = SqliteEamDbSettings.getAddKnownStatusIndexTemplate();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.");
|
||||||
|
}
|
||||||
|
final String wirelessNetworsDbTableName = "wireless_networks";
|
||||||
|
final String wirelessNetworksTableInstanceName = wirelessNetworsDbTableName + "_instances";
|
||||||
|
//add the wireless_networks attribute to the correlation_types table
|
||||||
|
preparedStatement = conn.prepareStatement(addAttributeSql);
|
||||||
|
preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
|
||||||
|
preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
|
||||||
|
preparedStatement.setString(3, wirelessNetworsDbTableName);
|
||||||
|
preparedStatement.setInt(4, 1);
|
||||||
|
preparedStatement.setInt(5, 1);
|
||||||
|
preparedStatement.execute();
|
||||||
|
|
||||||
|
//create a new wireless_networks_instances table and add indexes for its columns
|
||||||
|
statement.execute(String.format(addSsidTableTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
|
||||||
|
statement.execute(String.format(addCaseIdIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
|
||||||
|
statement.execute(String.format(addDataSourceIdIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
|
||||||
|
statement.execute(String.format(addValueIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
|
||||||
|
statement.execute(String.format(addKnownStatusIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
|
||||||
|
|
||||||
|
}
|
||||||
if (!updateSchemaVersion(conn)) {
|
if (!updateSchemaVersion(conn)) {
|
||||||
throw new EamDbException("Error updating schema version");
|
throw new EamDbException("Error updating schema version");
|
||||||
}
|
}
|
||||||
@ -3144,6 +3197,7 @@ abstract class AbstractSqlEamDb implements EamDb {
|
|||||||
throw ex;
|
throw ex;
|
||||||
} finally {
|
} finally {
|
||||||
EamDbUtil.closeResultSet(resultSet);
|
EamDbUtil.closeResultSet(resultSet);
|
||||||
|
EamDbUtil.closeStatement(preparedStatement);
|
||||||
EamDbUtil.closeStatement(statement);
|
EamDbUtil.closeStatement(statement);
|
||||||
EamDbUtil.closeConnection(conn);
|
EamDbUtil.closeConnection(conn);
|
||||||
}
|
}
|
||||||
|
@ -246,6 +246,7 @@ public class CorrelationAttributeInstance implements Serializable {
|
|||||||
public static final int EMAIL_TYPE_ID = 2;
|
public static final int EMAIL_TYPE_ID = 2;
|
||||||
public static final int PHONE_TYPE_ID = 3;
|
public static final int PHONE_TYPE_ID = 3;
|
||||||
public static final int USBID_TYPE_ID = 4;
|
public static final int USBID_TYPE_ID = 4;
|
||||||
|
public static final int SSID_TYPE_ID = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the default correlation types
|
* Load the default correlation types
|
||||||
@ -257,7 +258,8 @@ public class CorrelationAttributeInstance implements Serializable {
|
|||||||
"CorrelationType.DOMAIN.displayName=Domains",
|
"CorrelationType.DOMAIN.displayName=Domains",
|
||||||
"CorrelationType.EMAIL.displayName=Email Addresses",
|
"CorrelationType.EMAIL.displayName=Email Addresses",
|
||||||
"CorrelationType.PHONE.displayName=Phone Numbers",
|
"CorrelationType.PHONE.displayName=Phone Numbers",
|
||||||
"CorrelationType.USBID.displayName=USB Devices"})
|
"CorrelationType.USBID.displayName=USB Devices",
|
||||||
|
"CorrelationType.SSID.displayName=Wireless Networks"})
|
||||||
public static List<CorrelationAttributeInstance.Type> getDefaultCorrelationTypes() throws EamDbException {
|
public static List<CorrelationAttributeInstance.Type> getDefaultCorrelationTypes() throws EamDbException {
|
||||||
List<CorrelationAttributeInstance.Type> DEFAULT_CORRELATION_TYPES = new ArrayList<>();
|
List<CorrelationAttributeInstance.Type> DEFAULT_CORRELATION_TYPES = new ArrayList<>();
|
||||||
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS
|
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS
|
||||||
@ -265,6 +267,7 @@ public class CorrelationAttributeInstance implements Serializable {
|
|||||||
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(EMAIL_TYPE_ID, Bundle.CorrelationType_EMAIL_displayName(), "email_address", true, true)); // NON-NLS
|
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(EMAIL_TYPE_ID, Bundle.CorrelationType_EMAIL_displayName(), "email_address", true, true)); // NON-NLS
|
||||||
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS
|
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS
|
||||||
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS
|
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS
|
||||||
|
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(SSID_TYPE_ID, Bundle.CorrelationType_SSID_displayName(), "wireless_networks", true, true)); // NON-NLS
|
||||||
return DEFAULT_CORRELATION_TYPES;
|
return DEFAULT_CORRELATION_TYPES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,8 +289,9 @@ public class CorrelationAttributeInstance implements Serializable {
|
|||||||
* @param typeId Unique ID for this Correlation Type
|
* @param typeId Unique ID for this Correlation Type
|
||||||
* @param displayName Name of this type displayed in the UI.
|
* @param displayName Name of this type displayed in the UI.
|
||||||
* @param dbTableName Central repository db table where data of this
|
* @param dbTableName Central repository db table where data of this
|
||||||
* type is stored. Must start with a lowercase letter and only contain
|
* type is stored. Must start with a lowercase letter
|
||||||
* lowercase letters, numbers, and '_' characters.
|
* and only contain lowercase letters, numbers, and
|
||||||
|
* '_' characters.
|
||||||
* @param supported Is this Type currently supported
|
* @param supported Is this Type currently supported
|
||||||
* @param enabled Is this Type currently enabled.
|
* @param enabled Is this Type currently enabled.
|
||||||
*/
|
*/
|
||||||
@ -312,8 +316,9 @@ public class CorrelationAttributeInstance implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param displayName Name of this type displayed in the UI.
|
* @param displayName Name of this type displayed in the UI.
|
||||||
* @param dbTableName Central repository db table where data of this
|
* @param dbTableName Central repository db table where data of this
|
||||||
* type is stored Must start with a lowercase letter and only contain
|
* type is stored Must start with a lowercase letter
|
||||||
* lowercase letters, numbers, and '_' characters.
|
* and only contain lowercase letters, numbers, and
|
||||||
|
* '_' characters.
|
||||||
* @param supported Is this Type currently supported
|
* @param supported Is this Type currently supported
|
||||||
* @param enabled Is this Type currently enabled.
|
* @param enabled Is this Type currently enabled.
|
||||||
*/
|
*/
|
||||||
@ -477,8 +482,8 @@ public class CorrelationAttributeInstance implements Serializable {
|
|||||||
* custom_instances)
|
* custom_instances)
|
||||||
*
|
*
|
||||||
* @param dbTableName the dbTableName to set. Must start with lowercase
|
* @param dbTableName the dbTableName to set. Must start with lowercase
|
||||||
* letter and can only contain lowercase letters, numbers, and '_'
|
* letter and can only contain lowercase letters,
|
||||||
* characters.
|
* numbers, and '_' characters.
|
||||||
*
|
*
|
||||||
* @throws EamDbException if dbTableName contains invalid characters
|
* @throws EamDbException if dbTableName contains invalid characters
|
||||||
*/
|
*/
|
||||||
|
@ -63,6 +63,8 @@ final public class CorrelationAttributeNormalizer {
|
|||||||
return normalizePhone(data);
|
return normalizePhone(data);
|
||||||
case CorrelationAttributeInstance.USBID_TYPE_ID:
|
case CorrelationAttributeInstance.USBID_TYPE_ID:
|
||||||
return normalizeUsbId(data);
|
return normalizeUsbId(data);
|
||||||
|
case CorrelationAttributeInstance.SSID_TYPE_ID:
|
||||||
|
return data;
|
||||||
default:
|
default:
|
||||||
final String errorMessage = String.format(
|
final String errorMessage = String.format(
|
||||||
"Validator function not found for attribute type: %s",
|
"Validator function not found for attribute type: %s",
|
||||||
|
@ -159,13 +159,14 @@ public class EamArtifactUtil {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (correlationType.getId() == CorrelationAttributeInstance.USBID_TYPE_ID
|
} else if (correlationType.getId() == CorrelationAttributeInstance.USBID_TYPE_ID
|
||||||
&& BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeID) {
|
&& BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeID) {
|
||||||
|
|
||||||
value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID)).getValueString();
|
value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID)).getValueString();
|
||||||
|
} else if (correlationType.getId() == CorrelationAttributeInstance.SSID_TYPE_ID
|
||||||
|
&& BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID() == artifactTypeID) {
|
||||||
|
value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID)).getValueString();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
|
logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
|
||||||
return null;
|
return null;
|
||||||
@ -185,9 +186,10 @@ public class EamArtifactUtil {
|
|||||||
* Uses the determined type and vallue, then looks up instance details to
|
* Uses the determined type and vallue, then looks up instance details to
|
||||||
* create proper CorrelationAttributeInstance.
|
* create proper CorrelationAttributeInstance.
|
||||||
*
|
*
|
||||||
* @param bbArtifact the blackboard artifatc
|
* @param bbArtifact the blackboard artifact
|
||||||
* @param correlationType the given type
|
* @param correlationType the given type
|
||||||
* @param value the artifact value
|
* @param value the artifact value
|
||||||
|
*
|
||||||
* @return CorrelationAttributeInstance from details
|
* @return CorrelationAttributeInstance from details
|
||||||
*/
|
*/
|
||||||
private static CorrelationAttributeInstance makeCorrelationAttributeInstanceUsingTypeValue(BlackboardArtifact bbArtifact, CorrelationAttributeInstance.Type correlationType, String value) {
|
private static CorrelationAttributeInstance makeCorrelationAttributeInstanceUsingTypeValue(BlackboardArtifact bbArtifact, CorrelationAttributeInstance.Type correlationType, String value) {
|
||||||
|
@ -31,9 +31,9 @@ import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
|
|||||||
*/
|
*/
|
||||||
public interface EamDb {
|
public interface EamDb {
|
||||||
|
|
||||||
public static final int SCHEMA_VERSION = 1;
|
public static final int SCHEMA_VERSION = 2;
|
||||||
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
|
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
|
||||||
= new CaseDbSchemaVersionNumber(1, 1);
|
= new CaseDbSchemaVersionNumber(1, 2);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +36,8 @@ import org.sleuthkit.autopsy.coreutils.TextConverterException;
|
|||||||
/**
|
/**
|
||||||
* Settings for the Postgres implementation of the Central Repository database
|
* Settings for the Postgres implementation of the Central Repository database
|
||||||
*
|
*
|
||||||
* NOTE: This is public scope because the options panel calls it directly to set/get
|
* NOTE: This is public scope because the options panel calls it directly to
|
||||||
|
* set/get
|
||||||
*/
|
*/
|
||||||
public final class PostgresEamDbSettings {
|
public final class PostgresEamDbSettings {
|
||||||
|
|
||||||
@ -391,26 +392,13 @@ public final class PostgresEamDbSettings {
|
|||||||
createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)");
|
createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)");
|
||||||
createCorrelationTypesTable.append(")");
|
createCorrelationTypesTable.append(")");
|
||||||
|
|
||||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate();
|
||||||
StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
|
|
||||||
createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
|
|
||||||
createArtifactInstancesTableTemplate.append("id SERIAL PRIMARY KEY,");
|
|
||||||
createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("value text NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("comment text,");
|
|
||||||
createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique_ UNIQUE (data_source_id, value, file_path),");
|
|
||||||
createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
|
|
||||||
createArtifactInstancesTableTemplate.append(")");
|
|
||||||
|
|
||||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
String instancesIdx1 = getAddCaseIdIndexTemplate();
|
||||||
String instancesIdx1 = "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
|
String instancesIdx2 = getAddDataSourceIdIndexTemplate();
|
||||||
String instancesIdx2 = "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
|
|
||||||
String instancesIdx3 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
|
String instancesIdx3 = getAddValueIndexTemplate();
|
||||||
String instancesIdx4 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
|
String instancesIdx4 = getAddKnownStatusIndexTemplate();
|
||||||
|
|
||||||
StringBuilder createDbInfoTable = new StringBuilder();
|
StringBuilder createDbInfoTable = new StringBuilder();
|
||||||
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
|
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
|
||||||
@ -454,7 +442,7 @@ public final class PostgresEamDbSettings {
|
|||||||
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
|
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
|
||||||
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
|
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
|
||||||
|
|
||||||
stmt.execute(String.format(createArtifactInstancesTableTemplate.toString(), instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname));
|
||||||
stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
|
||||||
stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
|
||||||
stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
|
||||||
@ -480,6 +468,83 @@ public final class PostgresEamDbSettings {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template String for creating a new _instances table in a Postgres
|
||||||
|
* central repository. %s will exist in the template where the name of the
|
||||||
|
* new table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for cretating a new _instances table
|
||||||
|
*/
|
||||||
|
static String getCreateArtifactInstancesTableTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
|
||||||
|
createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
|
||||||
|
createArtifactInstancesTableTemplate.append("id SERIAL PRIMARY KEY,");
|
||||||
|
createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("value text NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("comment text,");
|
||||||
|
createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique_ UNIQUE (data_source_id, value, file_path),");
|
||||||
|
createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
|
||||||
|
createArtifactInstancesTableTemplate.append(")");
|
||||||
|
return createArtifactInstancesTableTemplate.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the case_id column of an
|
||||||
|
* instance table. %s will exist in the template where the name of the new
|
||||||
|
* table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the case_id
|
||||||
|
* column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddCaseIdIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the data_source_id column of an
|
||||||
|
* instance table. %s will exist in the template where the name of the new
|
||||||
|
* table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the
|
||||||
|
* data_source_id column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddDataSourceIdIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the value column of an instance
|
||||||
|
* table. %s will exist in the template where the name of the new table will
|
||||||
|
* be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the value
|
||||||
|
* column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddValueIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the known_status column of an
|
||||||
|
* instance table. %s will exist in the template where the name of the new
|
||||||
|
* table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the
|
||||||
|
* known_status column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddKnownStatusIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
|
||||||
|
}
|
||||||
|
|
||||||
public boolean insertDefaultDatabaseContent() {
|
public boolean insertDefaultDatabaseContent() {
|
||||||
Connection conn = getEphemeralConnection(false);
|
Connection conn = getEphemeralConnection(false);
|
||||||
if (null == conn) {
|
if (null == conn) {
|
||||||
|
@ -36,7 +36,8 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
|||||||
/**
|
/**
|
||||||
* Settings for the sqlite implementation of the Central Repository database
|
* Settings for the sqlite implementation of the Central Repository database
|
||||||
*
|
*
|
||||||
* NOTE: This is public scope because the options panel calls it directly to set/get
|
* NOTE: This is public scope because the options panel calls it directly to
|
||||||
|
* set/get
|
||||||
*/
|
*/
|
||||||
public final class SqliteEamDbSettings {
|
public final class SqliteEamDbSettings {
|
||||||
|
|
||||||
@ -103,11 +104,11 @@ public final class SqliteEamDbSettings {
|
|||||||
*/
|
*/
|
||||||
public boolean dbFileExists() {
|
public boolean dbFileExists() {
|
||||||
File dbFile = new File(getFileNameWithPath());
|
File dbFile = new File(getFileNameWithPath());
|
||||||
if(! dbFile.exists()){
|
if (!dbFile.exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// It's unlikely, but make sure the file isn't actually a directory
|
// It's unlikely, but make sure the file isn't actually a directory
|
||||||
return ( ! dbFile.isDirectory());
|
return (!dbFile.isDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,6 +152,7 @@ public final class SqliteEamDbSettings {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete the database
|
* Delete the database
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public boolean deleteDatabase() {
|
public boolean deleteDatabase() {
|
||||||
@ -333,26 +335,13 @@ public final class SqliteEamDbSettings {
|
|||||||
createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)");
|
createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)");
|
||||||
createCorrelationTypesTable.append(")");
|
createCorrelationTypesTable.append(")");
|
||||||
|
|
||||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate();
|
||||||
StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
|
|
||||||
createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
|
|
||||||
createArtifactInstancesTableTemplate.append("id integer primary key autoincrement NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("value text NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("comment text,");
|
|
||||||
createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path) ON CONFLICT IGNORE,");
|
|
||||||
createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
|
|
||||||
createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
|
|
||||||
createArtifactInstancesTableTemplate.append(")");
|
|
||||||
|
|
||||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
String instancesIdx1 = getAddCaseIdIndexTemplate();
|
||||||
String instancesIdx1 = "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
|
String instancesIdx2 = getAddDataSourceIdIndexTemplate();
|
||||||
String instancesIdx2 = "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
|
|
||||||
String instancesIdx3 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
|
String instancesIdx3 = getAddValueIndexTemplate();
|
||||||
String instancesIdx4 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
|
String instancesIdx4 = getAddKnownStatusIndexTemplate();
|
||||||
|
|
||||||
StringBuilder createDbInfoTable = new StringBuilder();
|
StringBuilder createDbInfoTable = new StringBuilder();
|
||||||
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
|
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
|
||||||
@ -402,7 +391,7 @@ public final class SqliteEamDbSettings {
|
|||||||
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
|
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
|
||||||
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
|
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
|
||||||
|
|
||||||
stmt.execute(String.format(createArtifactInstancesTableTemplate.toString(), instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname));
|
||||||
stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
|
||||||
stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
|
||||||
stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
|
stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
|
||||||
@ -427,6 +416,83 @@ public final class SqliteEamDbSettings {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template String for creating a new _instances table in a Sqlite
|
||||||
|
* central repository. %s will exist in the template where the name of the
|
||||||
|
* new table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for cretating a new _instances table
|
||||||
|
*/
|
||||||
|
static String getCreateArtifactInstancesTableTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
|
||||||
|
createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
|
||||||
|
createArtifactInstancesTableTemplate.append("id integer primary key autoincrement NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("value text NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("comment text,");
|
||||||
|
createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path) ON CONFLICT IGNORE,");
|
||||||
|
createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
|
||||||
|
createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
|
||||||
|
createArtifactInstancesTableTemplate.append(")");
|
||||||
|
return createArtifactInstancesTableTemplate.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the case_id column of an
|
||||||
|
* instance table. %s will exist in the template where the name of the new
|
||||||
|
* table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the case_id
|
||||||
|
* column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddCaseIdIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the data_source_id column of an
|
||||||
|
* instance table. %s will exist in the template where the name of the new
|
||||||
|
* table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the
|
||||||
|
* data_source_id column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddDataSourceIdIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the value column of an instance
|
||||||
|
* table. %s will exist in the template where the name of the new table will
|
||||||
|
* be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the value
|
||||||
|
* column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddValueIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the template for creating an index on the known_status column of an
|
||||||
|
* instance table. %s will exist in the template where the name of the new
|
||||||
|
* table will be addedd.
|
||||||
|
*
|
||||||
|
* @return a String which is a template for adding an index to the
|
||||||
|
* known_status column of a _instances table
|
||||||
|
*/
|
||||||
|
static String getAddKnownStatusIndexTemplate() {
|
||||||
|
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||||
|
return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
|
||||||
|
}
|
||||||
|
|
||||||
public boolean insertDefaultDatabaseContent() {
|
public boolean insertDefaultDatabaseContent() {
|
||||||
Connection conn = getEphemeralConnection();
|
Connection conn = getEphemeralConnection();
|
||||||
if (null == conn) {
|
if (null == conn) {
|
||||||
@ -490,8 +556,6 @@ public final class SqliteEamDbSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the dbDirectory
|
* @return the dbDirectory
|
||||||
*/
|
*/
|
||||||
|
@ -183,7 +183,10 @@ public class IngestEventsListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
if (getCeModuleInstanceCount() > 0) {
|
//if ingest is running we want there to check if there is a Correlation Engine module running
|
||||||
|
//sometimes artifacts are generated by DSPs or other sources while ingest is not running
|
||||||
|
//in these cases we still want to create correlation attributes for those artifacts when appropriate
|
||||||
|
if (!IngestManager.getInstance().isIngestRunning() || getCeModuleInstanceCount() > 0) {
|
||||||
EamDb dbManager;
|
EamDb dbManager;
|
||||||
try {
|
try {
|
||||||
dbManager = EamDb.getInstance();
|
dbManager = EamDb.getInstance();
|
||||||
@ -193,7 +196,9 @@ public class IngestEventsListener {
|
|||||||
}
|
}
|
||||||
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
|
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
|
||||||
case DATA_ADDED: {
|
case DATA_ADDED: {
|
||||||
jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, isFlagNotableItems()));
|
//if ingest isn't running create the interesting items otherwise use the ingest module setting to determine if we create interesting items
|
||||||
|
boolean flagNotable = !IngestManager.getInstance().isIngestRunning() || isFlagNotableItems();
|
||||||
|
jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, flagNotable));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,6 @@ final class IngestModule implements FileIngestModule {
|
|||||||
private CorrelationDataSource eamDataSource;
|
private CorrelationDataSource eamDataSource;
|
||||||
private Blackboard blackboard;
|
private Blackboard blackboard;
|
||||||
private CorrelationAttributeInstance.Type filesType;
|
private CorrelationAttributeInstance.Type filesType;
|
||||||
|
|
||||||
private final boolean flagTaggedNotableItems;
|
private final boolean flagTaggedNotableItems;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -34,7 +34,7 @@ AddNewOrganizationDialog.bnOK.text=OK
|
|||||||
AddNewOrganizationDialog.tfName.tooltip=POC Name
|
AddNewOrganizationDialog.tfName.tooltip=POC Name
|
||||||
ManageTagsDialog.okButton.text=OK
|
ManageTagsDialog.okButton.text=OK
|
||||||
ManageTagsDialog.cancelButton.text=Cancel
|
ManageTagsDialog.cancelButton.text=Cancel
|
||||||
ManageArtifactTypesDialog.taInstructionsMsg.text=Enable one or more correlation properties to use for correlation during ingest. Note, these properties are global and impact all users of the central repository.
|
ManageArtifactTypesDialog.taInstructionsMsg.text=Enable one or more correlation properties to use for correlation during ingest. Note, these properties are global and impact all users of the Central Repository.
|
||||||
EamSqliteSettingsDialog.bnOk.text=OK
|
EamSqliteSettingsDialog.bnOk.text=OK
|
||||||
EamPostgresSettingsDialog.bnSave.text=Save
|
EamPostgresSettingsDialog.bnSave.text=Save
|
||||||
EamDbSettingsDialog.bnDatabasePathFileOpen.text=Browse...
|
EamDbSettingsDialog.bnDatabasePathFileOpen.text=Browse...
|
||||||
@ -58,11 +58,10 @@ ManageCorrelationPropertiesDialog.okButton.text=OK
|
|||||||
GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties
|
GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties
|
||||||
EamDbSettingsDialog.lbDatabaseDesc.text=Database File:
|
EamDbSettingsDialog.lbDatabaseDesc.text=Database File:
|
||||||
EamDbSettingsDialog.lbFullDbPath.text=
|
EamDbSettingsDialog.lbFullDbPath.text=
|
||||||
GlobalSettingsPanel.cbUseCentralRepo.text=Use a central repository
|
GlobalSettingsPanel.cbUseCentralRepo.text=Use a Central Repository
|
||||||
GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation.\n
|
GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the Central Repository.
|
||||||
GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the central repository.
|
|
||||||
GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations
|
GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations
|
||||||
GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases.
|
GlobalSettingsPanel.lbCentralRepository.text=A Central Repository allows you to correlate files and results between cases.
|
||||||
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
|
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
|
||||||
GlobalSettingsPanel.organizationPanel.border.title=Organizations
|
GlobalSettingsPanel.organizationPanel.border.title=Organizations
|
||||||
GlobalSettingsPanel.casesPanel.border.title=Case Details
|
GlobalSettingsPanel.casesPanel.border.title=Case Details
|
||||||
@ -74,8 +73,9 @@ ShowCasesDialog.caseDetailsTable.toolTipText=Click column name to sort. Right-cl
|
|||||||
ShowCasesDialog.title=Case Details
|
ShowCasesDialog.title=Case Details
|
||||||
GlobalSettingsPanel.Case\ Details.AccessibleContext.accessibleName=Cases Details
|
GlobalSettingsPanel.Case\ Details.AccessibleContext.accessibleName=Cases Details
|
||||||
ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription=Click column name to sort.
|
ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription=Click column name to sort.
|
||||||
GlobalSettingsPanel.casesTextArea.text=Display table that lists central repository case details.
|
GlobalSettingsPanel.casesTextArea.text=Display table that lists Central Repository case details.
|
||||||
GlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to central repository settings when ingest is running!
|
GlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to Central Repository settings when ingest is running!
|
||||||
|
GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the Central Repository for later correlation.\n
|
||||||
ManageCasesDialog.examinerPhoneLabel.text=Examiner Phone:
|
ManageCasesDialog.examinerPhoneLabel.text=Examiner Phone:
|
||||||
ManageCasesDialog.examinerNameLabel.text=Examiner Name:
|
ManageCasesDialog.examinerNameLabel.text=Examiner Name:
|
||||||
ManageCasesDialog.examinerEmailLabel.text=Examiner Email:
|
ManageCasesDialog.examinerEmailLabel.text=Examiner Email:
|
||||||
|
@ -102,7 +102,7 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
return "Directories and central repository databases";
|
return "Directories and Central Repository databases";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
cbDatabaseType.setSelectedItem(selectedPlatform);
|
cbDatabaseType.setSelectedItem(selectedPlatform);
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="lbCentralRepository" pref="1022" max="32767" attributes="0"/>
|
<Component id="lbCentralRepository" max="32767" attributes="0"/>
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
|
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
|
||||||
@ -67,7 +67,7 @@
|
|||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Component id="cbUseCentralRepo" min="-2" pref="162" max="-2" attributes="0"/>
|
<Component id="cbUseCentralRepo" min="-2" pref="162" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
<Component id="ingestRunningWarningLabel" max="32767" attributes="0"/>
|
<Component id="ingestRunningWarningLabel" pref="844" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
@ -89,13 +89,13 @@
|
|||||||
</Group>
|
</Group>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
<Component id="pnDatabaseConfiguration" min="-2" max="-2" attributes="0"/>
|
<Component id="pnDatabaseConfiguration" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
<Component id="pnCorrelationProperties" min="-2" max="-2" attributes="0"/>
|
<Component id="pnCorrelationProperties" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
<Component id="organizationPanel" min="-2" max="-2" attributes="0"/>
|
<Component id="organizationPanel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
<Component id="casesPanel" min="-2" max="-2" attributes="0"/>
|
<Component id="casesPanel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
<Component id="tbOops" min="-2" max="-2" attributes="0"/>
|
<Component id="tbOops" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -242,14 +242,14 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" 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="correlationPropertiesScrollPane" max="32767" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
|
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
|
<Component id="correlationPropertiesScrollPane" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
@ -258,8 +258,7 @@
|
|||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
|
<Component id="correlationPropertiesScrollPane" pref="32" max="32767" attributes="0"/>
|
||||||
<Component id="correlationPropertiesScrollPane" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
|
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||||
@ -301,7 +300,7 @@
|
|||||||
<Font name="Tahoma" size="11" style="0"/>
|
<Font name="Tahoma" size="11" style="0"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="lineWrap" type="boolean" value="true"/>
|
<Property name="lineWrap" type="boolean" value="true"/>
|
||||||
<Property name="rows" type="int" value="2"/>
|
<Property name="rows" type="int" value="1"/>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.correlationPropertiesTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="GlobalSettingsPanel.correlationPropertiesTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
@ -334,7 +333,7 @@
|
|||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="organizationScrollPane" pref="992" max="32767" attributes="0"/>
|
<Component id="organizationScrollPane" max="32767" attributes="0"/>
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/>
|
<Component id="manageOrganizationButton" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
|
@ -222,7 +222,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
correlationPropertiesTextArea.setColumns(20);
|
correlationPropertiesTextArea.setColumns(20);
|
||||||
correlationPropertiesTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
|
correlationPropertiesTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
|
||||||
correlationPropertiesTextArea.setLineWrap(true);
|
correlationPropertiesTextArea.setLineWrap(true);
|
||||||
correlationPropertiesTextArea.setRows(2);
|
correlationPropertiesTextArea.setRows(1);
|
||||||
correlationPropertiesTextArea.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.correlationPropertiesTextArea.text")); // NOI18N
|
correlationPropertiesTextArea.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.correlationPropertiesTextArea.text")); // NOI18N
|
||||||
correlationPropertiesTextArea.setToolTipText("");
|
correlationPropertiesTextArea.setToolTipText("");
|
||||||
correlationPropertiesTextArea.setWrapStyleWord(true);
|
correlationPropertiesTextArea.setWrapStyleWord(true);
|
||||||
@ -236,17 +236,16 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
.addGroup(pnCorrelationPropertiesLayout.createSequentialGroup()
|
.addGroup(pnCorrelationPropertiesLayout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addGroup(pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(correlationPropertiesScrollPane)
|
|
||||||
.addGroup(pnCorrelationPropertiesLayout.createSequentialGroup()
|
.addGroup(pnCorrelationPropertiesLayout.createSequentialGroup()
|
||||||
.addComponent(bnManageTypes)
|
.addComponent(bnManageTypes)
|
||||||
.addGap(0, 0, Short.MAX_VALUE)))
|
.addGap(0, 0, Short.MAX_VALUE))
|
||||||
|
.addComponent(correlationPropertiesScrollPane))
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
pnCorrelationPropertiesLayout.setVerticalGroup(
|
pnCorrelationPropertiesLayout.setVerticalGroup(
|
||||||
pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnCorrelationPropertiesLayout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnCorrelationPropertiesLayout.createSequentialGroup()
|
||||||
.addGap(7, 7, 7)
|
.addComponent(correlationPropertiesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 32, Short.MAX_VALUE)
|
||||||
.addComponent(correlationPropertiesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(bnManageTypes)
|
.addComponent(bnManageTypes)
|
||||||
.addGap(8, 8, 8))
|
.addGap(8, 8, 8))
|
||||||
@ -281,7 +280,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
.addGroup(organizationPanelLayout.createSequentialGroup()
|
.addGroup(organizationPanelLayout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addGroup(organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(organizationScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 992, Short.MAX_VALUE)
|
.addComponent(organizationScrollPane)
|
||||||
.addGroup(organizationPanelLayout.createSequentialGroup()
|
.addGroup(organizationPanelLayout.createSequentialGroup()
|
||||||
.addComponent(manageOrganizationButton)
|
.addComponent(manageOrganizationButton)
|
||||||
.addGap(0, 0, Short.MAX_VALUE)))
|
.addGap(0, 0, Short.MAX_VALUE)))
|
||||||
@ -356,7 +355,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
jPanel1.setLayout(jPanel1Layout);
|
jPanel1.setLayout(jPanel1Layout);
|
||||||
jPanel1Layout.setHorizontalGroup(
|
jPanel1Layout.setHorizontalGroup(
|
||||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, 1022, Short.MAX_VALUE)
|
.addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
@ -366,7 +365,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addComponent(cbUseCentralRepo, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(cbUseCentralRepo, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
.addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 844, Short.MAX_VALUE))
|
||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||||
@ -382,13 +381,13 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
.addComponent(ingestRunningWarningLabel))
|
.addComponent(ingestRunningWarningLabel))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addGap(0, 0, 0)
|
||||||
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addGap(0, 0, 0)
|
||||||
.addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addGap(0, 0, 0)
|
||||||
.addComponent(casesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(casesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addGap(0, 0, 0)
|
||||||
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
|
@ -74,7 +74,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
|||||||
private final Outline outline;
|
private final Outline outline;
|
||||||
private ExplorerManager explorerManager;
|
private ExplorerManager explorerManager;
|
||||||
|
|
||||||
private NSDictionary rootDict;
|
private NSObject rootDict;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form PListViewer
|
* Creates new form PListViewer
|
||||||
@ -415,24 +415,37 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses given binary stream and extracts Plist key/value
|
* Parses given binary stream and extracts Plist key/value.
|
||||||
*
|
*
|
||||||
* @param plistbytes
|
* @param plistbytes The byte array containing the Plist data.
|
||||||
*
|
*
|
||||||
* @return list of PropKeyValue
|
* @return list of PropKeyValue
|
||||||
*/
|
*/
|
||||||
private List<PropKeyValue> parsePList(final byte[] plistbytes) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
|
private List<PropKeyValue> parsePList(final byte[] plistbytes) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
|
||||||
|
|
||||||
final List<PropKeyValue> plist = new ArrayList<>();
|
final List<PropKeyValue> plist = new ArrayList<>();
|
||||||
rootDict = (NSDictionary) PropertyListParser.parse(plistbytes);
|
rootDict = PropertyListParser.parse(plistbytes);
|
||||||
|
|
||||||
final String[] keys = rootDict.allKeys();
|
/*
|
||||||
for (final String key : keys) {
|
* Parse the data if the root is an NSArray or NSDictionary. Anything
|
||||||
final PropKeyValue pkv = parseProperty(key, rootDict.objectForKey(key));
|
* else is unexpected and will be ignored.
|
||||||
|
*/
|
||||||
|
if (rootDict instanceof NSArray) {
|
||||||
|
for (int i=0; i < ((NSArray)rootDict).count(); i++) {
|
||||||
|
final PropKeyValue pkv = parseProperty("", ((NSArray)rootDict).objectAtIndex(i));
|
||||||
if (null != pkv) {
|
if (null != pkv) {
|
||||||
plist.add(pkv);
|
plist.add(pkv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (rootDict instanceof NSDictionary) {
|
||||||
|
final String[] keys = ((NSDictionary)rootDict).allKeys();
|
||||||
|
for (final String key : keys) {
|
||||||
|
final PropKeyValue pkv = parseProperty(key, ((NSDictionary)rootDict).objectForKey(key));
|
||||||
|
if (null != pkv) {
|
||||||
|
plist.add(pkv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return plist;
|
return plist;
|
||||||
}
|
}
|
||||||
|
@ -487,7 +487,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
|||||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())
|
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID())
|
||||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())
|
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID())
|
||||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID())
|
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_OBJECT_DETECTED.getTypeID())
|
||||||
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID())) {
|
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID())
|
||||||
|
|| (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID())) {
|
||||||
return 3;
|
return 3;
|
||||||
} else {
|
} else {
|
||||||
return 6;
|
return 6;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2012-2015 Basis Technology Corp.
|
* Copyright 2012-2018 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,14 +18,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.coreutils;
|
package org.sleuthkit.autopsy.coreutils;
|
||||||
|
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
public class NetworkUtils {
|
public class NetworkUtils {
|
||||||
|
|
||||||
|
private NetworkUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the host name variable. Sometimes the network can be finicky, so the
|
* Set the host name variable. Sometimes the network can be finicky, so the
|
||||||
* answer returned by getHostName() could throw an exception or be null.
|
* answer returned by getHostName() could throw an exception or be null.
|
||||||
* Have it read the environment variable if getHostName() is unsuccessful.
|
* Have it read the environment variable if getHostName() is unsuccessful.
|
||||||
|
*
|
||||||
|
* @return the local host name
|
||||||
*/
|
*/
|
||||||
public static String getLocalHostName() {
|
public static String getLocalHostName() {
|
||||||
String hostName = "";
|
String hostName = "";
|
||||||
@ -41,4 +49,78 @@ public class NetworkUtils {
|
|||||||
}
|
}
|
||||||
return hostName;
|
return hostName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to manually extract the domain from a URL.
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @return empty string if no domain could be found
|
||||||
|
*/
|
||||||
|
private static String getBaseDomain(String url) {
|
||||||
|
String host = null;
|
||||||
|
|
||||||
|
//strip protocol
|
||||||
|
String cleanUrl = url.replaceFirst(".*:\\/\\/", "");
|
||||||
|
|
||||||
|
//strip after slashes
|
||||||
|
String dirToks[] = cleanUrl.split("\\/");
|
||||||
|
if (dirToks.length > 0) {
|
||||||
|
host = dirToks[0];
|
||||||
|
} else {
|
||||||
|
host = cleanUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the domain part from host (last 2)
|
||||||
|
StringTokenizer tok = new StringTokenizer(host, ".");
|
||||||
|
StringBuilder hostB = new StringBuilder();
|
||||||
|
int toks = tok.countTokens();
|
||||||
|
|
||||||
|
for (int count = 0; count < toks; ++count) {
|
||||||
|
String part = tok.nextToken();
|
||||||
|
int diff = toks - count;
|
||||||
|
if (diff < 3) {
|
||||||
|
hostB.append(part);
|
||||||
|
}
|
||||||
|
if (diff == 2) {
|
||||||
|
hostB.append(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String base = hostB.toString();
|
||||||
|
// verify there are no special characters in there
|
||||||
|
if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to extract the domain from a URL.
|
||||||
|
* Will start by using the built-in URL class, and if that fails will
|
||||||
|
* try to extract it manually.
|
||||||
|
*
|
||||||
|
* @param urlString The URL to extract the domain from
|
||||||
|
* @return empty string if no domain name was found
|
||||||
|
*/
|
||||||
|
public static String extractDomain(String urlString) {
|
||||||
|
if (urlString == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
String result = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
result = url.getHost();
|
||||||
|
} catch (MalformedURLException ex) {
|
||||||
|
//do not log if not a valid URL - we will try to extract it ourselves
|
||||||
|
}
|
||||||
|
|
||||||
|
//was not a valid URL, try a less picky method
|
||||||
|
if (result == null || result.trim().isEmpty()) {
|
||||||
|
return getBaseDomain(urlString);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.coreutils;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.SimpleTimeZone;
|
import java.util.SimpleTimeZone;
|
||||||
@ -45,7 +47,7 @@ public class TimeZoneUtils {
|
|||||||
java.util.TimeZone zone = java.util.TimeZone.getTimeZone(timeZoneId);
|
java.util.TimeZone zone = java.util.TimeZone.getTimeZone(timeZoneId);
|
||||||
int offset = zone.getRawOffset() / 1000;
|
int offset = zone.getRawOffset() / 1000;
|
||||||
int hour = offset / 3600;
|
int hour = offset / 3600;
|
||||||
int min = (offset % 3600) / 60;
|
int min = Math.abs((offset % 3600) / 60);
|
||||||
|
|
||||||
DateFormat dfm = new SimpleDateFormat("z");
|
DateFormat dfm = new SimpleDateFormat("z");
|
||||||
dfm.setTimeZone(zone);
|
dfm.setTimeZone(zone);
|
||||||
@ -74,7 +76,7 @@ public class TimeZoneUtils {
|
|||||||
public static String createTimeZoneString(TimeZone timeZone) {
|
public static String createTimeZoneString(TimeZone timeZone) {
|
||||||
int offset = timeZone.getRawOffset() / 1000;
|
int offset = timeZone.getRawOffset() / 1000;
|
||||||
int hour = offset / 3600;
|
int hour = offset / 3600;
|
||||||
int minutes = (offset % 3600) / 60;
|
int minutes = Math.abs((offset % 3600) / 60);
|
||||||
|
|
||||||
return String.format("(GMT%+d:%02d) %s", hour, minutes, timeZone.getID()); //NON-NLS
|
return String.format("(GMT%+d:%02d) %s", hour, minutes, timeZone.getID()); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -83,9 +85,11 @@ public class TimeZoneUtils {
|
|||||||
* Generates a list of time zones.
|
* Generates a list of time zones.
|
||||||
*/
|
*/
|
||||||
public static List<String> createTimeZoneList() {
|
public static List<String> createTimeZoneList() {
|
||||||
List<String> timeZoneList = new ArrayList<>();
|
/*
|
||||||
|
* Create a list of time zones.
|
||||||
|
*/
|
||||||
|
List<TimeZone> timeZoneList = new ArrayList<>();
|
||||||
|
|
||||||
// load and add all timezone
|
|
||||||
String[] ids = SimpleTimeZone.getAvailableIDs();
|
String[] ids = SimpleTimeZone.getAvailableIDs();
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
/*
|
/*
|
||||||
@ -97,10 +101,36 @@ public class TimeZoneUtils {
|
|||||||
* if(hasDaylight){ result = result + second; }
|
* if(hasDaylight){ result = result + second; }
|
||||||
* timeZoneComboBox.addItem(item + " (" + result + ")");
|
* timeZoneComboBox.addItem(item + " (" + result + ")");
|
||||||
*/
|
*/
|
||||||
timeZoneList.add(createTimeZoneString(TimeZone.getTimeZone(id)));
|
timeZoneList.add(TimeZone.getTimeZone(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return timeZoneList;
|
/*
|
||||||
|
* Sort the list of time zones first by offset, then by ID.
|
||||||
|
*/
|
||||||
|
Collections.sort(timeZoneList, new Comparator<TimeZone>(){
|
||||||
|
@Override
|
||||||
|
public int compare(TimeZone o1, TimeZone o2){
|
||||||
|
int offsetDelta = Integer.compare(o1.getRawOffset(), o2.getRawOffset());
|
||||||
|
|
||||||
|
if (offsetDelta == 0) {
|
||||||
|
return o1.getID().compareToIgnoreCase(o2.getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
return offsetDelta;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a list of Strings encompassing both the GMT offset and the
|
||||||
|
* time zone ID.
|
||||||
|
*/
|
||||||
|
List<String> outputList = new ArrayList<>();
|
||||||
|
|
||||||
|
for (TimeZone timeZone : timeZoneList) {
|
||||||
|
outputList.add(createTimeZoneString(timeZone));
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,6 +156,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
|
|||||||
return filePath + "drive_network.png"; //NON-NLS
|
return filePath + "drive_network.png"; //NON-NLS
|
||||||
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID()) {
|
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED.getTypeID()) {
|
||||||
return filePath + "face.png"; //NON-NLS
|
return filePath + "face.png"; //NON-NLS
|
||||||
|
} else if (typeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID()) {
|
||||||
|
return filePath + "network-wifi.png"; //NON-NLS
|
||||||
}
|
}
|
||||||
return filePath + "artifact-icon.png"; //NON-NLS
|
return filePath + "artifact-icon.png"; //NON-NLS
|
||||||
}
|
}
|
||||||
|
BIN
Core/src/org/sleuthkit/autopsy/images/network-wifi.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/network-wifi.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 453 B |
@ -21,9 +21,6 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -166,11 +163,12 @@ class SevenZipExtractor {
|
|||||||
*
|
*
|
||||||
* @param archiveFile the AbstractFile for the parent archive which
|
* @param archiveFile the AbstractFile for the parent archive which
|
||||||
* which we are checking
|
* which we are checking
|
||||||
* @param inArchive The SevenZip archive currently open for extraction
|
* @param inArchive The SevenZip archive currently open for
|
||||||
|
* extraction
|
||||||
*
|
*
|
||||||
* @param inArchiveItemIndex Index of item inside the SevenZip archive. Each
|
* @param inArchiveItemIndex Index of item inside the SevenZip archive. Each
|
||||||
* file inside an archive is associated with a unique
|
* file inside an archive is associated with a
|
||||||
* integer
|
* unique integer
|
||||||
*
|
*
|
||||||
* @param depthMap a concurrent hashmap which keeps track of the
|
* @param depthMap a concurrent hashmap which keeps track of the
|
||||||
* depth of all nested archives, key of objectID
|
* depth of all nested archives, key of objectID
|
||||||
@ -797,138 +795,55 @@ class SevenZipExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream used to unpack the archive to local file
|
* UnpackStream used by the SevenZipBindings to do archive extraction. A memory
|
||||||
|
* leak exists in the SevenZip library that will not let go of the streams until
|
||||||
|
* the entire archive extraction is complete. Instead of creating a new UnpackStream
|
||||||
|
* for every file in the archive, instead we just rebase our EncodedFileOutputStream pointer
|
||||||
|
* for every new file.
|
||||||
*/
|
*/
|
||||||
private abstract static class UnpackStream implements ISequentialOutStream {
|
private final static class UnpackStream implements ISequentialOutStream {
|
||||||
|
|
||||||
private OutputStream output;
|
private EncodedFileOutputStream output;
|
||||||
private String localAbsPath;
|
private String localAbsPath;
|
||||||
|
private int bytesWritten;
|
||||||
|
|
||||||
UnpackStream(String localAbsPath) {
|
UnpackStream(String localAbsPath) throws IOException {
|
||||||
|
this.output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
|
||||||
this.localAbsPath = localAbsPath;
|
this.localAbsPath = localAbsPath;
|
||||||
try {
|
this.bytesWritten = 0;
|
||||||
output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Error writing extracted file: " + localAbsPath, ex); //NON-NLS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setNewOutputStream(String localAbsPath) throws IOException {
|
||||||
|
this.output.close();
|
||||||
|
this.output = new EncodedFileOutputStream(new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
|
||||||
|
this.localAbsPath = localAbsPath;
|
||||||
|
this.bytesWritten = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract long getSize();
|
public int getSize() {
|
||||||
|
return bytesWritten;
|
||||||
OutputStream getOutput() {
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
String getLocalAbsPath() {
|
|
||||||
return localAbsPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
|
||||||
if (output != null) {
|
|
||||||
try {
|
|
||||||
output.flush();
|
|
||||||
output.close();
|
|
||||||
output = null;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing unpack stream for file: {0}", localAbsPath); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream used to unpack the archive of unknown size to local file
|
|
||||||
*/
|
|
||||||
private static class UnknownSizeUnpackStream extends UnpackStream {
|
|
||||||
|
|
||||||
private long freeDiskSpace;
|
|
||||||
private boolean outOfSpace = false;
|
|
||||||
private long bytesWritten = 0;
|
|
||||||
|
|
||||||
UnknownSizeUnpackStream(String localAbsPath, long freeDiskSpace) {
|
|
||||||
super(localAbsPath);
|
|
||||||
this.freeDiskSpace = freeDiskSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getSize() {
|
|
||||||
return this.bytesWritten;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int write(byte[] bytes) throws SevenZipException {
|
public int write(byte[] bytes) throws SevenZipException {
|
||||||
try {
|
try {
|
||||||
// If the content size is unknown, cautiously write to disk.
|
output.write(bytes);
|
||||||
// Write only if byte array is less than 80% of the current
|
|
||||||
// free disk space.
|
|
||||||
if (freeDiskSpace == IngestMonitor.DISK_FREE_SPACE_UNKNOWN || bytes.length < 0.8 * freeDiskSpace) {
|
|
||||||
getOutput().write(bytes);
|
|
||||||
// NOTE: this method is called multiple times for a
|
|
||||||
// single extractSlow() call. Update bytesWritten and
|
|
||||||
// freeDiskSpace after every write operation.
|
|
||||||
this.bytesWritten += bytes.length;
|
this.bytesWritten += bytes.length;
|
||||||
this.freeDiskSpace -= bytes.length;
|
|
||||||
} else {
|
|
||||||
this.outOfSpace = true;
|
|
||||||
logger.log(Level.INFO, NbBundle.getMessage(
|
|
||||||
SevenZipExtractor.class,
|
|
||||||
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg"));
|
|
||||||
throw new SevenZipException(
|
|
||||||
NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg"));
|
|
||||||
}
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new SevenZipException(
|
throw new SevenZipException(
|
||||||
NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg",
|
NbBundle.getMessage(SevenZipExtractor.class,
|
||||||
getLocalAbsPath()), ex);
|
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg",
|
||||||
|
localAbsPath), ex);
|
||||||
}
|
}
|
||||||
return bytes.length;
|
return bytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void close() throws IOException {
|
||||||
public void close() {
|
try(EncodedFileOutputStream out = output) {
|
||||||
if (getOutput() != null) {
|
out.flush();
|
||||||
try {
|
|
||||||
getOutput().flush();
|
|
||||||
getOutput().close();
|
|
||||||
if (this.outOfSpace) {
|
|
||||||
Files.delete(Paths.get(getLocalAbsPath()));
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing unpack stream for file: {0}", getLocalAbsPath()); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream used to unpack the archive of known size to local file
|
|
||||||
*/
|
|
||||||
private static class KnownSizeUnpackStream extends UnpackStream {
|
|
||||||
|
|
||||||
private long size;
|
|
||||||
|
|
||||||
KnownSizeUnpackStream(String localAbsPath, long size) {
|
|
||||||
super(localAbsPath);
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getSize() {
|
|
||||||
return this.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int write(byte[] bytes) throws SevenZipException {
|
|
||||||
try {
|
|
||||||
getOutput().write(bytes);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new SevenZipException(
|
|
||||||
NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg",
|
|
||||||
getLocalAbsPath()), ex);
|
|
||||||
}
|
|
||||||
return bytes.length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -975,7 +890,6 @@ class SevenZipExtractor {
|
|||||||
private final ProgressHandle progressHandle;
|
private final ProgressHandle progressHandle;
|
||||||
|
|
||||||
private int inArchiveItemIndex;
|
private int inArchiveItemIndex;
|
||||||
private final long freeDiskSpace;
|
|
||||||
|
|
||||||
private long createTimeInSeconds;
|
private long createTimeInSeconds;
|
||||||
private long modTimeInSeconds;
|
private long modTimeInSeconds;
|
||||||
@ -992,7 +906,6 @@ class SevenZipExtractor {
|
|||||||
String password, long freeDiskSpace) {
|
String password, long freeDiskSpace) {
|
||||||
|
|
||||||
this.inArchive = inArchive;
|
this.inArchive = inArchive;
|
||||||
this.freeDiskSpace = freeDiskSpace;
|
|
||||||
this.progressHandle = progressHandle;
|
this.progressHandle = progressHandle;
|
||||||
this.archiveFile = archiveFile;
|
this.archiveFile = archiveFile;
|
||||||
this.archiveDetailsMap = archiveDetailsMap;
|
this.archiveDetailsMap = archiveDetailsMap;
|
||||||
@ -1000,15 +913,17 @@ class SevenZipExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get stream is called by the internal framework as it traverses
|
* Get stream is called by the internal framework as it traverses the
|
||||||
* the archive structure. The ISequentialOutStream is where the
|
* archive structure. The ISequentialOutStream is where the archive file
|
||||||
* archive file contents will be expanded and written to the local disk.
|
* contents will be expanded and written to the local disk.
|
||||||
*
|
*
|
||||||
* Skips folders, as there is nothing to extract.
|
* Skips folders, as there is nothing to extract.
|
||||||
*
|
*
|
||||||
* @param inArchiveItemIndex current location of the
|
* @param inArchiveItemIndex current location of the
|
||||||
* @param mode Will always be EXTRACT
|
* @param mode Will always be EXTRACT
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
|
*
|
||||||
* @throws SevenZipException
|
* @throws SevenZipException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -1023,17 +938,24 @@ class SevenZipExtractor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Long archiveItemSize = (Long) inArchive.getProperty(
|
|
||||||
inArchiveItemIndex, PropID.SIZE);
|
|
||||||
final String localAbsPath = archiveDetailsMap.get(
|
final String localAbsPath = archiveDetailsMap.get(
|
||||||
inArchiveItemIndex).getLocalAbsPath();
|
inArchiveItemIndex).getLocalAbsPath();
|
||||||
|
|
||||||
if (archiveItemSize != null) {
|
//If the Unpackstream has been allocated, then set the Outputstream
|
||||||
unpackStream = new SevenZipExtractor.KnownSizeUnpackStream(
|
//to another file rather than creating a new unpack stream. The 7Zip
|
||||||
localAbsPath, archiveItemSize);
|
//binding has a memory leak, so creating new unpack streams will not be
|
||||||
|
//dereferenced. As a fix, we create one UnpackStream, and mutate its state,
|
||||||
|
//so that there only exists one 8192 byte buffer in memory per archive.
|
||||||
|
try {
|
||||||
|
if (unpackStream != null) {
|
||||||
|
unpackStream.setNewOutputStream(localAbsPath);
|
||||||
} else {
|
} else {
|
||||||
unpackStream = new SevenZipExtractor.UnknownSizeUnpackStream(
|
unpackStream = new UnpackStream(localAbsPath);
|
||||||
localAbsPath, freeDiskSpace);
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, String.format("Error opening or setting new stream " //NON-NLS
|
||||||
|
+ "for archive file at %s", localAbsPath), ex.getMessage()); //NON-NLS
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return unpackStream;
|
return unpackStream;
|
||||||
@ -1044,6 +966,7 @@ class SevenZipExtractor {
|
|||||||
* Called after getStream.
|
* Called after getStream.
|
||||||
*
|
*
|
||||||
* @param mode Will always be EXTRACT.
|
* @param mode Will always be EXTRACT.
|
||||||
|
*
|
||||||
* @throws SevenZipException
|
* @throws SevenZipException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -1103,7 +1026,11 @@ class SevenZipExtractor {
|
|||||||
!(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
|
!(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
|
||||||
0L, createTimeInSeconds, accessTimeInSeconds, modTimeInSeconds, localRelPath);
|
0L, createTimeInSeconds, accessTimeInSeconds, modTimeInSeconds, localRelPath);
|
||||||
|
|
||||||
|
try {
|
||||||
unpackStream.close();
|
unpackStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.log(Level.WARNING, "Error closing unpack stream for file: {0}", localAbsPath); //NON-NLS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -1214,9 +1141,9 @@ class SevenZipExtractor {
|
|||||||
*/
|
*/
|
||||||
List<AbstractFile> getRootFileObjects() {
|
List<AbstractFile> getRootFileObjects() {
|
||||||
List<AbstractFile> ret = new ArrayList<>();
|
List<AbstractFile> ret = new ArrayList<>();
|
||||||
for (UnpackedNode child : rootNode.getChildren()) {
|
rootNode.getChildren().forEach((child) -> {
|
||||||
ret.add(child.getFile());
|
ret.add(child.getFile());
|
||||||
}
|
});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1228,17 +1155,17 @@ class SevenZipExtractor {
|
|||||||
*/
|
*/
|
||||||
List<AbstractFile> getAllFileObjects() {
|
List<AbstractFile> getAllFileObjects() {
|
||||||
List<AbstractFile> ret = new ArrayList<>();
|
List<AbstractFile> ret = new ArrayList<>();
|
||||||
for (UnpackedNode child : rootNode.getChildren()) {
|
rootNode.getChildren().forEach((child) -> {
|
||||||
getAllFileObjectsRec(ret, child);
|
getAllFileObjectsRec(ret, child);
|
||||||
}
|
});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getAllFileObjectsRec(List<AbstractFile> list, UnpackedNode parent) {
|
private void getAllFileObjectsRec(List<AbstractFile> list, UnpackedNode parent) {
|
||||||
list.add(parent.getFile());
|
list.add(parent.getFile());
|
||||||
for (UnpackedNode child : parent.getChildren()) {
|
parent.getChildren().forEach((child) -> {
|
||||||
getAllFileObjectsRec(list, child);
|
getAllFileObjectsRec(list, child);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,7 +91,7 @@ HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg=Failed to open has
|
|||||||
HashLookupModuleFactory.moduleName.text=Hash Lookup
|
HashLookupModuleFactory.moduleName.text=Hash Lookup
|
||||||
HashLookupModuleFactory.moduleDescription.text=Identifies known and notable files using supplied hash sets, such as a standard NSRL hash set.
|
HashLookupModuleFactory.moduleDescription.text=Identifies known and notable files using supplied hash sets, such as a standard NSRL hash set.
|
||||||
HashDbIngestModule.fileReadErrorMsg=Read Error\: {0}
|
HashDbIngestModule.fileReadErrorMsg=Read Error\: {0}
|
||||||
HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0}.
|
HashDbIngestModule.calcHashValueErr=Error encountered while calculating the hash value for {0} ({1}).
|
||||||
HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error\: {0}
|
HashDbIngestModule.hashLookupErrorMsg=Hash Lookup Error\: {0}
|
||||||
HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}.
|
HashDbIngestModule.settingKnownBadStateErr=Error encountered while setting notable state for {0}.
|
||||||
HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.
|
HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.
|
||||||
|
@ -229,7 +229,9 @@ public class HashDbIngestModule implements FileIngestModule {
|
|||||||
services.postMessage(IngestMessage.createErrorMessage(
|
services.postMessage(IngestMessage.createErrorMessage(
|
||||||
HashLookupModuleFactory.getModuleName(),
|
HashLookupModuleFactory.getModuleName(),
|
||||||
NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", name),
|
NbBundle.getMessage(this.getClass(), "HashDbIngestModule.fileReadErrorMsg", name),
|
||||||
NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr", name)));
|
NbBundle.getMessage(this.getClass(), "HashDbIngestModule.calcHashValueErr",
|
||||||
|
file.getParentPath() + file.getName(),
|
||||||
|
file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)?"Allocated File" : "Deleted File")));
|
||||||
return ProcessResult.ERROR;
|
return ProcessResult.ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,7 +471,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
|
|||||||
if (!this.nameTextField.getText().isEmpty()) {
|
if (!this.nameTextField.getText().isEmpty()) {
|
||||||
if (this.nameRegexCheckbox.isSelected()) {
|
if (this.nameRegexCheckbox.isSelected()) {
|
||||||
try {
|
try {
|
||||||
Pattern pattern = Pattern.compile(this.nameTextField.getText());
|
Pattern pattern = Pattern.compile(this.nameTextField.getText(), Pattern.CASE_INSENSITIVE);
|
||||||
if (this.fullNameRadioButton.isSelected()) {
|
if (this.fullNameRadioButton.isSelected()) {
|
||||||
condition = new FilesSet.Rule.FullNameCondition(pattern);
|
condition = new FilesSet.Rule.FullNameCondition(pattern);
|
||||||
} else {
|
} else {
|
||||||
@ -556,7 +556,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
|
|||||||
if (!this.pathTextField.getText().isEmpty()) {
|
if (!this.pathTextField.getText().isEmpty()) {
|
||||||
if (this.pathRegexCheckBox.isSelected()) {
|
if (this.pathRegexCheckBox.isSelected()) {
|
||||||
try {
|
try {
|
||||||
condition = new FilesSet.Rule.ParentPathCondition(Pattern.compile(this.pathTextField.getText()));
|
condition = new FilesSet.Rule.ParentPathCondition(Pattern.compile(this.pathTextField.getText(), Pattern.CASE_INSENSITIVE));
|
||||||
} catch (PatternSyntaxException ex) {
|
} catch (PatternSyntaxException ex) {
|
||||||
logger.log(Level.SEVERE, "Attempt to get malformed path condition", ex); // NON-NLS
|
logger.log(Level.SEVERE, "Attempt to get malformed path condition", ex); // NON-NLS
|
||||||
throw new IllegalStateException("The files set rule panel path condition is not in a valid state"); // NON-NLS
|
throw new IllegalStateException("The files set rule panel path condition is not in a valid state"); // NON-NLS
|
||||||
|
@ -271,6 +271,9 @@ class ReportHTML implements TableReportModule {
|
|||||||
case TSK_ACCOUNT:
|
case TSK_ACCOUNT:
|
||||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS
|
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/accounts.png"); //NON-NLS
|
||||||
break;
|
break;
|
||||||
|
case TSK_WIFI_NETWORK:
|
||||||
|
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/network-wifi.png"); //NON-NLS
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = {0}", dataType); //NON-NLS
|
logger.log(Level.WARNING, "useDataTypeIcon: unhandled artifact type = {0}", dataType); //NON-NLS
|
||||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS
|
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/star.png"); //NON-NLS
|
||||||
|
@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
|||||||
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||||
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.DataSource;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A runnable that adds an archive data source as well as data sources contained
|
* A runnable that adds an archive data source as well as data sources contained
|
||||||
@ -195,10 +196,19 @@ class AddArchiveTask implements Runnable {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are here it means the data source was addedd successfully
|
// if we are here it means the data source was added successfully
|
||||||
success = true;
|
success = true;
|
||||||
newDataSources.addAll(internalDataSource.getContent());
|
newDataSources.addAll(internalDataSource.getContent());
|
||||||
|
|
||||||
|
// Update the names for all new data sources to be the root archive plus the name of the data source
|
||||||
|
for (Content c:internalDataSource.getContent()) {
|
||||||
|
if (c instanceof DataSource) {
|
||||||
|
DataSource ds = (DataSource) c;
|
||||||
|
String newName = Paths.get(archivePath).getFileName() + "/" + ds.getName();
|
||||||
|
ds.setDisplayName(newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// skip all other DSPs for this data source
|
// skip all other DSPs for this data source
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
|||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEventException;
|
import org.sleuthkit.autopsy.events.AutopsyEventException;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
|
||||||
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingStatus;
|
import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestJob.ProcessingStatus;
|
||||||
@ -666,43 +667,73 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
|
|||||||
* @return A result code indicating success, partial success, or failure.
|
* @return A result code indicating success, partial success, or failure.
|
||||||
*/
|
*/
|
||||||
CaseDeletionResult deleteCase(AutoIngestJob job) {
|
CaseDeletionResult deleteCase(AutoIngestJob job) {
|
||||||
synchronized (jobsLock) {
|
|
||||||
String caseName = job.getManifest().getCaseName();
|
String caseName = job.getManifest().getCaseName();
|
||||||
Path metadataFilePath = job.getCaseDirectoryPath().resolve(caseName + CaseMetadata.getFileExtension());
|
Path caseDirectoryPath = job.getCaseDirectoryPath();
|
||||||
|
Path metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension());
|
||||||
|
StopWatch stopWatch = new StopWatch();
|
||||||
|
stopWatch.start();
|
||||||
|
synchronized (jobsLock) {
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to acquire jobsLock (Java monitor in AutoIngestMonitor class) for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
|
||||||
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
try {
|
try {
|
||||||
CaseMetadata metadata = new CaseMetadata(metadataFilePath);
|
CaseMetadata metadata = new CaseMetadata(metadataFilePath);
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to read case metadata for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
|
||||||
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
Case.deleteCase(metadata);
|
Case.deleteCase(metadata);
|
||||||
|
|
||||||
} catch (CaseMetadata.CaseMetadataException ex) {
|
} catch (CaseMetadata.CaseMetadataException ex) {
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to get case metadata file %s for case %s at %s", metadataFilePath.toString(), caseName, job.getCaseDirectoryPath().toString()), ex);
|
LOGGER.log(Level.SEVERE, String.format("Failed to read case metadata file %s for case %s at %s", metadataFilePath, caseName, caseDirectoryPath), ex);
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to fail to read case metadata file %s for case %s at %s", stopWatch.getElapsedTimeSecs(), metadataFilePath, caseName, caseDirectoryPath));
|
||||||
return CaseDeletionResult.FAILED;
|
return CaseDeletionResult.FAILED;
|
||||||
} catch (CaseActionException ex) {
|
} catch (CaseActionException ex) {
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to physically delete case %s at %s", caseName, job.getCaseDirectoryPath().toString()), ex);
|
LOGGER.log(Level.SEVERE, String.format("Failed to delete case %s at %s", caseName, caseDirectoryPath), ex);
|
||||||
return CaseDeletionResult.FAILED;
|
return CaseDeletionResult.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the state of completed jobs associated with this case to indicate
|
// Update the state of completed jobs associated with this case to indicate
|
||||||
// that the case has been deleted
|
// that the case has been deleted
|
||||||
for (AutoIngestJob completedJob : getCompletedJobs()) {
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
|
List<AutoIngestJob> completedJobs = getCompletedJobs();
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to get completed jobs listing for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
|
||||||
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
|
for (AutoIngestJob completedJob : completedJobs) {
|
||||||
if (caseName.equals(completedJob.getManifest().getCaseName())) {
|
if (caseName.equals(completedJob.getManifest().getCaseName())) {
|
||||||
try {
|
try {
|
||||||
completedJob.setProcessingStatus(DELETED);
|
completedJob.setProcessingStatus(DELETED);
|
||||||
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(completedJob);
|
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(completedJob);
|
||||||
coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, completedJob.getManifest().getFilePath().toString(), nodeData.toArray());
|
coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, completedJob.getManifest().getFilePath().toString(), nodeData.toArray());
|
||||||
} catch (CoordinationServiceException | InterruptedException ex) {
|
} catch (CoordinationServiceException | InterruptedException ex) {
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to update completed job node data for %s when deleting case %s", completedJob.getManifest().getFilePath().toString(), caseName), ex);
|
LOGGER.log(Level.SEVERE, String.format("Failed to update completed job node data for %s when deleting case %s at %s", completedJob.getManifest().getFilePath(), caseName, caseDirectoryPath), ex);
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to fail to update job node data for completed jobs for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
|
||||||
return CaseDeletionResult.PARTIALLY_DELETED;
|
return CaseDeletionResult.PARTIALLY_DELETED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to update job node data for completed jobs for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
|
||||||
|
|
||||||
// Remove jobs associated with this case from the completed jobs collection.
|
// Remove jobs associated with this case from the completed jobs collection.
|
||||||
jobsSnapshot.completedJobs.removeIf((AutoIngestJob completedJob)
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
|
completedJobs.removeIf((AutoIngestJob completedJob)
|
||||||
-> completedJob.getManifest().getCaseName().equals(caseName));
|
-> completedJob.getManifest().getCaseName().equals(caseName));
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to remove completed jobs for case %s at %s from current jobs snapshot", stopWatch.getElapsedTimeSecs(), caseName, caseDirectoryPath));
|
||||||
|
|
||||||
// Publish a message to update auto ingest nodes.
|
// Publish a message to update auto ingest nodes.
|
||||||
|
stopWatch.reset();
|
||||||
|
stopWatch.start();
|
||||||
eventPublisher.publishRemotely(new AutoIngestCaseDeletedEvent(caseName, LOCAL_HOST_NAME, AutoIngestManager.getSystemUserNameProperty()));
|
eventPublisher.publishRemotely(new AutoIngestCaseDeletedEvent(caseName, LOCAL_HOST_NAME, AutoIngestManager.getSystemUserNameProperty()));
|
||||||
|
stopWatch.stop();
|
||||||
|
LOGGER.log(Level.INFO, String.format("Used %d s to publish job deletion event for case %s at %s", stopWatch.getElapsedTimeSecs(), caseName,caseDirectoryPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
return CaseDeletionResult.FULLY_DELETED;
|
return CaseDeletionResult.FULLY_DELETED;
|
||||||
|
@ -254,6 +254,7 @@ public final class ImageGalleryController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Should the "forward" button on the history be enabled?
|
* Should the "forward" button on the history be enabled?
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ReadOnlyBooleanProperty getCanAdvance() {
|
public ReadOnlyBooleanProperty getCanAdvance() {
|
||||||
@ -262,6 +263,7 @@ public final class ImageGalleryController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Should the "Back" button on the history be enabled?
|
* Should the "Back" button on the history be enabled?
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ReadOnlyBooleanProperty getCanRetreat() {
|
public ReadOnlyBooleanProperty getCanRetreat() {
|
||||||
@ -269,10 +271,9 @@ public final class ImageGalleryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the passed in group. Causes this group to
|
* Display the passed in group. Causes this group to get recorded in the
|
||||||
* get recorded in the history queue and observers of the
|
* history queue and observers of the current state will be notified and
|
||||||
* current state will be notified and update their panels/widgets
|
* update their panels/widgets appropriately.
|
||||||
* appropriately.
|
|
||||||
*
|
*
|
||||||
* @param newState
|
* @param newState
|
||||||
*/
|
*/
|
||||||
@ -283,6 +284,7 @@ public final class ImageGalleryController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the next group in the "forward" history stack
|
* Display the next group in the "forward" history stack
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public GroupViewState advance() {
|
public GroupViewState advance() {
|
||||||
@ -291,6 +293,7 @@ public final class ImageGalleryController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the previous group in the "back" history stack
|
* Display the previous group in the "back" history stack
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public GroupViewState retreat() {
|
public GroupViewState retreat() {
|
||||||
@ -500,10 +503,6 @@ public final class ImageGalleryController {
|
|||||||
return drawableDB.getFileFromID(fileID);
|
return drawableDB.getFileFromID(fileID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyDoubleProperty regroupProgress() {
|
|
||||||
return groupManager.regroupProgress();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashSetManager getHashSetManager() {
|
public HashSetManager getHashSetManager() {
|
||||||
return hashSetManager;
|
return hashSetManager;
|
||||||
}
|
}
|
||||||
@ -764,8 +763,9 @@ public final class ImageGalleryController {
|
|||||||
//do in transaction
|
//do in transaction
|
||||||
drawableDbTransaction = taskDB.beginTransaction();
|
drawableDbTransaction = taskDB.beginTransaction();
|
||||||
|
|
||||||
/* We are going to periodically commit the CaseDB transaction and sleep so
|
/* We are going to periodically commit the CaseDB transaction
|
||||||
* that the user can have Autopsy do other stuff while these bulk tasks are ongoing.
|
* and sleep so that the user can have Autopsy do other stuff
|
||||||
|
* while these bulk tasks are ongoing.
|
||||||
*/
|
*/
|
||||||
int caseDbCounter = 0;
|
int caseDbCounter = 0;
|
||||||
for (final AbstractFile f : files) {
|
for (final AbstractFile f : files) {
|
||||||
|
@ -211,7 +211,7 @@ public class ImageGalleryModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName()) == DATA_ADDED) {
|
else if (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName()) == DATA_ADDED) {
|
||||||
ModuleDataEvent mde = (ModuleDataEvent)evt.getOldValue();
|
ModuleDataEvent mde = (ModuleDataEvent) evt.getOldValue();
|
||||||
|
|
||||||
if (mde.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
|
if (mde.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
|
||||||
DrawableDB drawableDB = controller.getDatabase();
|
DrawableDB drawableDB = controller.getDatabase();
|
||||||
|
@ -68,13 +68,6 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
|
|||||||
DrawableGroup(GroupKey<?> groupKey, Set<Long> filesInGroup, boolean seen) {
|
DrawableGroup(GroupKey<?> groupKey, Set<Long> filesInGroup, boolean seen) {
|
||||||
this.groupKey = groupKey;
|
this.groupKey = groupKey;
|
||||||
this.fileIDs.setAll(filesInGroup);
|
this.fileIDs.setAll(filesInGroup);
|
||||||
fileIDs.addListener((ListChangeListener.Change<? extends Long> listchange) -> {
|
|
||||||
boolean seenChanged = false;
|
|
||||||
while (false == seenChanged && listchange.next()) {
|
|
||||||
seenChanged |= listchange.wasAdded();
|
|
||||||
}
|
|
||||||
invalidateProperties(seenChanged);
|
|
||||||
});
|
|
||||||
this.seen.set(seen);
|
this.seen.set(seen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,15 +176,21 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
|
|||||||
if (fileIDs.contains(f) == false) {
|
if (fileIDs.contains(f) == false) {
|
||||||
fileIDs.add(f);
|
fileIDs.add(f);
|
||||||
}
|
}
|
||||||
|
// invalidate no matter what because the file could have new hash hits, etc.
|
||||||
|
invalidateProperties(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setFiles(Set<? extends Long> newFileIds) {
|
synchronized void setFiles(Set<? extends Long> newFileIds) {
|
||||||
fileIDs.removeIf(fileID -> newFileIds.contains(fileID) == false);
|
fileIDs.removeIf(fileID -> newFileIds.contains(fileID) == false);
|
||||||
|
invalidateProperties(false);
|
||||||
newFileIds.stream().forEach(this::addFile);
|
newFileIds.stream().forEach(this::addFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void removeFile(Long f) {
|
synchronized void removeFile(Long f) {
|
||||||
|
if (fileIDs.contains(f)) {
|
||||||
fileIDs.removeAll(f);
|
fileIDs.removeAll(f);
|
||||||
|
invalidateProperties(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invalidateProperties(boolean seenChanged) {
|
private void invalidateProperties(boolean seenChanged) {
|
||||||
|
@ -50,6 +50,7 @@ import javafx.beans.property.ReadOnlyBooleanWrapper;
|
|||||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||||
|
import javafx.beans.property.ReadOnlyStringProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.concurrent.Service;
|
import javafx.concurrent.Service;
|
||||||
@ -278,8 +279,8 @@ public class GroupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update unseenGroups list accordingly based on the current status
|
* Update unseenGroups list accordingly based on the current status of
|
||||||
* of 'group'. Removes it if it is seen or adds it if it is unseen.
|
* 'group'. Removes it if it is seen or adds it if it is unseen.
|
||||||
*
|
*
|
||||||
* @param group
|
* @param group
|
||||||
*/
|
*/
|
||||||
@ -505,6 +506,10 @@ public class GroupManager {
|
|||||||
return regrouper.progressProperty();
|
return regrouper.progressProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReadOnlyStringProperty regroupMessage() {
|
||||||
|
return regrouper.messageProperty();
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
synchronized public void handleTagAdded(ContentTagAddedEvent evt) {
|
synchronized public void handleTagAdded(ContentTagAddedEvent evt) {
|
||||||
GroupKey<?> newGroupKey = null;
|
GroupKey<?> newGroupKey = null;
|
||||||
@ -730,12 +735,7 @@ public class GroupManager {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
@NbBundle.Messages({"# {0} - groupBy attribute Name",
|
@NbBundle.Messages({"# {0} - groupBy attribute Name",
|
||||||
"# {1} - sortBy name",
|
"ReGroupTask.displayTitle=regrouping by {0}: " })
|
||||||
"# {2} - sort Order",
|
|
||||||
"ReGroupTask.displayTitle=regrouping files by {0} sorted by {1} in {2} order",
|
|
||||||
"# {0} - groupBy attribute Name",
|
|
||||||
"# {1} - atribute value",
|
|
||||||
"ReGroupTask.progressUpdate=regrouping files by {0} : {1}"})
|
|
||||||
class ReGroupTask<AttrValType extends Comparable<AttrValType>> extends LoggedTask<Void> {
|
class ReGroupTask<AttrValType extends Comparable<AttrValType>> extends LoggedTask<Void> {
|
||||||
|
|
||||||
private final DataSource dataSource;
|
private final DataSource dataSource;
|
||||||
@ -743,16 +743,14 @@ public class GroupManager {
|
|||||||
private final GroupSortBy sortBy;
|
private final GroupSortBy sortBy;
|
||||||
private final SortOrder sortOrder;
|
private final SortOrder sortOrder;
|
||||||
|
|
||||||
private final ProgressHandle groupProgress;
|
|
||||||
|
|
||||||
ReGroupTask(DataSource dataSource, DrawableAttribute<AttrValType> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
|
ReGroupTask(DataSource dataSource, DrawableAttribute<AttrValType> groupBy, GroupSortBy sortBy, SortOrder sortOrder) {
|
||||||
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true);
|
super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString() ), true);
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.groupBy = groupBy;
|
this.groupBy = groupBy;
|
||||||
this.sortBy = sortBy;
|
this.sortBy = sortBy;
|
||||||
this.sortOrder = sortOrder;
|
this.sortOrder = sortOrder;
|
||||||
|
|
||||||
groupProgress = ProgressHandle.createHandle(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), this);
|
updateTitle(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString() ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -761,7 +759,8 @@ public class GroupManager {
|
|||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
groupProgress.start();
|
|
||||||
|
updateProgress(-1, 1);
|
||||||
|
|
||||||
analyzedGroups.clear();
|
analyzedGroups.clear();
|
||||||
unSeenGroups.clear();
|
unSeenGroups.clear();
|
||||||
@ -769,7 +768,7 @@ public class GroupManager {
|
|||||||
// Get the list of group keys
|
// Get the list of group keys
|
||||||
Multimap<DataSource, AttrValType> valsByDataSource = findValuesForAttribute();
|
Multimap<DataSource, AttrValType> valsByDataSource = findValuesForAttribute();
|
||||||
|
|
||||||
groupProgress.switchToDeterminate(valsByDataSource.entries().size());
|
updateProgress(0, valsByDataSource.entries().size());
|
||||||
int p = 0;
|
int p = 0;
|
||||||
// For each key value, partially create the group and add it to the list.
|
// For each key value, partially create the group and add it to the list.
|
||||||
for (final Map.Entry<DataSource, AttrValType> valForDataSource : valsByDataSource.entries()) {
|
for (final Map.Entry<DataSource, AttrValType> valForDataSource : valsByDataSource.entries()) {
|
||||||
@ -777,9 +776,8 @@ public class GroupManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
p++;
|
p++;
|
||||||
updateMessage(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), valForDataSource.getValue()));
|
updateMessage(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString()) + valForDataSource.getValue());
|
||||||
updateProgress(p, valsByDataSource.size());
|
updateProgress(p, valsByDataSource.size());
|
||||||
groupProgress.progress(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), valForDataSource), p);
|
|
||||||
popuplateIfAnalyzed(new GroupKey<>(groupBy, valForDataSource.getValue(), valForDataSource.getKey()), this);
|
popuplateIfAnalyzed(new GroupKey<>(groupBy, valForDataSource.getValue(), valForDataSource.getKey()), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,8 +806,8 @@ public class GroupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
groupProgress.finish();
|
|
||||||
updateProgress(1, 1);
|
updateProgress(1, 1);
|
||||||
|
updateMessage("");
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -827,12 +825,9 @@ public class GroupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find the distinct values for the given column (DrawableAttribute)
|
* Find the distinct values for the given column (DrawableAttribute).
|
||||||
*
|
|
||||||
* These values represent the groups of files.
|
* These values represent the groups of files.
|
||||||
*
|
*
|
||||||
* @param groupBy
|
|
||||||
*
|
|
||||||
* @return map of data source (or null if group by attribute ignores
|
* @return map of data source (or null if group by attribute ignores
|
||||||
* data sources) to list of unique group values
|
* data sources) to list of unique group values
|
||||||
*/
|
*/
|
||||||
|
@ -10,12 +10,21 @@
|
|||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
<?import javafx.scene.layout.StackPane?>
|
<?import javafx.scene.layout.StackPane?>
|
||||||
|
|
||||||
<fx:root id="AnchorPane" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1">
|
<fx:root id="AnchorPane" maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" type="javafx.scene.layout.AnchorPane" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1">
|
||||||
<children>
|
<children>
|
||||||
<BorderPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
<BorderPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||||
<right>
|
<right>
|
||||||
<HBox alignment="CENTER_RIGHT" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" BorderPane.alignment="CENTER_RIGHT">
|
<HBox alignment="CENTER_RIGHT" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" BorderPane.alignment="CENTER_RIGHT">
|
||||||
<children>
|
<children>
|
||||||
|
<Label fx:id="staleLabel" text="Some data may be out of date. Enable listening to ingest to update.">
|
||||||
|
<graphic>
|
||||||
|
<ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
|
||||||
|
<image>
|
||||||
|
<Image url="@../images/information.png" />
|
||||||
|
</image>
|
||||||
|
</ImageView>
|
||||||
|
</graphic>
|
||||||
|
</Label>
|
||||||
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" HBox.hgrow="NEVER">
|
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" HBox.hgrow="NEVER">
|
||||||
<children>
|
<children>
|
||||||
<ProgressBar id="progBar" fx:id="fileTaskProgresBar" focusTraversable="false" maxHeight="-1.0" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-1.0" prefHeight="24.0" prefWidth="-1.0" progress="0.0" visible="true" />
|
<ProgressBar id="progBar" fx:id="fileTaskProgresBar" focusTraversable="false" maxHeight="-1.0" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-1.0" prefHeight="24.0" prefWidth="-1.0" progress="0.0" visible="true" />
|
||||||
@ -31,37 +40,27 @@
|
|||||||
<Insets />
|
<Insets />
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
</StackPane>
|
</StackPane>
|
||||||
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" HBox.hgrow="NEVER">
|
|
||||||
<children>
|
|
||||||
<ProgressBar fx:id="bgTaskProgressBar" maxHeight="-1.0" maxWidth="-1.0" minHeight="-Infinity" minWidth="-1.0" prefHeight="24.0" prefWidth="-1.0" progress="0.0" StackPane.alignment="CENTER" />
|
|
||||||
<Label fx:id="bgTaskLabel" alignment="CENTER" cache="false" contentDisplay="CENTER" disable="false" focusTraversable="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" text="" StackPane.alignment="CENTER">
|
|
||||||
<StackPane.margin>
|
|
||||||
<Insets left="3.0" right="3.0" />
|
|
||||||
</StackPane.margin>
|
|
||||||
<padding>
|
|
||||||
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
|
|
||||||
</padding></Label>
|
|
||||||
</children>
|
|
||||||
<HBox.margin>
|
|
||||||
<Insets right="5.0" />
|
|
||||||
</HBox.margin>
|
|
||||||
</StackPane>
|
|
||||||
</children>
|
</children>
|
||||||
<BorderPane.margin>
|
<BorderPane.margin>
|
||||||
<Insets left="10.0" />
|
<Insets left="10.0" />
|
||||||
</BorderPane.margin>
|
</BorderPane.margin>
|
||||||
</HBox>
|
</HBox>
|
||||||
</right>
|
</right>
|
||||||
<left><Label fx:id="staleLabel" text="Some data may be out of date. Enable listening to ingest to update." BorderPane.alignment="CENTER">
|
<left>
|
||||||
<graphic><ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
|
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" BorderPane.alignment="CENTER">
|
||||||
<image>
|
<children>
|
||||||
<Image url="@../images/information.png" />
|
<ProgressBar fx:id="regroupProgressBar" maxHeight="-1.0" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-1.0" prefHeight="24.0" prefWidth="500.0" progress="0.0" StackPane.alignment="CENTER_LEFT" />
|
||||||
</image></ImageView>
|
<Label fx:id="regroupLabel" cache="false" contentDisplay="CENTER" disable="false" focusTraversable="false" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="500.0" text="" textOverrun="CENTER_ELLIPSIS" StackPane.alignment="CENTER_LEFT">
|
||||||
</graphic>
|
<StackPane.margin>
|
||||||
<BorderPane.margin>
|
<Insets left="3.0" right="3.0" />
|
||||||
<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
|
</StackPane.margin>
|
||||||
</BorderPane.margin></Label>
|
<padding>
|
||||||
</left>
|
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
|
||||||
|
</padding>
|
||||||
|
</Label>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
|
</left>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
</children>
|
</children>
|
||||||
</fx:root>
|
</fx:root>
|
||||||
|
@ -28,28 +28,26 @@ import javafx.scene.control.Tooltip;
|
|||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
|
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
|
||||||
|
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class StatusBar extends AnchorPane {
|
public class StatusBar extends AnchorPane {
|
||||||
|
|
||||||
private final ImageGalleryController controller;
|
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ProgressBar fileTaskProgresBar;
|
private ProgressBar fileTaskProgresBar;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label fileUpdateTaskLabel;
|
private Label fileUpdateTaskLabel;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label bgTaskLabel;
|
private Label regroupLabel;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private Label staleLabel;
|
private Label staleLabel;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private ProgressBar bgTaskProgressBar;
|
private ProgressBar regroupProgressBar;
|
||||||
|
|
||||||
|
private final ImageGalleryController controller;
|
||||||
|
private final GroupManager groupManager;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@NbBundle.Messages({"StatusBar.fileUpdateTaskLabel.text= File Update Tasks",
|
@NbBundle.Messages({"StatusBar.fileUpdateTaskLabel.text= File Update Tasks",
|
||||||
@ -58,23 +56,25 @@ public class StatusBar extends AnchorPane {
|
|||||||
void initialize() {
|
void initialize() {
|
||||||
assert fileTaskProgresBar != null : "fx:id=\"fileTaskProgresBar\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
assert fileTaskProgresBar != null : "fx:id=\"fileTaskProgresBar\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
||||||
assert fileUpdateTaskLabel != null : "fx:id=\"fileUpdateTaskLabel\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
assert fileUpdateTaskLabel != null : "fx:id=\"fileUpdateTaskLabel\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
||||||
assert bgTaskLabel != null : "fx:id=\"bgTaskLabel\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
assert regroupLabel != null : "fx:id=\"regroupLabel\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
||||||
assert bgTaskProgressBar != null : "fx:id=\"bgTaskProgressBar\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
assert regroupProgressBar != null : "fx:id=\"regroupProgressBar\" was not injected: check your FXML file 'StatusBar.fxml'.";
|
||||||
|
|
||||||
fileUpdateTaskLabel.textProperty().bind(controller.getDBTasksQueueSizeProperty().asString().concat(Bundle.StatusBar_fileUpdateTaskLabel_text()));
|
fileUpdateTaskLabel.textProperty().bind(controller.getDBTasksQueueSizeProperty().asString().concat(Bundle.StatusBar_fileUpdateTaskLabel_text()));
|
||||||
fileTaskProgresBar.progressProperty().bind(controller.getDBTasksQueueSizeProperty().negate());
|
fileTaskProgresBar.progressProperty().bind(controller.getDBTasksQueueSizeProperty().negate());
|
||||||
|
|
||||||
controller.regroupProgress().addListener((ov, oldSize, newSize) -> {
|
groupManager.regroupProgress().addListener((ov, oldSize, newSize) -> {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (controller.regroupProgress().lessThan(1.0).get()) {
|
if (groupManager.regroupProgress().lessThan(1.0).get()) {
|
||||||
// Regrouping in progress
|
// Regrouping in progress
|
||||||
bgTaskProgressBar.progressProperty().setValue(-1.0);
|
regroupProgressBar.progressProperty().setValue(groupManager.regroupProgress().doubleValue());
|
||||||
bgTaskLabel.setText(Bundle.StatusBar_bgTaskLabel_text());
|
regroupLabel.setText(groupManager.regroupMessage().get());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Clear the progress bar
|
// Clear the progress bar
|
||||||
bgTaskProgressBar.progressProperty().setValue(0.0);
|
regroupProgressBar.progressProperty().setValue(0.0);
|
||||||
bgTaskLabel.setText("");
|
regroupLabel.setText("");
|
||||||
}
|
}
|
||||||
|
regroupLabel.setTooltip(new Tooltip(regroupLabel.getText()));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -84,6 +84,7 @@ public class StatusBar extends AnchorPane {
|
|||||||
|
|
||||||
public StatusBar(ImageGalleryController controller) {
|
public StatusBar(ImageGalleryController controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
this.groupManager = controller.getGroupManager();
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("StatusBar.fxml")); //NON-NLS
|
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("StatusBar.fxml")); //NON-NLS
|
||||||
fxmlLoader.setRoot(this);
|
fxmlLoader.setRoot(this);
|
||||||
fxmlLoader.setController(this);
|
fxmlLoader.setController(this);
|
||||||
@ -93,6 +94,5 @@ public class StatusBar extends AnchorPane {
|
|||||||
} catch (IOException exception) {
|
} catch (IOException exception) {
|
||||||
throw new RuntimeException(exception);
|
throw new RuntimeException(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
NEWS.txt
8
NEWS.txt
@ -1,8 +1,8 @@
|
|||||||
---------------- VERSION 4.9.0 --------------
|
---------------- VERSION 4.9.1 --------------
|
||||||
Bug Fixes:
|
Bug Fixes:
|
||||||
- Fixed possible ingest deadlock from Image Gallery database inserts
|
- Fixed possible ingest deadlock from Image Gallery database inserts.
|
||||||
- Image Gallery does not need lock on Case DB during pre-population, which makes UI more responsive
|
- Image Gallery does not need lock on Case DB during pre-population, which makes UI more responsive.
|
||||||
- Other misc Image Gallery fixes
|
- Other misc Image Gallery fixes.
|
||||||
|
|
||||||
---------------- VERSION 4.9.0 --------------
|
---------------- VERSION 4.9.0 --------------
|
||||||
|
|
||||||
|
@ -64,9 +64,7 @@
|
|||||||
</run-dependency>
|
</run-dependency>
|
||||||
</dependency>
|
</dependency>
|
||||||
</module-dependencies>
|
</module-dependencies>
|
||||||
<public-packages>
|
<public-packages/>
|
||||||
<package>org.sleuthkit.autopsy.recentactivity</package>
|
|
||||||
</public-packages>
|
|
||||||
<class-path-extension>
|
<class-path-extension>
|
||||||
<runtime-relative-path>ext/gson-2.1.jar</runtime-relative-path>
|
<runtime-relative-path>ext/gson-2.1.jar</runtime-relative-path>
|
||||||
<binary-origin>release/modules/ext/gson-2.1.jar</binary-origin>
|
<binary-origin>release/modules/ext/gson-2.1.jar</binary-origin>
|
||||||
|
@ -39,6 +39,7 @@ import java.io.FileReader;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -163,7 +164,7 @@ class Chrome extends Extract {
|
|||||||
NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
|
NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||||
(Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
|
(NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
|
||||||
|
|
||||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
|
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY, historyFile, bbattributes);
|
||||||
if (bbart != null) {
|
if (bbart != null) {
|
||||||
@ -286,7 +287,7 @@ class Chrome extends Extract {
|
|||||||
} else {
|
} else {
|
||||||
date = Long.valueOf(0);
|
date = Long.valueOf(0);
|
||||||
}
|
}
|
||||||
String domain = Util.extractDomain(url);
|
String domain = NetworkUtils.extractDomain(url);
|
||||||
try {
|
try {
|
||||||
BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
|
BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
|
||||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||||
@ -496,7 +497,7 @@ class Chrome extends Extract {
|
|||||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
|
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", time));
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), time));
|
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), time));
|
||||||
String domain = Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
|
String domain = NetworkUtils.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""); //NON-NLS
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), domain));
|
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), domain));
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
|
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME,
|
||||||
@ -590,7 +591,7 @@ class Chrome extends Extract {
|
|||||||
NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
|
NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
|
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
|
||||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||||
(Util.extractDomain((result.get("origin_url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
|
(NetworkUtils.extractDomain((result.get("origin_url").toString() != null) ? result.get("url").toString() : "")))); //NON-NLS
|
||||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
|
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
|
||||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||||
((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
|
((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
|
||||||
|
@ -26,6 +26,7 @@ import java.io.BufferedReader;
|
|||||||
|
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.coreutils.ExecUtil;
|
import org.sleuthkit.autopsy.coreutils.ExecUtil;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@ -609,6 +610,6 @@ class ExtractIE extends Extract {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Util.extractDomain(url);
|
return NetworkUtils.extractDomain(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -374,7 +374,9 @@ class ExtractRegistry extends Extract {
|
|||||||
// Add all "usb" dataType nodes to collection of BlackboardArtifacts
|
// Add all "usb" dataType nodes to collection of BlackboardArtifacts
|
||||||
// that we will submit in a ModuleDataEvent for additional processing.
|
// that we will submit in a ModuleDataEvent for additional processing.
|
||||||
Collection<BlackboardArtifact> usbBBartifacts = new ArrayList<>();
|
Collection<BlackboardArtifact> usbBBartifacts = new ArrayList<>();
|
||||||
|
// Add all "ssid" dataType nodes to collection of BlackboardArtifacts
|
||||||
|
// that we will submit in a ModuleDataEvent for additional processing.
|
||||||
|
Collection<BlackboardArtifact> wifiBBartifacts = new ArrayList<>();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
Element tempnode = (Element) children.item(i);
|
Element tempnode = (Element) children.item(i);
|
||||||
|
|
||||||
@ -734,6 +736,7 @@ class ExtractRegistry extends Extract {
|
|||||||
bbart.addAttributes(bbattributes);
|
bbart.addAttributes(bbattributes);
|
||||||
// index the artifact for keyword search
|
// index the artifact for keyword search
|
||||||
this.indexArtifact(bbart);
|
this.indexArtifact(bbart);
|
||||||
|
wifiBBartifacts.add(bbart);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Error adding SSID artifact to blackboard."); //NON-NLS
|
logger.log(Level.SEVERE, "Error adding SSID artifact to blackboard."); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -756,6 +759,9 @@ class ExtractRegistry extends Extract {
|
|||||||
if (!usbBBartifacts.isEmpty()) {
|
if (!usbBBartifacts.isEmpty()) {
|
||||||
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(moduleName, BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED, usbBBartifacts));
|
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(moduleName, BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED, usbBBartifacts));
|
||||||
}
|
}
|
||||||
|
if (!wifiBBartifacts.isEmpty()){
|
||||||
|
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(moduleName, BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK, wifiBBartifacts));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
logger.log(Level.SEVERE, "Error finding the registry file."); //NON-NLS
|
logger.log(Level.SEVERE, "Error finding the registry file."); //NON-NLS
|
||||||
|
@ -35,6 +35,7 @@ import java.util.logging.Level;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||||
@ -669,6 +670,6 @@ class Firefox extends Extract {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Util.extractDomain(url);
|
return NetworkUtils.extractDomain(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,83 +84,6 @@ class Util {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* @return empty string if no domain could be found
|
|
||||||
*/
|
|
||||||
private static String getBaseDomain(String url) {
|
|
||||||
String host = null;
|
|
||||||
|
|
||||||
//strip protocol
|
|
||||||
String cleanUrl = url.replaceFirst(".*:\\/\\/", "");
|
|
||||||
|
|
||||||
//strip after slashes
|
|
||||||
String dirToks[] = cleanUrl.split("\\/");
|
|
||||||
if (dirToks.length > 0) {
|
|
||||||
host = dirToks[0];
|
|
||||||
} else {
|
|
||||||
host = cleanUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the domain part from host (last 2)
|
|
||||||
StringTokenizer tok = new StringTokenizer(host, ".");
|
|
||||||
StringBuilder hostB = new StringBuilder();
|
|
||||||
int toks = tok.countTokens();
|
|
||||||
|
|
||||||
for (int count = 0; count < toks; ++count) {
|
|
||||||
String part = tok.nextToken();
|
|
||||||
int diff = toks - count;
|
|
||||||
if (diff < 3) {
|
|
||||||
hostB.append(part);
|
|
||||||
}
|
|
||||||
if (diff == 2) {
|
|
||||||
hostB.append(".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
String base = hostB.toString();
|
|
||||||
// verify there are no special characters in there
|
|
||||||
if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* @return empty string if no domain name was found
|
|
||||||
*/
|
|
||||||
public static String extractDomain(String value) {
|
|
||||||
if (value == null) {
|
|
||||||
return "";
|
|
||||||
|
|
||||||
}
|
|
||||||
String result = "";
|
|
||||||
// String domainPattern = "(\\w+)\\.(AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CW|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SX|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XXX|YE|YT|ZA|ZM|ZW(co\\.[a-z].))";
|
|
||||||
// Pattern p = Pattern.compile(domainPattern,Pattern.CASE_INSENSITIVE);
|
|
||||||
// Matcher m = p.matcher(value);
|
|
||||||
// while (m.find()) {
|
|
||||||
// result = value.substring(m.start(0),m.end(0));
|
|
||||||
// }
|
|
||||||
|
|
||||||
try {
|
|
||||||
URL url = new URL(value);
|
|
||||||
result = url.getHost();
|
|
||||||
} catch (MalformedURLException ex) {
|
|
||||||
//do not log if not a valid URL, and handle later
|
|
||||||
//Logger.getLogger(Util.class.getName()).log(Level.SEVERE, null, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
//was not a valid URL, try a less picky method
|
|
||||||
if (result == null || result.trim().isEmpty()) {
|
|
||||||
return getBaseDomain(value);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getFileName(String value) {
|
public static String getFileName(String value) {
|
||||||
String filename = "";
|
String filename = "";
|
||||||
String filematch = "^([a-zA-Z]\\:)(\\\\[^\\\\/:*?<>\"|]*(?<!\\[ \\]))*(\\.[a-zA-Z]{2,6})$"; //NON-NLS
|
String filematch = "^([a-zA-Z]\\:)(\\\\[^\\\\/:*?<>\"|]*(?<!\\[ \\]))*(\\.[a-zA-Z]{2,6})$"; //NON-NLS
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#Updated by build script
|
#Updated by build script
|
||||||
#Sat, 13 Oct 2018 21:02:18 -0400
|
#Tue, 13 Nov 2018 17:30:09 -0500
|
||||||
LBL_splash_window_title=Starting Autopsy
|
LBL_splash_window_title=Starting Autopsy
|
||||||
SPLASH_HEIGHT=314
|
SPLASH_HEIGHT=314
|
||||||
SPLASH_WIDTH=538
|
SPLASH_WIDTH=538
|
||||||
@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
|
|||||||
SplashRunningTextColor=0x0
|
SplashRunningTextColor=0x0
|
||||||
SplashRunningTextFontSize=19
|
SplashRunningTextFontSize=19
|
||||||
|
|
||||||
currentVersion=Autopsy 4.9.0
|
currentVersion=Autopsy 4.9.1
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#Updated by build script
|
#Updated by build script
|
||||||
#Sat, 13 Oct 2018 21:02:18 -0400
|
#Tue, 13 Nov 2018 17:30:09 -0500
|
||||||
CTL_MainWindow_Title=Autopsy 4.9.0
|
CTL_MainWindow_Title=Autopsy 4.9.1
|
||||||
CTL_MainWindow_Title_No_Project=Autopsy 4.9.0
|
CTL_MainWindow_Title_No_Project=Autopsy 4.9.1
|
||||||
|
@ -1,268 +0,0 @@
|
|||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
# Updates various Autopsy version numbers
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use File::Copy;
|
|
||||||
|
|
||||||
# global variables
|
|
||||||
my $VER;
|
|
||||||
|
|
||||||
|
|
||||||
my $TESTING = 0;
|
|
||||||
print "TESTING MODE (no commits)\n" if ($TESTING);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sub main {
|
|
||||||
|
|
||||||
# Get the Autopsy version argument
|
|
||||||
if (scalar (@ARGV) != 1) {
|
|
||||||
print stderr "Missing release version argument (i.e. 4.9.0)\n";
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$VER = $ARGV[0];
|
|
||||||
die "Invalid version number: $VER (1.2.3 or 1.2.3b1 expected)" unless ($VER =~ /^\d+\.\d+\.\d+(b\d+)?$/);
|
|
||||||
|
|
||||||
|
|
||||||
my $AUT_RELNAME = "autopsy-${VER}";
|
|
||||||
# Verify the tag doesn't already exist
|
|
||||||
exec_pipe(*OUT, "git tag | grep \"${AUT_RELNAME}\$\"");
|
|
||||||
my $foo = read_pipe_line(*OUT);
|
|
||||||
if ($foo ne "") {
|
|
||||||
print "Tag ${AUT_RELNAME} already exists\n";
|
|
||||||
print "Remove with 'git tag -d ${AUT_RELNAME}'\n";
|
|
||||||
die "stopping";
|
|
||||||
}
|
|
||||||
close(OUT);
|
|
||||||
|
|
||||||
# Assume we running out of 'release' folder
|
|
||||||
chdir ".." or die "Error changing directories to root";
|
|
||||||
|
|
||||||
|
|
||||||
# verify_precheckin();
|
|
||||||
|
|
||||||
|
|
||||||
# Update the version info in that tag
|
|
||||||
update_project_properties();
|
|
||||||
update_doxygen_dev();
|
|
||||||
update_doxygen_user();
|
|
||||||
|
|
||||||
print "Files updated. You need to commit and push them\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
######################################################
|
|
||||||
# Utility functions
|
|
||||||
|
|
||||||
|
|
||||||
# Function to execute a command and send output to pipe
|
|
||||||
# returns handle
|
|
||||||
# exec_pipe(HANDLE, CMD);
|
|
||||||
sub exec_pipe {
|
|
||||||
my $handle = shift(@_);
|
|
||||||
my $cmd = shift(@_);
|
|
||||||
|
|
||||||
die "Can't open pipe for exec_pipe"
|
|
||||||
unless defined(my $pid = open($handle, '-|'));
|
|
||||||
|
|
||||||
if ($pid) {
|
|
||||||
return $handle;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$| = 1;
|
|
||||||
exec("$cmd") or die "Can't exec program: $!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Read a line of text from an open exec_pipe handle
|
|
||||||
sub read_pipe_line {
|
|
||||||
my $handle = shift(@_);
|
|
||||||
my $out;
|
|
||||||
|
|
||||||
for (my $i = 0; $i < 100; $i++) {
|
|
||||||
$out = <$handle>;
|
|
||||||
return $out if (defined $out);
|
|
||||||
}
|
|
||||||
return $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Prompt user for argument and return response
|
|
||||||
sub prompt_user {
|
|
||||||
my $q = shift(@_);
|
|
||||||
print "$q: ";
|
|
||||||
$| = 1;
|
|
||||||
$_ = <STDIN>;
|
|
||||||
chomp;
|
|
||||||
return $_;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# File update methods
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Verify that all files in the current source directory
|
|
||||||
# are checked in. dies if any are modified.
|
|
||||||
sub verify_precheckin {
|
|
||||||
|
|
||||||
#system ("git pull");
|
|
||||||
|
|
||||||
print "Verifying everything is checked in\n";
|
|
||||||
exec_pipe(*OUT, "git status -s | grep \"^ M\"");
|
|
||||||
|
|
||||||
my $foo = read_pipe_line(*OUT);
|
|
||||||
if ($foo ne "") {
|
|
||||||
print "Files not checked in\n";
|
|
||||||
while ($foo ne "") {
|
|
||||||
print "$foo";
|
|
||||||
$foo = read_pipe_line(*OUT);
|
|
||||||
}
|
|
||||||
die "stopping" unless ($TESTING);
|
|
||||||
}
|
|
||||||
close(OUT);
|
|
||||||
|
|
||||||
print "Verifying everything is pushed\n";
|
|
||||||
exec_pipe(*OUT, "git status -sb | grep \"^##\" | grep \"ahead \"");
|
|
||||||
my $foo = read_pipe_line(*OUT);
|
|
||||||
if ($foo ne "") {
|
|
||||||
print "$foo";
|
|
||||||
print "Files not pushed to remote\n";
|
|
||||||
die "stopping" unless ($TESTING);
|
|
||||||
}
|
|
||||||
close(OUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# update the version in nbproject/project.properties
|
|
||||||
sub update_project_properties {
|
|
||||||
|
|
||||||
my $orig = "project.properties";
|
|
||||||
my $temp = "${orig}-bak";
|
|
||||||
|
|
||||||
print "Updating the version in ${orig}\n";
|
|
||||||
|
|
||||||
chdir "nbproject" or die "cannot change into nbproject directory";
|
|
||||||
|
|
||||||
|
|
||||||
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
|
|
||||||
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
|
|
||||||
|
|
||||||
my $found = 0;
|
|
||||||
while (<CONF_IN>) {
|
|
||||||
if (/^app\.version=/) {
|
|
||||||
print CONF_OUT "app.version=$VER\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print CONF_OUT $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close (CONF_IN);
|
|
||||||
close (CONF_OUT);
|
|
||||||
|
|
||||||
if ($found != 1) {
|
|
||||||
die "$found (instead of 1) occurrences of app.version found in ${orig}";
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink ($orig) or die "Error deleting ${orig}";
|
|
||||||
rename ($temp, $orig) or die "Error renaming tmp $orig file";
|
|
||||||
system("git add ${orig}") unless ($TESTING);
|
|
||||||
chdir ".." or die "Error changing directories back to root";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# update the dev docs
|
|
||||||
sub update_doxygen_dev {
|
|
||||||
|
|
||||||
my $orig = "Doxyfile";
|
|
||||||
my $temp = "${orig}-bak";
|
|
||||||
|
|
||||||
print "Updating the version in ${orig} (Dev)\n";
|
|
||||||
|
|
||||||
chdir "docs/doxygen" or die "cannot change into docs/doxygen directory";
|
|
||||||
|
|
||||||
|
|
||||||
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
|
|
||||||
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
|
|
||||||
|
|
||||||
my $found = 0;
|
|
||||||
while (<CONF_IN>) {
|
|
||||||
if (/^PROJECT_NUMBER/) {
|
|
||||||
print CONF_OUT "PROJECT_NUMBER = ${VER}\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
elsif (/^HTML_OUTPUT/) {
|
|
||||||
print CONF_OUT "HTML_OUTPUT = api-docs/${VER}/\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print CONF_OUT $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close (CONF_IN);
|
|
||||||
close (CONF_OUT);
|
|
||||||
|
|
||||||
if ($found != 2) {
|
|
||||||
die "$found (instead of 2) occurrences of version found in (DEV) ${orig}";
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink ($orig) or die "Error deleting ${orig}";
|
|
||||||
rename ($temp, $orig) or die "Error renaming tmp $orig file";
|
|
||||||
system("git add ${orig}") unless ($TESTING);
|
|
||||||
chdir "../.." or die "Error changing directories back to root";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# update the user docs
|
|
||||||
sub update_doxygen_user {
|
|
||||||
|
|
||||||
my $orig = "Doxyfile";
|
|
||||||
my $temp = "${orig}-bak";
|
|
||||||
|
|
||||||
print "Updating the version in ${orig} (User)\n";
|
|
||||||
|
|
||||||
chdir "docs/doxygen-user" or die "cannot change into docs/doxygen-user directory";
|
|
||||||
|
|
||||||
|
|
||||||
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
|
|
||||||
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
|
|
||||||
|
|
||||||
my $found = 0;
|
|
||||||
while (<CONF_IN>) {
|
|
||||||
if (/^PROJECT_NUMBER/) {
|
|
||||||
print CONF_OUT "PROJECT_NUMBER = ${VER}\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
elsif (/^HTML_OUTPUT/) {
|
|
||||||
print CONF_OUT "HTML_OUTPUT = ${VER}\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print CONF_OUT $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close (CONF_IN);
|
|
||||||
close (CONF_OUT);
|
|
||||||
|
|
||||||
if ($found != 2) {
|
|
||||||
die "$found (instead of 2) occurrences of version found in (USER) ${orig}";
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink ($orig) or die "Error deleting ${orig}";
|
|
||||||
rename ($temp, $orig) or die "Error renaming tmp $orig file";
|
|
||||||
system("git add ${orig}") unless ($TESTING);
|
|
||||||
chdir "../.." or die "Error changing directories back to root";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
main();
|
|
@ -1,199 +0,0 @@
|
|||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
# Updates various TSK version numbers
|
|
||||||
# use this when the version of TSK that Autopsy depends on changes
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use File::Copy;
|
|
||||||
|
|
||||||
# global variables
|
|
||||||
my $VER;
|
|
||||||
|
|
||||||
my $TESTING = 0;
|
|
||||||
print "TESTING MODE (no commits)\n" if ($TESTING);
|
|
||||||
|
|
||||||
|
|
||||||
sub main {
|
|
||||||
|
|
||||||
# Get the TSK version argument
|
|
||||||
if (scalar (@ARGV) != 1) {
|
|
||||||
print stderr "Missing release version argument (i.e. 4.9.0)\n";
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$VER = $ARGV[0];
|
|
||||||
die "Invalid version number: $VER (1.2.3 or 1.2.3b1 expected)" unless ($VER =~ /^\d+\.\d+\.\d+(b\d+)?$/);
|
|
||||||
|
|
||||||
# Assume we running out of 'release' folder
|
|
||||||
chdir ".." or die "Error changing directories to root";
|
|
||||||
|
|
||||||
# Update the version info in that tag
|
|
||||||
update_tsk_version();
|
|
||||||
update_core_project_properties();
|
|
||||||
update_core_project_xml();
|
|
||||||
|
|
||||||
print "Files updated. You need to commit and push them\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
######################################################
|
|
||||||
# Utility functions
|
|
||||||
|
|
||||||
|
|
||||||
# Function to execute a command and send output to pipe
|
|
||||||
# returns handle
|
|
||||||
# exec_pipe(HANDLE, CMD);
|
|
||||||
sub exec_pipe {
|
|
||||||
my $handle = shift(@_);
|
|
||||||
my $cmd = shift(@_);
|
|
||||||
|
|
||||||
die "Can't open pipe for exec_pipe"
|
|
||||||
unless defined(my $pid = open($handle, '-|'));
|
|
||||||
|
|
||||||
if ($pid) {
|
|
||||||
return $handle;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$| = 1;
|
|
||||||
exec("$cmd") or die "Can't exec program: $!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Read a line of text from an open exec_pipe handle
|
|
||||||
sub read_pipe_line {
|
|
||||||
my $handle = shift(@_);
|
|
||||||
my $out;
|
|
||||||
|
|
||||||
for (my $i = 0; $i < 100; $i++) {
|
|
||||||
$out = <$handle>;
|
|
||||||
return $out if (defined $out);
|
|
||||||
}
|
|
||||||
return $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#############################################
|
|
||||||
# File update methods
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# update the tskversion.xml
|
|
||||||
sub update_tsk_version {
|
|
||||||
|
|
||||||
my $orig = "TSKVersion.xml";
|
|
||||||
my $temp = "${orig}-bak";
|
|
||||||
|
|
||||||
print "Updating the version in ${orig}\n";
|
|
||||||
|
|
||||||
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
|
|
||||||
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
|
|
||||||
|
|
||||||
my $found = 0;
|
|
||||||
while (<CONF_IN>) {
|
|
||||||
if (/name="TSK_VERSION" value=/) {
|
|
||||||
print CONF_OUT " <property name=\"TSK_VERSION\" value=\"${VER}\"/>\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print CONF_OUT $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close (CONF_IN);
|
|
||||||
close (CONF_OUT);
|
|
||||||
|
|
||||||
if ($found != 1) {
|
|
||||||
die "$found (instead of 1) occurrences of app.version found in ${orig}";
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink ($orig) or die "Error deleting ${orig}";
|
|
||||||
rename ($temp, $orig) or die "Error renaming tmp $orig file";
|
|
||||||
system("git add ${orig}") unless ($TESTING);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sub update_core_project_properties {
|
|
||||||
|
|
||||||
my $orig = "project.properties";
|
|
||||||
my $temp = "${orig}-bak";
|
|
||||||
|
|
||||||
print "Updating the version in ${orig}\n";
|
|
||||||
|
|
||||||
chdir "Core/nbproject" or die "cannot change into Core/nbproject directory";
|
|
||||||
|
|
||||||
|
|
||||||
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
|
|
||||||
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
|
|
||||||
|
|
||||||
my $found = 0;
|
|
||||||
while (<CONF_IN>) {
|
|
||||||
if (/^file\.reference\.sleuthkit\-postgresql-/) {
|
|
||||||
print CONF_OUT "file.reference.sleuthkit-postgresql-${VER}.jar=release/modules/ext/sleuthkit-postgresql-${VER}.jar\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
print CONF_OUT $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close (CONF_IN);
|
|
||||||
close (CONF_OUT);
|
|
||||||
|
|
||||||
if ($found != 1) {
|
|
||||||
die "$found (instead of 1) occurrences of version found in ${orig}";
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink ($orig) or die "Error deleting ${orig}";
|
|
||||||
rename ($temp, $orig) or die "Error renaming tmp $orig file";
|
|
||||||
system("git add ${orig}") unless ($TESTING);
|
|
||||||
chdir "../.." or die "Error changing directories back to root";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub update_core_project_xml {
|
|
||||||
|
|
||||||
my $orig = "project.xml";
|
|
||||||
my $temp = "${orig}-bak";
|
|
||||||
|
|
||||||
print "Updating the version in ${orig}\n";
|
|
||||||
|
|
||||||
chdir "Core/nbproject" or die "cannot change into Core/nbproject directory";
|
|
||||||
|
|
||||||
open (CONF_IN, "<${orig}") or die "Cannot open ${orig}";
|
|
||||||
open (CONF_OUT, ">${temp}") or die "Cannot open ${temp}";
|
|
||||||
|
|
||||||
my $found = 0;
|
|
||||||
while (<CONF_IN>) {
|
|
||||||
if (/<runtime-relative-path>ext\/sleuthkit-postgresql/) {
|
|
||||||
print CONF_OUT " <runtime-relative-path>ext/sleuthkit-postgresql-${VER}.jar</runtime-relative-path>\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
elsif (/<binary-origin>release\/modules\/ext\/sleuthkit-postgresql/) {
|
|
||||||
print CONF_OUT " <binary-origin>release/modules/ext/sleuthkit-postgresql-${VER}.jar</binary-origin>\n";
|
|
||||||
$found++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
print CONF_OUT $_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close (CONF_IN);
|
|
||||||
close (CONF_OUT);
|
|
||||||
|
|
||||||
if ($found != 2) {
|
|
||||||
die "$found (instead of 2) occurrences of version found in ${orig}";
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink ($orig) or die "Error deleting ${orig}";
|
|
||||||
rename ($temp, $orig) or die "Error renaming tmp $orig file";
|
|
||||||
system("git add ${orig}") unless ($TESTING);
|
|
||||||
chdir "../.." or die "Error changing directories back to root";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
main();
|
|
Loading…
x
Reference in New Issue
Block a user